4

I'd like to implement something similar to what's asked in this question in Laravel 4, where a player/ resource can have more than one team/, and vice-versa.

In an ideal world I would be able to query

players/1/teams

and get back some JSON like this:

{ player: { 
    id: 1, name: 'Bob', sport: 'Curling', teams: [
        { id: 1, name: 'Northern Curling Soc.', age: 2}, 
        { id:2, name: 'Southern Curling Soc.', age: 4 }
    ] 
}

or

teams/{id}/players and get the correlative.

Obviously if I were using Laravel's views I could simply call $player->teams and all would be well, but this is for a JSON API so it all needs to be up front.

I also need to be able to paginate the related results, although this is probably a different question.

How can I do this with Laravel?

Thanks for any help!

Community
  • 1
  • 1
djb
  • 5,591
  • 5
  • 41
  • 47

2 Answers2

5

Laravel 4 added support for nested resources routes. They're pretty nice, and seem perfectly suited for this.

Basically, in addition to your "direct" resource controllers, you need to add routes for your nested resources. In this case, in addition to :

Route::resource('players', 'PlayersController');  // players/#
Route::resource('teams', 'TeamsController');      // teams/#

... you'd need:

Route::resource('players.teams', 'PlayerTeamsController');  // players/#/teams/#
Route::resource('teams.players', 'TeamPlayersController');  // teams/#/player/#

Then in your controllers, methods that usually receives a single ID as parameter will now receive two (the order is defined by your route):

class PlayerTeamsController extends Controller {

    public function show($player_id, $team_id) {

    }

}

You can then use inheritance to avoid code redundancy between your controllers.

idmadj
  • 2,565
  • 2
  • 19
  • 23
1

Via the API, just include the relationship and return the object (in laravel 4). L4 will automatically format the data for JSON output.

return Player::with( [ 'teams' ] )->get();

It will give you pretty much exactly the format you're after :)

Oddman
  • 3,715
  • 1
  • 16
  • 13
  • Thanks. I've been doing this elsewhere. The JSON is great! The question is, how do I route to this in a generalised way (I don't want to have to set up and maintain separate routes for all my resources)? – djb Aug 07 '13 at 14:08
  • As in, have the player controller respond to resources for the player itself? Aka, player/1/teams player/1/clubs .etc? – Oddman Aug 08 '13 at 15:27
  • 1
    this is a separate question, really - but I would advise against it. A better approach is to query for specific teams, aka: GET /teams?player_id=5 instead of GET /player/5/teams/ It keeps your API simpler, your routes/controllers.etc. easier to maintain, and is a recommended approach in various articles. I'd recommend reading Teach a dog to rest (google it). – Oddman Aug 13 '13 at 05:53
  • @Oddman The players/5/teams approach to represent relationships is actually recommended in Teach a dog to REST. Query parameters are a better fit for filters (get all players over 25 y.o. = /players?min_age=25). I'm looking for a way to do this with Laravel myself. – idmadj Mar 28 '14 at 22:10
  • @idmadj wow I must have missed that! If you get a good solution in Laravel lemme know, would be keen to see it :) – Oddman Mar 30 '14 at 20:04
  • Ah nice, yeah I see it. I can see some problems with it though, notably duplicate code/routes. I wonder if it's possible to have the teams controller represent both resources and just alter functionality slightly when there's a player_id present? – Oddman Mar 31 '14 at 18:33