Intereting Posts
как восстановить резервную копию файла mysql в php Создание функций без круглых скобок в PHP, таких как «эхо», В случае необходимости для сайта, который объясняет, как использовать PHPUnit Лучшие инструменты QA PHP Функция php для проверки переменной существует или не находится вне функции Вставить переменную NULL в базу данных Может ли вредоносный пользователь в веб-приложении манипулировать входами (помимо данных формы), которые отправляются передним интерфейсом веб-приложения? Удалить index.php в codeigniter 2.1.0 Как изолировать нежелательные сообщения об ошибках PHP? Как я могу скомпилировать linux для совместного использования со всеми дистрибутивами? Как использовать один и тот же пароль для java и php? Как исправить ошибки максимального времени выполнения в PHP? MongoDB обновляет вложенный массив Есть ли в Microsoft SQL Server драйвер для PHP имеет ограничение на длину строки запроса? CodeIgniter – Лучшая реализация для ACL

«Три способа» отношения «многие-ко-многим» с использованием Eloquent

У меня простая настройка базы данных: пользователи, группы, страницы – для многих их много. См. Диаграмму: 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(); 

Желательная загрузка может быть решением вашей проблемы: высокая загрузка