Laravel Eloquent-嵌套关系具有两个层次以上的约束

Ada*_*ann 3 php laravel eloquent

** 更新帖子:我认为使用Eloquent实际上是不可能的,所以我采取了另一种方法,谢谢!**

考虑以下简化表:

content
---------------
| id | name   |
---------------
| 1  | news   |
| 2  | review |
---------------

games
-------------
| id | name |
-------------
| 8  | halo |
| 9  | gta  |
-------------

releases
-------------------------------
| id | name         | game_id |
-------------------------------
| 14 | halo for ps3 | 8       |
| 15 | halo for wii | 8       |
| 16 | gta for ps4  | 9       |
-------------------------------

content_releases
-------------------------------------
| content_id | release_id | game_id |
-------------------------------------
| 1          | 14         | 8       |
| 1          | 15         | 8       |
| 2          | 15         | 8       |
| 2          | 16         | 9       |
-------------------------------------
Run Code Online (Sandbox Code Playgroud)
  • content可以releases通过content_games表格将许多项目链接到许多项目。
  • 许多releases属于一个game
  • 这样,通过将content项目链接到releases它们,它们也固有地链接到games

我的模型如下所示:

class Content extends \Eloquent
{
    public function games()
    {
        return $this->belongsToMany('Models\Game', 'content_game');
    }
}

class Game extends \Eloquent
{
    public function releases()
    {
        return $this->belongsToMany('Models\Release', 'content_game');
    }
}

class Release extends \Eloquent 
{
    public function content()
    {
        return $this->belongsToMany('Models\Content', 'content_game');
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试编写一个相对较快的延迟加载的口才查询,该查询可以使我满意,并在其下嵌套相关游戏,然后在其下嵌套相关发行版。所以我希望输出数组看起来像这样:

Array
(
    [0] => Array
    (
        [id] => 1
        [name] => News
        [games] => Array
        (
            [0] => Array
            (
                [id] => 8
                [name] => Halo
                [releases] => Array
                (
                    [0] => Array
                    (
                        [id] => 14
                        [name] => Halo for PS3
                    )
                    [1] => Array
                    (
                        [id] => 15
                        [name] => Halo for Wii
                    )
                )
            )
        )
    )
    [1] => Array
    (
        [id] => 2
        [name] => Review
        [games] => Array
        (
            [0] => Array
            (
                [id] => 8
                [name] => Halo
                [releases] => Array
                (
                    [0] => Array
                    (
                        [id] => 15
                        [name] => Halo for Wii
                    )
                )
            )
            [1] => Array
            (
                [id] => 9
                [name] => GTA
                [releases] => Array
                (
                    [0] => Array
                    (
                        [id] => 16
                        [name] => GTA for PS4
                    )
                )
            )
        )
    )

)
Run Code Online (Sandbox Code Playgroud)

Content::with('games', 'games.releases')->toArray();用3列表将content_releases它们全部连接在一起不能充分发挥作用,因为Eloquent仅基于两个列进行查询。因此,我需要添加一个约束games.releases。

它可以工作(下面的代码),但是效率不高:

Content::with(['games' => function ($query) {
                        $query->groupBy(['game_id','game.id','pivot_content_id']);
                     },
                    'games.releases' => function ($query) {
                        $query->has('content');
                    }]);
Run Code Online (Sandbox Code Playgroud)

它产生以下查询:

select * from "content" limit 10 offset 0

select "game".*, "content_game"."content_id" as "pivot_content_id", "content_game"."game_id" as "pivot_game_id" 
from "game" 
inner join "content_game" on "game"."id" = "content_game"."game_id"
where "content_game"."content_id" in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)           
group by "game_id", "game"."id", "pivot_content_id"

select "releases".*, "content_game"."game_id" as "pivot_game_id", "content_game"."release_id" as "pivot_release_id"
from "releases" 
inner join "content_game" on "releases"."id" = "content_game"."release_id" 
where "content_game"."game_id" in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
and (
    select count(*)
    from "content"
    inner join "content_game" on "content"."id" = "content_game"."content_id" 
    where "content_game"."release_id" = "releases"."id"
) >= 1
Run Code Online (Sandbox Code Playgroud)

谁能建议一种更有效的方法来实现相同的输出?

谢谢。

99l*_*ode 6

是的,这个问题有点过时了,但我前一段时间对此感到困惑,正确的答案可能对其他人有用:)

设置数据库表和关系的方式存在一些问题,因此让我们先避免它们:

如果我理解正确,内容与游戏之间存在多对多关系,游戏与发行之间存在多对多关系。因此,您将为内容和游戏之间的关系创建数据透视表,并在发布表上使用外键。这意味着重命名枢轴(为清楚起见)并删除release_id列。

完成后,我们必须更新模型关系。“内容属于ToMany游戏”,“游戏属于ToMany内容”和“游戏hasMany发布”。

现在只需要使用嵌套的雄辩关系,此后可能已经在文档中添加了一些内容。

Content::with(['games', 'games.releases'])->get()->toArray();
Run Code Online (Sandbox Code Playgroud)