Я создаю приложение, использующее Laravel 5.1 с пользователями , ролями и действиями .
Настройка таблицы выглядит так:
пользователь
id name 1 John Smith 2 Fred Smith
роль
id name 1 Administrator 2 Customer
role_user
user_id role_id 1 1 2 1
действие
id name description path 1 dashboard ability to access dashboard /admin 2 editAdmin ability to edit admins /admin/users/administrators/{id}/edit
action_role
action_id role_id 1 1 2 1
В таблице user
содержатся ВСЕ пользователи на сайте, включая администраторов и клиентов.
Таблица role
содержит все возможные роли, которые может иметь пользователь. Например, администратор или клиент .
Таблица role_user
представляет собой role_user
таблицу, которая связывает role
с user
.
В таблице action
перечислены все возможные действия (например, URL-адреса или маршруты) в приложении.
action_role
– сводная таблица, которая связывает action
с role
.
Итак, подведем итог:
Я хочу иметь промежуточную установку, которая проверяет загрузку страницы, если у пользователя есть разрешения на просмотр текущей страницы. Чтобы сделать это, мне нужно иметь доступ к действиям пользователей, используя такой вызов:
$user->roles()->actions();
Как настроить мои красноречивые отношения для поддержки такого вызова?
ОБНОВИТЬ
Мои отношения настроены так в моих моделях:
пользователь
/** * The roles that belong to the user. * * @return Object */ public function roles() { return $this->belongsToMany('App\Models\User\Role')->withTimestamps(); }
Роль
/** * The actions that belong to the role. * * @return Object */ public function actions() { return $this->belongsToMany('App\Models\User\Action'); } /** * The users that belong to the role. * * @return Object */ public function users() { return $this->belongsToMany('App\Models\User\User'); }
действие
/** * The roles that belong to the action. * * @return Object */ public function roles() { return $this->belongsToMany('App\Models\User\Role'); }
Eloquent не имеет отношения HasManyThrough
через две сводные таблицы.
1. Вы можете получить действия от ленивой нетерпеливой загрузки ролей и действий, а затем извлечь их:
$actions = $user->load('roles.actions')->roles->pluck('actions')->collapse()->unique();
2. Вы можете проверить действие непосредственно в базе данных, используя ограничение whereHas
:
$allowed = $user->roles()->whereHas('actions', function ($query) use ($action) { $query->where('name', $action); })->exists();
Для обработки пользовательских ролей и пользовательских разрешений вы можете просто использовать пакет Toddish .
Есть много вещей, которые этот пакет делает для вас. как:
$user->is('Your Defined Role'); $user->can('add_user'); $user->level(7);
Для установки просто прочитайте его документацию.
Хотя вы уже упоминали, что ваши модели Eloquent (и их отношения) настроены, я предполагаю, что в вашем приложении уже есть следующее:
Модель пользователя
class User extends Eloquent { public function roles() { return $this->belongsToMany('App\Models\Role'); } }
Ролевая модель
class Role extends Eloquent { public function actions() { return $this->belongsToMany('App\Models\Action'); } public function users() { return $this->belongsToMany('App\Models\User'); } }
Модель действия
class Action extends Eloquent{ public function roles(){ return $this->belongsToMany('App\Models\Role'); } }
Учитывая, что это правильно установлено, вы не можете сделать такой вызов, как следующее: Laravel предположит, что вы делаете вызов метода Query Builder или чего-то еще [этого на самом деле не существует]:
$userActions = App\Models\User::find(1)->roles()->actions();
Вместо этого вы должны использовать магический метод Laravel whereHas
для запроса отношений, в которых задействованы несколько вложенных отношений.
Теперь, имея id
пользователя и текущее допустимое action
[ которое действительно может быть использовано в вашем промежуточном программном обеспечении ], можно определить, разрешено ли пользователю видеть страницу:
$hasAccess = App\Models\User::whereHas('roles.actions', function($q) use ($id, $action){ $q->where('users.id', $id); $q->where('actions.name', $action); })->get()->toArray(); if($hasAccess){ // or `count($hasAccess) > 0`. The former will work since any number > 0 evaluates to true in PHP //user has access }
Обратите внимание на вложение отношений .
,
В Laravel существование взаимосвязи между моделями определяется с whereHas
методов has
и whereHas
. Метод has
используется для определения того, существует ли связь , например, при выполнении App\User::has('roles')->get()
вы всегда получите список / коллекцию пользователей, которые, по крайней мере, имеют какие-либо роли . Больше энергии для этого можно добавить с помощью whereHas
с помощью которого вы можете добавить where
предложения к фактическому запросу.
Привет, вот как я решил это.
Я не использовал таблицу действий. Просто пользователи , роли и таблица user_role . После решения я передаю свое собственное промежуточное программное обеспечение для массива ролей для каждого создаваемого мной маршрута:
Route::get('insights',[ 'as'=>'insights', **'middleware'=>['access.level'],** **'roles'=>['admin','customer'],** 'uses'=>'CustomersController@index' ]);
Измененные файлы: приложение \ Http \ Controllers \ Controller.php Пользовательское промежуточное ПО: приложение CheckAccessLevel \ Http \ Kernel.php app \ Http \ routes.php
Controller.php В этом файле я хотел бы загрузить загружаемого текущего пользователя с его ролями и сделать его глобальной переменной во всех представлениях как {{currentUser}} и во всех моих контроллерах как «$ this-> currentUser» . это код:
protected $currentUser; public function __construct() { if(isset(Auth::user()->username)){ $this->currentUser = User::with('roles')->where(['username' => Auth::user()->username])->first(); // Share this property with all the views and controllers in your application. view()->share('currentUser', $this->currentUser); } }
Пользовательское промежуточное ПО: CheckAccessLevel.php
Здесь, в промежуточном программном обеспечении, я извлекаю массив ролей, переданный на маршрут, а также роли, назначенные текущему пользователю. После того, как я получу эти переменные, я пересекаю их, чтобы увидеть, есть ли совпадение, прежде чем я включу пользователя. проверьте код ниже:
//if user is not logged in, show them where to login :) if (!Auth::check()) { return redirect()->route('user::login'); } //Otherwise get the roles for that route $get_route_action = $request->route()->getAction(); $get_route_roles = $get_route_action['roles']; //Eager load the user with their list of roles $eager_user = User::with('roles')->where(['id'=>$request->user()->id])->first(); $user_roles = $eager_user->roles->pluck('role_name')->toArray(); //intersect the users roles with the route roles to see if there is a match foreach ($user_roles as $user_role){ if(in_array($user_role, $get_route_roles)){ return $next($request); } }
Kernel.php здесь, я регистрирую свой маршрут как «access.level» внутри группы промежуточного программного обеспечения маршрута
Route.php, тогда всякий раз, когда я создаю маршрут, я просто передаю ему разрешенные имена и voala! Меня устраивает..
Надеюсь, это поможет.
Здесь вам нужны отношения HasManyThrough. Вот вам кое-что, чтобы вы начали.
Судя по вашим данным таблицам, я вижу, что у него есть отношения «один ко многим» с пользователем и ролями. Хотя действие и роли также имеют отношения «многие ко многим».
Но сначала вам нужно создать модели для каждого объекта (пользователя, роли, действия), чтобы следовать структуре MVC. Вы можете легко сделать эти модели из командной строки с помощью мастера Laravel с помощью этой команды.
php artisan make:model User
Обязательно добавьте или измените столбцы во вновь созданных миграциях. Предполагая, что у вас также установлены сводные таблицы для трех таблиц, теперь вы можете добавить отношения.
class User extends Model { // protected $table = 'users'; /* * @var table * */ public function action() { return $this->hasManyThrough('App\Action', 'App\Role'); } }
Теперь у вас есть отношения HasManyThrough . вы можете запросить это прямо, не нужно включать роль.
//this $actions = User::find(1)->action(); //instead of $actions = User::find(1)->role()->action(); //this will return all actions available to a user with id of 1
ПРИМЕЧАНИЕ. Я также предлагаю вам настроить свою роль и пользовательские модели на отношения один к одному.