Прошу прощения за задержку продолжения. Навалилось много дел… Но сейчас не о них. Продолжим!
Собственно пакеты мы создавать научились, давайте теперь приступим к разработке именно ACL. В первую очередь создадим две миграции.
php artisan make:migration create_roles_table --path=packages/Bitw/Acl/database/migrations и php artisan make:migration create_users_roles_table --path=packages/Bitw/Acl/database/migrations
Напомню, что Bitw/Acl это мое название «поставщика» и название пакета. У себя вы можете использовать свое.
содержание миграций я сделал такое
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?php // /packages/Bitw/Acl/database/migrations/2015_09_15_175235_create_roles_table.php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; use Illuminate\Support\Facades\Schema; class CreateRolesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('roles', function(Blueprint $table){ $table->increments('id'); $table->string('name'); $table->text('description'); $table->text('rules'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('roles'); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<?php // packages/Bitw/Acl/database/migrations/2015_09_15_175337_create_users_roles_table.php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; use Illuminate\Support\Facades\Schema; class CreateUsersRolesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users_roles', function (Blueprint $table) { $table->integer('user_id')->unsigned(); $table->integer('role_id')->unsigned(); $table->foreign('user_id') ->references('id')->on('users') ->onDelete('cascade'); $table->foreign('role_id') ->references('id')->on('roles') ->onDelete('cascade'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('users_roles'); } } |
Что бы в дальнейшем было удобнее публиковать и настраивать пакет давайте добавим в загрузку провайдера информацию для публикации миграций нашего пакет. Для этого необходимо в сервис-провайдере AclServiceProvider в метод boot добавить
1 2 3 |
$this->publishes([ __DIR__ . '/../database/migrations' => $this->app->databasePath() . '/migrations' ], 'migrations'); |
ну и давайте сразу добавим в загрузчик сервис-провайдера конфигуратор пакета и пути где искать представления для нашего пакета. Собственно на текущий момент у нас получается вот такой метод boot в AclServiceProvider
1 2 3 4 5 6 7 8 9 10 11 12 |
public function boot() { $this->publishes([__DIR__ . '/../config/acl.php' => config_path('acl.php')], 'config'); $this->publishes([ __DIR__ . '/../database/migrations' => $this->app->databasePath() . '/migrations' ], 'migrations'); $this->loadViewsFrom(__DIR__ . '/../resources/views/', 'acl'); require __DIR__ . '/Http/routes.php'; } |
И для полного счастья давайте добавим в метод register в сервис-провайдере подключение загрузки кунфигурации пакета. В результате у нас будет такой метод register в AclServiceProvider
1 2 3 4 5 6 7 8 |
public function register() { $this->mergeConfigFrom(__DIR__ . '/../config/acl.php', 'acl'); $this->app->bind('acl', function () { return new Acl; }); } |
Т.к. мы сразу заложили конфигуратор для нашего пакета то необходимо создать файл конфигурации.
1 |
touch packages/Bitw/Acl/config/acl.php |
с содержимым
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php return [ 'views' => [ 'layout' => 'acl::layout.default', 'manage' => 'acl::manage', 'edit' => 'acl::edit', ], 'sections' => [ 'content' => 'content', ] ]; |
По поводу содержимого конфигурации мы вернемся чуточку позже. А пока мы опубликуем и выполним миграции для нашего пакета. Для этого выполним в консоли
1 |
$ php artisan vendor:publish && php artisan migrate |
Превосходно! Конфигурации опубликованы, таблицы созданы! Настало время создать представления для управления ролями.
При разработке данного пакета я буду использовать принцип «Все что не разрешено — запрещено»
Как вы наверно помните в конфигурации мы создали набор параметров и некоторым, наверно очень интересно для чего это нужно? А сделано это для такого что бы в дальнейшем при работе с пакетом мы могли одной поправкой параметра конфигурации поменять основной макет куда будет вставляться наше представление, а также представления со списком ролей и формой редактирования.
Если кому не понятен данный подход, то пишите в комментариях и если наберется достаточно «интересующихся», то я более детально опишу этот подход
А теперь давайте создадим макет. Внимательный читатель должен был заметить в сервис-провайдере строку $this->loadViewsFrom(__DIR__ . '/../resources/views/', 'acl');
Вот эта инструкция и указывает Laravel путь где надо искать представления для данного пакета. Создадим основной макет для представлений $ touch packages/Bitw/Acl/resources/views/layout/default.blade.php с содержимым
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>ACL</title> <link rel="stylesheet" href="/vendor/bootstrap/dist/css/bootstrap.min.css"> </head> <body> <div class="container"> @yield('content') </div> {{urvanov-syntax-highlighter-internal:0}} {{urvanov-syntax-highlighter-internal:1}} @yield('scripts') </body> </html> |
Думаю, что мне не надо вам объяснять как поставить, настроить и использовать bower для того чтоб легко и быстро поставить jquery и bootstrap . Это я тут описывать не буду, но опять же если кому интересно то я могу написать по этой теме отдельную статью.
Так как в представлениях мы должны отображать данные из таблиц то настало время создать для работы с ролями.
$ touch packages/Bitw/Acl/src/Models/Role.php
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php namespace Bitw\Acl\Models; // packages/Bitw/Acl/src/Models/Role.php use Illuminate\Database\Eloquent\Model; class Role extends Model { protected $table = 'roles'; public $timestamps = false; protected $fillable = ['name', 'description', 'rules']; } |
Собираем представление для списка ролей
1 |
$ touch packages/Bitw/Acl/resources/views/manage.blade.php |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
@extends(config('acl.views.layout')) @section(config('acl.sections.content')) <h1>Access Control List</h1> @if(count($roles)) <table class="table table-hover"> <thead> <tr> <td>Название роли</td> <td colspan="2">Маршруты (имена)</td> </tr> </thead> <tbody id="js-roles"> @foreach($roles as $role) <tr data-id="{!! $role->id !!}"> <td> <a href="{!! route('acl.edit', $role->id) !!}">{!! $role->name !!}</a><br> <small>{!! $role->description !!}</small> </td> <td>{!! $role->rules !!}</td> <td><button type="button" class="btn btn-xs btn-danger js-role-delete">X</button></td> </tr> @endforeach </tbody> <tfoot> <tr> <td colspan="3"><a class="btn btn-primary" href="{!! route('acl.create') !!}">Создать новую роль</a></td> </tr> </tfoot> </table> @else <div class="alert alert-warning" role="alert"> <strong>Роли отсутствуют.</strong> <a href="{!! route('acl.create') !!}" class="alert-link">Создать новую роль</a>? </div> @endif @stop @section('scripts') {{urvanov-syntax-highlighter-internal:0}} @stop |
Представление для редактирование роли
1 |
$ touch packages/Bitw/Acl/resources/views/edit.blade.php |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
@extends(config('acl.views.layout')) @section(config('acl.sections.content')) <h1>Access Control List</h1> <form action="{!! $_action !!}" method="POST" role="form">{!! csrf_field() !!}{!! method_field($_method) !!} <div class="col-md-6 col-md-offset-3"> <legend>{!! $_title !!}</legend> <div class="form-group"> <label for="name">Имя</label> <input type="text" class="form-control" name="name" id="name" value="{!! Request::input('name', @$role->name) !!}" required> </div> <div class="form-group"> <label for="description" class="control-label">Описание (необязательно)</label> <textarea class="form-control" id="description" name="description">{!! Request::input('description', @$role->description) !!}</textarea> </div> <div class="form-group"> <label for="rules" class="control-label">Правила (разрешения)</label> <textarea class="form-control" id="rules" name="rules" required>{!! Request::input('rules', @$role->rules) !!}</textarea> </div> <button type="submit" class="btn btn-primary">Сохранить</button> <a class="btn btn-link" href="{!! route('acl.index') !!}">Отмена</a> </div> </form> @stop |
И все это завершим созданием контроллера $ touch packages/Bitw/Acl/src/Http/Controllers/AclController.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
<?php namespace Bitw\Acl\Http\Controllers; use App\Http\Controllers\Controller; use Bitw\Acl\Models\Role; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Http\Request; class AclController extends Controller { public function index() { return view(config('acl.views.manage'))->withRoles(Role::get()); } public function create() { return view(config('acl.views.edit'), [ '_action' => route('acl.store'), '_title' => 'Создание роли', '_method' => 'post' ]); } public function store(Request $request) { Role::create($request->all()); return redirect()->route('acl.index'); } public function edit($role) { try{ return view(config('acl.views.edit'))->with([ 'role' => Role::findOrFail($role), '_action' => route('acl.update', $role), '_title' => 'Редактирование роли', '_method' => 'put' ]); } catch(ModelNotFoundException $e) { return abort(404); } } public function update(Request $request, $role) { try{ $role = Role::findOrFail($role); } catch(ModelNotFoundException $e) { return abort(404); } $role->fill($request->all())->save(); return redirect()->route('acl.index'); } public function destroy(Request $request, $role) { try{ Role::findOrFail($role)->delete(); } catch(ModelNotFoundException $e) { return abort(404); } if(!$request->ajax()) return redirect()->route('acl.index'); } } |
Последним штрихом данной части будет изменение маршрутов (routes) данного пакета. В прошлой части мы сделали простеньикий маркрут искрючительно для проверки работоспособности пакета. Теперь же нам необходимо реализовать более полноценные маршруты. Необходимо открыть packages/Bitw/Acl/src/Http/routes.php и заменить все содержимое на
1 2 3 4 5 6 7 |
<?php Route::group(['namespace' => 'Bitw\Acl\Http\Controllers'], function () { Route::resource('acl', 'AclController', array( 'except' => array('show')) ); }); |
и если вы все сделали правильно то в браузере вы увидите
На этом я закончу эту часть. В следующей части мы реализуем регистрацию и авторизацию, а так же присвоение роли или набора ролей пользователям.