如何渴望加载多个关系并按嵌套关系分组

时间:2019-04-01 13:41:54

标签: php laravel

在体育应用中,我想显示球队列表以及每个球队的球员,并根据球员的位置对他们进行分组。

这里是定义模型关系的方式。

每个位置均与运动相关。在足球中,您将拥有CF,ST,GK等。在篮球中,您将拥有PG,PF,C等。

class Sport {

  public function positions()
  {
    return $this->hasMany(\App\Position::class);
  }

}

Position类知道每个扮演Position的玩家。

class Position {

  public function sport()
  {
    return $this->belongsTo(\App\Sport::class);
  }

  public function players()
  {
    return $this->hasMany(\App\Player::class);
  }

}

每个玩家都可以在一个团队中扮演特定职位。

class Player {

  public function position()
  {
    return $this->belongsTo(\App\Position::class);
  }

  public function team()
  {
    return $this->belongsTo(\App\Team::class);
  }

}

每个团队都与一项运动直接相关,每个玩家都可以在该团队中扮演一个职位。

class Team {

  public function sport()
  {
    return $this->belongsTo(\App\Sport::class);
  }

  public function players()
  {
    return $this->hasMany(\App\Player::class);
  }

}

现在,这是我的问题。我想返回一个球队列表,列出每个球队的位置,以及每个球员在该球队的位置。我想要的响应看起来像这样。

{
  "teams": [
    {
      "id": 1,
      "name": "Barcelona",
      "positions": [
        {
          "id": 1,
          "name": "Center Forward",
          "players": [
            {
              "id": 1,
              "name": "Lionel Messi"
            }
          ]
        }
      ]
    }
  ]
}

我尝试了多种方法,但似乎无法正确解决。下面的代码最终为我提供了一个可以接受的结构,但是球员并没有按团队过滤,因此无论团队是什么,我都会获得所有担任该职位的球员。例如,守门员位置将包含所有团队的守门员,这肯定是错误的。

Team::with(['sport.positions.players'])->paginate();

我觉得可能是这样的。

Team::with(['players.position' => function ($query) { /* insert groupBy magic */ }])->paginate();

有什么想法吗?

3 个答案:

答案 0 :(得分:0)

您应该让您的团队然后将其他数据加载到其中:

$teams->load('sport.positions.players');

注意:在分页功能中使用分页计数作为参数,如下所示:

$teams->load('sport.positions.players')->paginate(5);

答案 1 :(得分:0)

您可以尝试以下查询:

$team = Team::with(['players','position'=>function($q){
   $q->groupBy('positio_name') ;
})->get();

答案 2 :(得分:0)

不是您想要的东西, 完全 ,但这应该可以给您足够的帮助。

首先在teams上定义App\Sport关系

public function teams()
{
    return $this->hasMany(Team::class);
}

然后不去 Sport-> Position-> Players ,而是去 Sport-> Teams-> Players ,这样您就可以确定每个团队的球员范围免费,然后您可以像这样按position对每个团队成员进行分组

Sport::with(['teams.players.position'])->find($sport_id)
    ->setRelation('teams',  $sport->teams->map(function($team){
        return $team->setRelation('players', $team->players->groupBy(function($player){
            return $player->position->name;
        }));
    }));

setRelation()将覆盖关系,而不是在模型实例中添加具有关系名称的属性

希望有帮助。