Yii2 Bridge
naffiq
Bridge — это модуль админки, содержащий в себе генераторы кода для CRUD операций (CRUD — это Create, Read, Update, Delete; то есть все, что делает админ с контентом).

Интерфейс написан с помощью 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 теперь должна красоваться такая страница входа:

Однако пользователей в системе еще нет (чтобы не создавать админов с паролями 123456 по умолчанию). Сгенерировать его можно командой:
php yii user/create admin@email.com admin PASSWORD admin
Эта команда кочует в bridge из ususario и имеет довольно простой синтаксис:
- Первый аргумент — почтовый ящик
- Второй — логин
- Ваш пароль
- И роль пользователя.
Нам нужен админ, поэтому создаем первого пользователя с ролью admin. Остальные параметры необязательно называть так, поэтому здесь все ок.
После авторизации нам представляется панель администратора с базовым функционалом:

На первой странице пользователь видит состояние админки, ее последнюю версию и краткий список обновлений, который берется напрямую из GitHub API.
Эту страницу можно изменить — достаточно переназначить dashboardAction в модуле админки.
Настройки
Bridge предоставляет систему настроек, которую можно использовать для обертки статичных текстов, номеров и email для обратной связи, изображений и чекбоксов.

Саму настройку можно создать и использовать из любого места в вашем коде. Например, добавим на домашнюю страничку проекта картинки и кастомный текст:
<?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.
Теперь наша главная страница сайта (на фронте) будет выглядеть так:

Путь до картинки с котиком подставляется по умолчанию, если вы еще не успели загрузить свою картинку. К сожалению, пока не получается настроить изображение по умолчанию, однако вы всегда можете подключиться к разработке модуля, или хотя бы создать issue в гитхаб, если вам понадобится эта фича.
Теперь на странице модуля настроек появятся новые данные, которые мы вывели выше:

Если попытаться отредактировать настройку, то вам выйдет необходимое поле, под ваш тип данных.

Таким образом можно быстро создавать и редактировать данные без особых усилий. В планах добавить красивый интерфейс на страницу со всеми настройками и разделение их по группам (Контакты, Главная и т.д.).
Пользователи
Система предлагает разработчикам готовый модуль от 2amigos — usuario. Документацию о модуле можно прочитать тут.

Если вкратце, то функциональность пакета выходит за рамки стандартного CRUD пользователей:
- RBAC из под коробки
- Авторизация/Регистрация
- Отправка подтверждения и прочих уведомлений по почте
- Блокировка
Ожидается добавление загрузки аватарки из под коробки и еще плюхи (это можно посмотреть в гитхабе проекта).
Файловый менеджер

Тут в принципе нечего сказать — это обычный файл менеджер (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:

Помимо стандартного кода модели, генератор моделей от 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.

Когда вы нажмете на кнопку 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:

Не забудьте отметить чекбоксы, если у вас они по какой-то причине не активны. После генерации, вам станет доступна страница CRUD по URL https://localhost:8080/admin/cms/page/index

Однако в меню она еще появилась. Для того, чтобы добавить ее туда, нужно добавить в конфиг модуля следующее (над автоматическим либо более простым способом добавления в меню я уже работаю, но это сложно):
'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) и сам пункт меню:

Давайте попробуем создать страницу. В форме создания/редактирования автоматически генерируются нужные инпуты:

В планах добавить автоматическое распределение инпутов по колонкам внутри формы, но пока это не главный приоритет, вы можете сами отредактировать _form.php и расставить контент (сами колонки уже генерируются).
Как и в случае модели, инпуты генерируются по названию колонки, но так же важен тип колонки в БД:
- Если тип колонки — text, то генерируется CKEditor
- Если в конце названия image или _image — то файловый инпут с превью
- Для колонок, с is_ в начале — чекбоксы (точнее тоглы)
- Для колонок, с _at в конце — дэйтпикеры со временем
- Для колонок, с _date в конце — дейтпикеры, но уже без времени
Список виджетов для инпутов будет пополняться, идеи можете писать в issues. В ближайших планах — выбор локации на карте для колонки latlng.
Я создал 2 странички, и теперь на вкладке всех страниц можно увидеть различные колонки, которые сгенерировал нам Bridge.

Тут правила тоже простые:
- Если у таблицы есть title и image, то сгенерируется общая колонка с предпросмотром картинки (поиск идет по title)
- Все колонки типа text обрезаются до 100 символов (в планах просмотр полного текста)
- Если у таблицы есть поле position, то сгенерируется колонка с кнопками, для сортировки (и возможностью отправить элемент в самое начало)
- Если колонка начинается на is_, то генерируется ToggleColumn
Стоит еще отметить, что если в таблице есть поле is_deleted, то Bridge так же добавляет вкладку с корзиной на страницу. Удаление элементов будет отправлять контент на эту вкладку, откуда можно будет возвратить элемент.

Если у вас криво отображаются колонки, то теперь у вас есть возможность поменять ее ширину мышкой (не идеально, но работает):

Ширина колонок запоминается браузером.
Виджеты
Пока набор виджетов не богат, но я добавил самый основной (на мой взгляд) — отображение тостов:

Таким образом, любое действие с бекенда можно отобразить пользователю («Письмо отправлено!» и прочее). Вот пример вызова (класс naffiq\bridge\widgets\Toastr):
Toastr::error('Ошибка');
Toastr::warning('Предупреждение');
Toastr::success('Успех');
Toastr::info('Информация');