In a sports app, I want to display a list of teams and the players in each team, and have the players grouped by their position.
Here's how the model relationships are defined.
Each Position is linked to a Sport. In Football you'd have CF, ST, GK, etc. In Basketball you'd have PG, PF, C, etc.
class Sport {
public function positions()
{
return $this->hasMany(\App\Position::class);
}
}
The Position class knows about every Player that plays the Position.
class Position {
public function sport()
{
return $this->belongsTo(\App\Sport::class);
}
public function players()
{
return $this->hasMany(\App\Player::class);
}
}
Each Player can play a specific Position on a single Team.
class Player {
public function position()
{
return $this->belongsTo(\App\Position::class);
}
public function team()
{
return $this->belongsTo(\App\Team::class);
}
}
And each Team is directly related to a Sport and each Player can play a Position on that Team.
class Team {
public function sport()
{
return $this->belongsTo(\App\Sport::class);
}
public function players()
{
return $this->hasMany(\App\Player::class);
}
}
Now, here's my issue. I want to return a list of teams, with the positions being played on each team, and the players playing each position on that team. My desired response would look something like this.
{
"teams": [
{
"id": 1,
"name": "Barcelona",
"positions": [
{
"id": 1,
"name": "Center Forward",
"players": [
{
"id": 1,
"name": "Lionel Messi"
}
]
}
]
}
]
}
I've tried a variety of approaches but I can't seem to get it right. The code below ends up giving me an acceptable structure, but the players aren't filtered by team, so I get all the players that play the position, regardless of the team. By example, the Goalkeeper position would contain keepers from all teams which is definitely wrong.
Team::with(['sport.positions.players'])->paginate();
I feel like it might be something like this.
Team::with(['players.position' => function ($query) { /* insert groupBy magic */ }])->paginate();
Any ideas?