如何通过与Laravel 5 / Eloquent的多对多关系获得一个明确的类别列表?

时间:2015-05-20 20:16:04

标签: php mysql laravel eloquent laravel-5

我有一种复杂的数据模型,我试图用Laravel 5 / Eloquent编写我的查询,而不只是简单的ol' SQL。我的SQL下面有效,但是我喝了kool-aid,我想让它正常工作'正确'方式。

Actors和Poses之间有many to many relationship,Poses和Categories之间有many to many polymorphic relationship

我想做的是通过姿势获取与演员相关联的所有不同类别的列表。

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

categorizables         CATEGORY_ID         categorizable_id         categorizable_type

代码

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();
    }

2 个答案:

答案 0 :(得分: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();
}

您最终会得到一个数组,您可以将该数组传递给视图,其中键是actor的id,值是唯一类别的集合。例如,如果你想循环播放演员1的类别,你可以做类似......

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

答案 1 :(得分:1)

来自SoftOnSofaJarek Tkaczyk链接有一个我最终使用的干净解决方案。

我将此方法添加到我的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