【问题标题】:Laravel: chained relationships in a verbose wayLaravel:以冗长的方式链接关系
【发布时间】:2021-09-20 17:41:39
【问题描述】:

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

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

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

我尝试了“明显”

$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 应该有一种不那么冗长的方式来完成这项工作,但我找不到它。

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

非常感谢您并致以最诚挚的问候。

【问题讨论】:

    标签: laravel collections model relationship


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

      $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。它可以处理"infinite" 级别,而不仅仅是3。这是与之相关的SO question

      【讨论】:

      • 非常感谢你让我知道 Laravel 中没有 100% 开箱即用的解决方案(所以我可以停止搜索)。关于您的 first&iterate 解决方案,我更喜欢我的 pluck&whereIn 解决方案,因为它看起来更优雅且易于扩展(在级别上)。 hasManyThrough,遗憾的是级别限制,因为出于同样的原因,我也更喜欢 pluck&whereIn 解决方案。该软件包是一种有趣的可能性,但目前我正在尝试仅使用内置的 Laravel 解决方案。非常感谢@matiaslauriti!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-25
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多