0

我有一个简单的数据库设置:用户、组、页面——每一个都是多对多的。见图表: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

任何人都可以帮忙吗?

谢谢

4

2 回答 2

0

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

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

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

于 2013-06-25T16:12:36.190 回答
0

TL;DR:类中 的以下fetchAll方法MyCollection可以完成工作。只需调用fetchAll($user->groups, 'pages');


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

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

应用程序/库/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方法。

应用程序/模型/BaseModel.php

abstract class BaseModel extends Eloquent {

    public function newCollection(array $models = array()) {
        return new MyCollection($models);
    }

}

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

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

$pages = $user->groups->fetchAll('pages');
于 2013-06-25T16:40:15.787 回答