【问题标题】:How would I get a distinct list of Categories associated through two many to many relationships with Laravel 5/Eloquent?我如何获得通过与 Laravel 5/Eloquent 的两个多对多关系关联的不同类别列表?
【发布时间】:2015-08-02 06:48:58
【问题描述】:

我有一种复杂的数据模型,我正在尝试使用 Laravel 5/Eloquent 编写查询,而不仅仅是普通的 SQL。我下面的 SQL 可以工作,但我喝了 kool-aid,我想让它以“正确”的方式工作。

演员和姿势之间有一个many to many relationship,姿势和类别之间有一个many to many polymorphic relationship

我想要做的是通过它的姿势获取与一个 Actor 关联的所有不同类别的列表。

SQL

    SELECT DISTINCT 
        categories.name,
        categories.parent_id
    FROM 
        actor_pose 
    JOIN 
        poses ON poses.id = actor_pose.pose_id
    JOIN 
        categorizables ON categorizables.categorizable_id = poses.id  
    JOIN
        categories ON categories.id = categorizables.category_id
    WHERE 
        actor_pose.actor_id = 1 AND
        categorizables.categorizable_type = "App\\Pose"
    ORDER BY
        parent_id

数据库

演员 ID 名字

姿势 ID 名字

类别 ID 姓名 parent_id

可分类 类别ID 可分类的_id 可分类类型

代码

CategorizableTrait.php

<?php namespace App;
trait CategorizableTrait {
    public function categories()
    {
        return $this->morphToMany('App\Category', 'categorizable');
    }
}

Pose.php

<?php namespace App;
class Pose extends Model
{
    use CategorizableTrait;
    public function actors()
    {
        return $this->belongsToMany('App\Actor')->withTimestamps();
    }
}

Actor.php

<?php namespace App;    
class Actor extends Model
{
    public function poses()
    {
        return $this->belongsToMany('App\Pose')->withTimestamps();
    }

【问题讨论】:

  • 阅读 softonsofa.com/… 并且不要错过 Joseph Silber 的 cmets - 在 L5.1 中,只有收集方法才有可能。
  • 谢谢,我更新了我的答案,你的帖子效果很好!

标签: php mysql laravel eloquent laravel-5


【解决方案1】:

Collection 类有一些非常好的方法来处理这类事情。只需使用with() 建立您的关系并获得您想要的演员。循环遍历关系并添加到集合中。

$categories = new \Illuminate\Database\Eloquent\Collection();
$actor = App\Actor::with('poses.categories')->find($actor_id);

foreach($actor->poses as $pose) {
    foreach($pose->categories as $catgegory) {
        $categories->add($catgegory);
    }
}

$categories = $categories->unique();

如果您希望页面上的所有演员都有其独特的类别,那么这只是嵌套在另一个循环中的所有内容。

$actors = App\Actor::with('poses.categories')->get();
$actor_categories = [];

foreach($actors as $actor) {
    $actor_categories[$actor->id] = new \Illuminate\Database\Eloquent\Collection();
    foreach($actor->poses as $pose) {
        foreach($pose->categories as $category) {
            $actor_categories[$actor->id]->add($category);
        }
    }
    $actor_categories[$actor->id] = $actor_categories[$actor->id]->unique();
}

你最终会得到一个数组,你可以将它传递给视图,其中键是演员的 id,值是唯一类别的集合。例如,如果你想遍历演员 1 的类别,你可以这样做......

foreach($actor_categories[1] as $category) {
    echo $category->name;
}

【讨论】:

  • 感谢您的回复。理想情况下,我希望它与演员相关联,所以当我拉出演员列表时,我可以得到他们所属的类别。
  • 这只会给你与某个演员相关的类别。
  • 抱歉,我的评论不清楚。我想在一页上拉出许多演员。我仍然只想查看与一位演员相关的类别。
【解决方案2】:

Jarek TkaczykSoftOnSofa 的链接有一个我最终使用的干净解决方案。

我将此方法添加到我的 Actor.php 文件中。

Actor.php

public function getCategoriesAttribute()
{
    $categories = new Collection;
    $this->load(['poses.categories' => function ($q) use ( &$categories ) {
        $categories = $q->get()->unique();
    }]);
    return $categories->sortBy('order')->sortBy('parent_id');
}

控制器没有做任何特别的事情。在刀片中,您可以按如下方式访问它。

index.blade.php

@foreach($actor->categories as $key => $category)
    {{ $category->name }}
@endforeach

【讨论】:

  • 我想很多人会发现这非常有用。但是,请小心使用它。我刚刚在我自己的项目中实现了类似的东西来查找我必须通过角色表来查找用户的权限。对于 10 个用户,它运行了 28 个查询。
  • 谢谢。我做了一些测试,这种方式和你建议的方式都运行了两个查询。我最初运行了一个原始查询,但它没有返回 eloquent 集合。
猜你喜欢
  • 2020-12-16
  • 2013-05-15
  • 2014-09-27
  • 1970-01-01
  • 2018-10-05
  • 2019-07-08
  • 2021-01-14
  • 1970-01-01
  • 2016-11-19
相关资源
最近更新 更多