Yii2 Bridge
naffiq![](https://intra.rocketfirm.com/media/page_image/nl/1518766523h43n1.jpg)
Bridge — это модуль админки, содержащий в себе генераторы кода для CRUD операций (CRUD — это Create, Read, Update, Delete; то есть все, что делает админ с контентом).
![](https://intra.rocketfirm.com/media/page_image/tp/1518772059yf2ks.png)
Интерфейс написан с помощью Bootstrap 3, тема кастомная, дизайн и верстка — мои.
Вместо того, чтобы выпускать кучу неподдерживаемых модулей, я решил использовать зарекомендовавшие себя в боевых проектах готовые решения, в том числе:
- Janisto/Environments (GitHub)
- Yii2Tech/Admin (GitHub, обязателен к ознакомлению)
- Yii2Tech/Position (GitHub)
- Yii2Tech/Active Record Soft Delete (GitHub)
- 2amigos/Usuario (GitHub, обязателен к ознакомлению)
- 2amigos/GridView (GitHub)
- MongoSoft/UploadBehavior (GitHub)
На самом деле пакетов под коробкой больше, о них я потихоньку рассказываю на wiki странице проекта.
Начало работы
Чтобы создать новый проект с yii2-bridge, можно воспользоваться стандартной composer командой:
composer create-project naffiq/yii2-app-bridge PROJECT_NAME
И все, проект у вас завелся в своей папке со всеми последними зависимостями. После этого нужно настроить базу данных в папке конфигураций /config/local.php (можно скопировать /config/example.local.php для примера).
Bridge содержит в себе несколько миграций, которые можно запустить одной командой (из папки проекта):
./vendor/bin/bridge-install
После этого ваш проект готов к запуску на орбиту. По ссылке http://localhost:8080/admin теперь должна красоваться такая страница входа:
![](https://intra.rocketfirm.com/media/page_image/lh/15187742006dz3d.png)
Однако пользователей в системе еще нет (чтобы не создавать админов с паролями 123456 по умолчанию). Сгенерировать его можно командой:
php yii user/create admin@email.com admin PASSWORD admin
Эта команда кочует в bridge из ususario и имеет довольно простой синтаксис:
- Первый аргумент — почтовый ящик
- Второй — логин
- Ваш пароль
- И роль пользователя.
Нам нужен админ, поэтому создаем первого пользователя с ролью admin. Остальные параметры необязательно называть так, поэтому здесь все ок.
После авторизации нам представляется панель администратора с базовым функционалом:
![](https://intra.rocketfirm.com/media/page_image/gh/1518774308yvdfx.png)
На первой странице пользователь видит состояние админки, ее последнюю версию и краткий список обновлений, который берется напрямую из GitHub API.
Эту страницу можно изменить — достаточно переназначить dashboardAction в модуле админки.
Настройки
Bridge предоставляет систему настроек, которую можно использовать для обертки статичных текстов, номеров и email для обратной связи, изображений и чекбоксов.
![](https://intra.rocketfirm.com/media/page_image/g3/1518774486tnecx.png)
Саму настройку можно создать и использовать из любого места в вашем коде. Например, добавим на домашнюю страничку проекта картинки и кастомный текст:
<?php // @app/views/site/index.php use naffiq\bridge\models\Settings; /* @var $this yii\web\View */ $this->title = 'Bridge Tutorial'; ?> <div class="site-index"> <div class="jumbotron"> <h1><?= Settings::getOrCreate('main_title', [ 'title' => 'Заголовок на главной', 'type' => Settings::TYPE_TEXT, 'value' => 'Привет!' ]) ?></h1> <?= Settings::getOrCreate('main_text', [ 'title' => 'Текст на главной', 'type' => Settings::TYPE_TEXT, 'value' => 'Этот текст выставлен по умолчанию, пожалуйста перебейте меня в админке!' ]) ?> </div> <div class="body-content"> <div class="row"> <div class="col-lg-4"> <h2>Картинка 1</h2> <img src="<?= Settings::getOrCreate("main_image_1", [ 'title' => 'Картинка на главной 1', 'type' => Settings::TYPE_IMAGE, ]); ?>" alt="" class="img-responsive"> </div> <div class="col-lg-4"> <h2>Картинка 2</h2> <img src="<?= Settings::getOrCreate("main_image_2", [ 'title' => 'Картинка на главной 2', 'type' => Settings::TYPE_IMAGE, ]); ?>" alt="" class="img-responsive"> </div> <div class="col-lg-4"> <h2>Картинка 3</h2> <img src="<?= Settings::getOrCreate("main_image_3", [ 'title' => 'Картинка на главной 3', 'type' => Settings::TYPE_IMAGE, ]); ?>" alt="" class="img-responsive"> </div> </div> </div> </div>
В коде выше мы заменили стандартную страницу yii2 на свои тексты, которые подгружаются с модуля настроек админки. Можно заметить, что используется функция Settings::getOrCreate, у которой первый аргумент — ключ для использования, а второй — массив со значениями по умолчанию. Сама модель Settings имеет несколько констант, с доступными типами данных настроек. Кол-во типов будет постоянно пополнятся, но они всегда будут вида Settings::TYPE_ANYTHING_HERE.
Теперь наша главная страница сайта (на фронте) будет выглядеть так:
![](https://intra.rocketfirm.com/media/page_image/pe/151877769788umn.png)
Путь до картинки с котиком подставляется по умолчанию, если вы еще не успели загрузить свою картинку. К сожалению, пока не получается настроить изображение по умолчанию, однако вы всегда можете подключиться к разработке модуля, или хотя бы создать issue в гитхаб, если вам понадобится эта фича.
Теперь на странице модуля настроек появятся новые данные, которые мы вывели выше:
![](https://intra.rocketfirm.com/media/page_image/z7/15187780782k6we.png)
Если попытаться отредактировать настройку, то вам выйдет необходимое поле, под ваш тип данных.
![](https://intra.rocketfirm.com/media/page_image/cr/15187781614dpwm.png)
Таким образом можно быстро создавать и редактировать данные без особых усилий. В планах добавить красивый интерфейс на страницу со всеми настройками и разделение их по группам (Контакты, Главная и т.д.).
Пользователи
Система предлагает разработчикам готовый модуль от 2amigos — usuario. Документацию о модуле можно прочитать тут.
![](https://intra.rocketfirm.com/media/page_image/y0/1518779193be1w5.png)
Если вкратце, то функциональность пакета выходит за рамки стандартного CRUD пользователей:
- RBAC из под коробки
- Авторизация/Регистрация
- Отправка подтверждения и прочих уведомлений по почте
- Блокировка
Ожидается добавление загрузки аватарки из под коробки и еще плюхи (это можно посмотреть в гитхабе проекта).
Файловый менеджер
![](https://intra.rocketfirm.com/media/page_image/bg/1518779862717e3.png)
Тут в принципе нечего сказать — это обычный файл менеджер (ElFinder). Используется сторонний модуль для подключения его к yii2, который разрешает и запрещает разным ролям доступ к файловому хранилищу.
Генераторы
С встроенным функционалом разобрались. Что еще есть в админке? В админке есть генераторы кода, которые создают нужные behaviors и адаптируют CRUD.
Генерируем модель
Таблицу генерируем этой миграцией (чтобы сэкономить время на написание статьи, не приписал null'ы и комменты к колонкам, простите):
<?php // @app/migrations/m180216_112042_create_page_table.php use yii\db\Migration; /** * Handles the creation of table `page`. */ class m180216_112042_create_page_table extends Migration { /** * @inheritdoc */ public function up() { $this->createTable('page', [ 'id' => $this->primaryKey(), 'title' => $this->string(), 'text' => $this->text(), 'image' => $this->string(), 'position' => $this->integer(), 'is_deleted' => $this->boolean(), 'is_something' => $this->boolean(), ]); } /** * @inheritdoc */ public function down() { $this->dropTable('page'); } }
После этого заходим в интерфейс Gii и генерируем модель с помощью Bridge Model Generator:
![](https://intra.rocketfirm.com/media/page_image/wj/1518780203y9qq8.png)
Помимо стандартного кода модели, генератор моделей от Bridge, добавит рекомендованные behaviors, в зависимости от имени колонки (это можно отключить в самом генераторе, или используйте стандартный):
/** * @inheritdoc */ public function behaviors() { return [ 'imageUpload' => [ 'class' => 'mongosoft\file\UploadImageBehavior', 'attribute' => 'image', 'path' => '@webroot/media/page/{id}', 'url' => '@web/media/page/{id}', 'scenarios' => ['create', 'update'], 'thumbs' => ['thumb' => ['width' => 200, 'height' => 200, 'quality' => 90], 'preview' => ['width' => 50, 'height' => 50, 'quality' => 90]], ], 'positionSort' => [ 'class' => 'yii2tech\ar\position\PositionBehavior', 'positionAttribute' => 'position', ], 'softDeleteBehavior' => [ 'class' => 'yii2tech\ar\softdelete\SoftDeleteBehavior', 'softDeleteAttributeValues' => ['is_deleted' => 1], 'invokeDeleteEvents' => false, ], ]; }
Вот возможные поведения, которые Bridge может сгенерировать:
- Если колонка кончается на image или _image, то добавится поведение загрузки изображения, с кропом и ресайзом
- Если колонка кончается на file или _file, то добавится поведение загрузки файлов
- Если колонка называется postition, то генерируется поведение для сортировки (однако сортировать для вывода на фронте нужно будет самим)
- Если колонка называется is_deleted, то генерируется поведения для «мягкого удаления»
Поведения будут дополняться. Например сейчас я работаю над поведениям для колонок slug и created_at, updated_at.
Все эти поведения прекрасно отображаются с CRUD интерфейсом, сгенерированным Bridge Crud Generator
Генерируем CRUD
Перед генерацией CRUD, надо выбрать создать модуль, который будет содержать в себе контроллеры и вьюшки админки. Например, я назову модуль CMS (модуль adminуже занят 😀) и сгенерирую его стандартным Gii Module.
![](https://intra.rocketfirm.com/media/page_image/bp/1518781257yrknu.png)
Когда вы нажмете на кнопку Generate, вам выведется сообщение об успешном создании модуля и кусок кода, который надо вставить, чтобы он заработал. Однако, вам нужно будет вставить этот код в модуль admin. Ваши настройки модуля должны выглядеть так (/config/main.php):
'modules' => [ 'admin' => [ 'class' => \naffiq\bridge\BridgeModule::class, 'modules' => [ 'cms' => [ 'class' => 'app\modules\cms\Module', ], ], 'userClass' => \app\models\User::class, 'userSettings' => [ 'class' => \Da\User\Module::className(), 'administratorPermissionName' => 'admin' ] ], ],
После этого заходим в Bridge CRUD Generator и в namespace своего контроллера и путь до View не забываем указать модуль cms:
![](https://intra.rocketfirm.com/media/page_image/w7/1518781632drdnf.png)
Не забудьте отметить чекбоксы, если у вас они по какой-то причине не активны. После генерации, вам станет доступна страница CRUD по URL https://localhost:8080/admin/cms/page/index
![](https://intra.rocketfirm.com/media/page_image/ha/1518781788ug6h7.png)
Однако в меню она еще появилась. Для того, чтобы добавить ее туда, нужно добавить в конфиг модуля следующее (над автоматическим либо более простым способом добавления в меню я уже работаю, но это сложно):
'modules' => [ 'admin' => [ 'class' => \naffiq\bridge\BridgeModule::class, 'modules' => [ 'cms' => [ 'class' => 'app\modules\cms\Module', ], ], 'menu' => [ 'Content', [ 'title' => 'Pages', 'url' => ['/admin/cms/page/index'], 'active' => ['module' => 'cms', 'controller' => 'page'], 'icon' => 'font' ] ], 'userClass' => \app\models\User::class, 'userSettings' => [ 'class' => \Da\User\Module::className(), 'administratorPermissionName' => 'admin' ] ], ],
После этого, в нашем меню появится 2 вещи — разделитель (если указываем просто строку, например Content) и сам пункт меню:
![](https://intra.rocketfirm.com/media/page_image/qg/15187821187q7g3.gif)
Давайте попробуем создать страницу. В форме создания/редактирования автоматически генерируются нужные инпуты:
![](https://intra.rocketfirm.com/media/page_image/el/1518783439squq1.png)
В планах добавить автоматическое распределение инпутов по колонкам внутри формы, но пока это не главный приоритет, вы можете сами отредактировать _form.php и расставить контент (сами колонки уже генерируются).
Как и в случае модели, инпуты генерируются по названию колонки, но так же важен тип колонки в БД:
- Если тип колонки — text, то генерируется CKEditor
- Если в конце названия image или _image — то файловый инпут с превью
- Для колонок, с is_ в начале — чекбоксы (точнее тоглы)
- Для колонок, с _at в конце — дэйтпикеры со временем
- Для колонок, с _date в конце — дейтпикеры, но уже без времени
Список виджетов для инпутов будет пополняться, идеи можете писать в issues. В ближайших планах — выбор локации на карте для колонки latlng.
Я создал 2 странички, и теперь на вкладке всех страниц можно увидеть различные колонки, которые сгенерировал нам Bridge.
![](https://intra.rocketfirm.com/media/page_image/gh/1518783916snulp.png)
Тут правила тоже простые:
- Если у таблицы есть title и image, то сгенерируется общая колонка с предпросмотром картинки (поиск идет по title)
- Все колонки типа text обрезаются до 100 символов (в планах просмотр полного текста)
- Если у таблицы есть поле position, то сгенерируется колонка с кнопками, для сортировки (и возможностью отправить элемент в самое начало)
- Если колонка начинается на is_, то генерируется ToggleColumn
Стоит еще отметить, что если в таблице есть поле is_deleted, то Bridge так же добавляет вкладку с корзиной на страницу. Удаление элементов будет отправлять контент на эту вкладку, откуда можно будет возвратить элемент.
![](https://intra.rocketfirm.com/media/page_image/8w/1518784602tuo0t.gif)
Если у вас криво отображаются колонки, то теперь у вас есть возможность поменять ее ширину мышкой (не идеально, но работает):
![](https://intra.rocketfirm.com/media/page_image/o9/1518784422hnuoo.gif)
Ширина колонок запоминается браузером.
Виджеты
Пока набор виджетов не богат, но я добавил самый основной (на мой взгляд) — отображение тостов:
![](https://intra.rocketfirm.com/media/page_image/sk/1518785472shcha.png)
Таким образом, любое действие с бекенда можно отобразить пользователю («Письмо отправлено!» и прочее). Вот пример вызова (класс naffiq\bridge\widgets\Toastr):
Toastr::error('Ошибка'); Toastr::warning('Предупреждение'); Toastr::success('Успех'); Toastr::info('Информация');