【问题标题】:"Three way" many-to-many relationship using Eloquent使用 Eloquent 的“三向”多对多关系
【发布时间】:2013-06-22 09:54:06
【问题描述】:

我有一个简单的数据库设置:用户、组、页面——每一个都是多对多的。 见图:http://i.imgur.com/oFVsniH.png

现在我有一个可变的用户 ID ($id),我想用它来获取用户可以访问的页面列表,很明显,因为它在所有表上都是多对多的。

我已经像这样设置了我的主要模型:

class User extends Eloquent {
    protected $table = 'ssms_users';

    public function groups()
    {
        return $this->belongsToMany('Group', 'ssms_groups_users', 'user_id','group_id');
    }

}
class Group extends Eloquent {
    protected $table = 'ssms_groups';

    public function users()
    {
        return $this->belongsToMany('User', 'ssms_groups_users', 'user_id','group_id');
    }

    public function pages()
    {
        return $this->belongsToMany('Page', 'ssms_groups_pages', 'group_id','page_id');
    }

}
class Page extends Eloquent {
    protected $table = 'ssms_pages';

    public function groups()
    {
        return $this->belongsToMany('Group', 'ssms_groups_pages', 'group_id','page_id');
    }

}

我可以通过简单地获取用户所属的组:

User::with('groups')->first(); // just the first user for now

但是,我完全不知道如何通过一个查询获取用户可以(明显地)访问的页面?

我相信 SQL 会是这样的:

select DISTINCT GP.page_id
from GroupUser GU
join GroupPage GP on GU.group_id = GP.group_id 
where GU.user_id = $id

谁能帮忙?

谢谢

【问题讨论】:

    标签: php mysql sql laravel


    【解决方案1】:

    你以前尝试过这样的事情吗?

    $pages = User::with(array('groups', 'groups.pages'))->get();
    

    急切加载可能是您的问题的解决方案:eager loading

    【讨论】:

    • 返回:调用未定义的方法 Illuminate\Database\Query\Builder::pages() 虽然没有研究过急加载,需要弄清楚它是如何工作的!
    • 编辑了我的答案,您可能想再试一次。
    • 好的,谢谢,这行得通...我会研究一下 Eager 加载,看看有什么好处:)
    【解决方案2】:

    TL;DR: 下面的fetchAll 方法在MyCollection 类中完成了这项工作。只需拨打fetchAll($user->groups, 'pages');


    好的,假设您设法加载数据(这应该通过急切加载来完成,如另一个答案中所述),您应该循环通过 Groups 和 User ,然后循环通过它Pages 并将其添加到新集合中。由于我已经遇到过这个问题,我认为简单地扩展 Laravel 自己的 Collection 类并添加一个通用方法来做到这一点会更容易。

    为简单起见,只需创建一个app/libraries 文件夹并将其添加到您的composer.json,在autoload -> classmap 下,它将负责为我们加载类。然后将扩展的Collection 类放入文件夹中。

    app/libraries/MyCollection.php

    use Illuminate\Database\Eloquent\Collection as IlluminateCollection;
    
    class MyCollection extends IlluminateCollection {
    
        public function fetchAll($allProps, &$newCollection = null) {
            $allProps = explode('.', $allProps);
            $curProp = array_shift($allProps);
    
            // If this is the initial call, $newCollection should most likely be
            // null and we'll have to instantiate it here
            if ($newCollection === null) {
                $newCollection = new self();
            }
    
            if (count($allProps) === 0) {
    
                // If this is the last property we want, then do gather it, checking
                // for duplicates using the model's key
                foreach ($this as $item) {
                    foreach ($item->$curProp as $prop) {
                        if (! $newCollection->contains($prop->getKey())) {
                            $newCollection->push($prop);
                        }
                    }
                }
            } else {
    
                // If we do have nested properties to gather, then pass we do it
                // recursively, passing the $newCollection object by reference
                foreach ($this as $item) {
                    foreach ($item->$curProp as $prop) {
                        static::make($prop)->fetchAll(implode('.', $allProps), $newCollection);
                    }
                }
            }
    
            return $newCollection;
        }
    }
    

    但是,为了确保您的模型将使用这个类,而不是原来的 Illuminate\Database\Eloquent\Collection,您必须创建一个基础模型,您将从中扩展您的所有模型,并覆盖 newCollection方法。

    app/models/BaseModel.php

    abstract class BaseModel extends Eloquent {
    
        public function newCollection(array $models = array()) {
            return new MyCollection($models);
        }
    
    }
    

    别忘了你的模型现在应该是extend BaseModel,而不是Eloquent。完成所有这些后,要获取您所有的 UserPages,只有其 ID,请执行以下操作:

    $user = User::with(array('groups', 'groups.pages'))
                ->find($id);
    
    $pages = $user->groups->fetchAll('pages');
    

    【讨论】:

      猜你喜欢
      • 2013-05-27
      • 2020-03-27
      • 2015-08-19
      • 2019-06-13
      • 2015-11-10
      • 2017-11-03
      • 2018-03-28
      • 1970-01-01
      相关资源
      最近更新 更多