У меня простая настройка базы данных: пользователи, группы, страницы – для многих их много. См. Диаграмму: http://img.ruphp.com/php/oFVsniH.png
Теперь у меня есть переменный идентификатор пользователя ($ 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
Может ли кто-нибудь помочь?
благодаря
TL; DR: метод fetchAll
ниже, в классе MyCollection
, выполняет эту работу. Просто позвоните fetchAll($user->groups, 'pages');
Хорошо, если вам удастся загрузить данные (что должно быть сделано путем его загрузки, как указано в другом ответе), вы должны пройти через Group
« User
», затем прокрутить Page
и добавить ее в новая коллекция. Поскольку у меня уже была эта проблема, я подумал, что было бы проще просто расширить собственный класс Collection
Laravel и добавить общий метод для этого.
Чтобы это было просто, просто создайте папку app/libraries
и добавьте ее в свой composer.json
, в разделе 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
. После того, как все сделано, чтобы получить все Page
, имеющие только свой идентификатор, выполните:
$user = User::with(array('groups', 'groups.pages')) ->find($id); $pages = $user->groups->fetchAll('pages');
Вы что-то пробовали раньше?
$pages = User::with(array('groups', 'groups.pages'))->get();
Желательная загрузка может быть решением вашей проблемы: высокая загрузка