Laravel: 冗长的链式关系

Laravel: chained relationships in a verbose way

我有几个模型由 1:N 关系链接:

用户 (1 -> N) Asignatura (1 -> N) Clase (1 -> N) Asiento

我想获得一个 Asiento 模型集合,包含一个用户的所有 Asientos。

我尝试了“显而易见”

$user->asignaturas->clases->asientos;

但由于 $user->asignaturas 是一个集合,->clases 未被识别为有效方法(所有应有的关系,asignaturas()clases()asientos()已在各自的模型中创建)

所以我做了以下事情来解决问题:

$user = User::findorFail(Auth::user()->id);
$asignaturasArr = $user->asignaturas->pluck('id')->toArray();
$clases = Clase::whereIn('asignatura_id', $asignaturasArr)->get();
$clasesArr = $clases->pluck('id')->toArray();
$asientos = Asiento::whereIn('clase_id', $clasesArr)->get();

但我怀疑 Laravel 应该有一种不那么冗长的方法来完成这项工作,但我找不到它。

如果有任何专家的建议,我将不胜感激。

非常感谢您和最诚挚的问候。

$user->asignaturas->clases->asientos; 将不起作用,因为 asignaturascollection,因此您必须这样做才能工作:$user->asignaturas->first()->clases->first()->asientos; 但您必须遍历每个asignaturasclases 这肯定不理想。

所以,您可以尝试使用 hasManyThrough,但这也不会 100% 有效,因为它只允许 3 级别深度,它只适用于 User -> Asignaturas -> Clases(所以你获取所有用户的 Clases,但您仍然需要迭代每个 Clase 以获取每个 Asientos),否则它只适用于 Asignaturas -> Clases -> Asientos(但您必须编写此在 Asignatura 模型中,而不是在用户中,我仍然认为这对你有用。

所以,如果我们使用我提到的最后一个,你的 Asignatura 模型应该有这个:

class Asignatura extends Model
{
    public function asientos()
    {
        return $this->hasManyThrough(Asiento::class, Clase::class);
    }
}

请记住,这必须遵循标准约定,请阅读有关它的文档,如果它不起作用,请分享您的模型和表的名称,以便我们帮助您使其起作用。

然后,在您的 User 模型中:

class User extends Model
{
    public function asientos()
    {
        $asientos = collect();

        $this->asignaturas->each(function ($asignatura) use ($asientos) {
            $asignatura->asientos->each(function ($asiento) use ($asientos) {
                $asientos->push($asiento);
            });
        });

        return $asientos;
    }
}

但是,该代码不是 100% 好,因为你循环了很多,仍然可以工作。

其他解决方案是只做一个普通的查询(手动连接)并以这种方式获取数据,但我不会在这里这样做,因为我不知道你的表的名称是什么,你可以找到很好的教程关于这个,你将不得不加入表格,真的很简单。


您可以尝试使用但我从未使用过的其他可能的解决方案是使用某人由于这个确切问题而创建的包,它被称为 staudenmeir/eloquent-has-many-deep. It can handle "infinite" levels instead of just 3. This is the 与之相关。

最后,我认为我找到了问题的 Eloquent(优雅)解决方案。如下:

$asientos = $user->asignaturas->map->clases->unique()->flatten()->map->asientos->unique()->flatten();

使用 mapunique()->flatten()(当然还有模型中的必要关系),您可以链接任意多的关系级别。