Генератор админок «Битрикса»
Несколько лет назад я начал делать сайты на «Битриксе». У меня были проекты СМИ, которым требовались нестандартные интерфейсы, но не было инструментов для их разработки. Тут и там нужно было сделать страницу в админке: то для простого редактирования данных, то с навороченным интерфейсом и функционалом документооборота. Матёрый читатель наверняка уже досадно хмыкнул, читая эти строки, ведь в «Битриксе» это делается с помощью большой портянки в виде ПХП-скрипта, содержащего логику всех КРУД-операций страницы, вперемежку с ХТМЛ-кодом, ЦСС и ЯС. Пример — любая админская страница любого модуля «Битрикса».
ООП?
Генерация административного интерфейса — головная боль битриксоида. Кто-то мирится с этим досадным фактом и идёт по пути написания скриптов-портянок. Другие выносят «генератор» админских страниц в компоненты. Третьи разрабатывают различные обёртки, позволяющие хоть немного привести доработку панели управления «Битрикса» к ООП. Но тем не менее, каким бы решением вы не пользовались, речи об ООП быть не может, и вам так же придётся повсюду вставлять типовые куски кода: подключение ядра, связанных классов и т. п.
Автоматизация?
В «Битриксе» в принципе отсутствует роутинг страниц, основанный на единой точке входа. Под каждую новую страницу на сайте нужно создавать новый ПХП-файл. Тоже самое касается и админки. Сделали новую страницу для админки? Даже не думайте, что этим всё закончится! «Битрикс» не умеет забирать админские страницы из модуля. Ваш модуль при установке или обновлении должен создать эту страницу в каталоге bitrix/admin.
Решение есть!
Мой товарищ — Алексей Волков из «Цифровой палки» — летом прошлого года опубликовал бета-версию генератора админских страниц с немудрёным названием «Админ-хелпер».
Модуль реализует подход шаблона проектирования МВЦ в создании страниц для панели управления «Битрикса». Если у вас есть модель, написанная на ОРМ «Битрикса», вы за считанные минуты сможете сделать раздел для управления данными этой модели, ничем не уступающему по своим возможностям и внешнему виду интерфейсу управления элементами инфоблоков.
Стоит сразу же оговориться: единственный недостаток генератора на данный момент — отсутствие бизнес-процессов и документооборота. А теперь перечислю его преимущества:
- объектно-ориентированный подход,
- пара минут уходит на создание админки под КРУД-операции с моделью,
- данные могут храниться где угодно: в отдельной таблице или другой БД,
- неограниченные возможности по кастомизации интерфейса,
- нет необходимости копировать ПХП-скрипты в bitrix/admin.
С тех пор я применил на нескольких проектах этот модуль и весьма неплохо доработал его вместе со своей командой в «Нотамедии». Мы сделали версию 2.0, в которую было добавлено много различных фич, приведу некоторые из них:
- менеджер сущностей, сохраняющий данные в связанные модели,
- совместный вывод и управление записями и категориями этих записей,
- новые виджеты (файлы, элементы инфоблоков, записи из ОРМ, УРЛ, пользователи, визуальный редактор),
- возможность создания интерфейсов, не завязанных на ОРМ-моделях,
- объектно-ориентированное описание интерфейса админки.
Ближе к телу
Сейчас я покажу вам, на сколько просто и быстро вы теперь можете создавать прекрасные интерфейсы в панели управления. Сделаем раздел по управлению новостями.
Подключите «Админ-хелпер» к своему проекту через «Композер»:
Подключение генератора.
composer require digitalwand/digitalwand.admin_helper
Примера ради, представим, что у вас есть модуль: local/modules/demo.adminhelper. Как вы помните, все классы должны начинаться с неймспейса Demo\AdminHelper, что бы работала автозагрузка классов.
Структура модуля.
В каталоге lib вашего модуля создайте каталог под сущность новостей: demo.adminhelper/lib/news. В нём мы будем размещать всё, что так или иначе связано с сущностью новостей. А всё относящееся к интерфейсу панели управления «Битрикса» — в каталог demo.adminhelper/lib/news/admininterface.
Создадим модель. Подразумевается, что с ОРМ «Битрикса» вы знакомы. Модель предельно простая:
Модель новостей.
<?php
namespace Demo\AdminHelper\News;
use Bitrix\Main\Entity\DataManager;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Type\DateTime;
Loc::loadMessages(__FILE__);
/**
* Модель новостей.
*/
class NewsTable extends DataManager
{
/**
* {@inheritdoc}
*/
public static function getTableName()
{
return 'd_ah_news';
}
/**
* {@inheritdoc}
*/
public static function getMap()
{
return array(
'ID' => array(
'data_type' => 'integer',
'primary' => true,
'autocomplete' => true,
),
'DATE_CREATE' => array(
'data_type' => 'datetime',
'title' => Loc::getMessage('DEMO_AH_NEWS_DATE_CREATE'),
'default_value' => new DateTime()
),
'CREATED_BY' => array(
'data_type' => 'integer',
'title' => Loc::getMessage('DEMO_AH_NEWS_CREATED_BY'),
'default_value' => static::getUserId()
),
'MODIFIED_BY' => array(
'data_type' => 'integer',
'title' => Loc::getMessage('DEMO_AH_NEWS_MODIFIED_BY'),
'default_value' => static::getUserId()
),
'TITLE' => array(
'data_type' => 'string',
'title' => Loc::getMessage('DEMO_AH_NEWS_TITLE')
),
'TEXT' => array(
'data_type' => 'text',
'title' => Loc::getMessage('DEMO_AH_NEWS_TEXT')
),
// Для всех полей, используемых визивигом, нужно создавать в таблице атрибут с суффиксом _TEXT_TYPE.
// В нём будет храниться информация о типе сохранённого контента (ХТМЛ или обычный текст).
'TEXT_TEXT_TYPE' => array(
'data_type' => 'string'
),
'SOURCE' => array(
'data_type' => 'string',
'title' => Loc::getMessage('DEMO_AH_NEWS_SOURCE')
),
// Хранением файлов занимается Битрикс (хотя это вовсе необязательно, вы можете описать свою логику).
// В атрибуте таблицы будет хранится идентификатор файла.
'IMAGE' => array(
'data_type' => 'integer',
'title' => Loc::getMessage('DEMO_AH_NEWS_IMAGE')
),
);
}
/**
* {@inheritdoc}
*/
public static function update($primary, array $data)
{
$data['MODIFIED_BY'] = static::getUserId();
return parent::update($primary, $data);
}
/**
* Возвращает идентификатор пользователя.
*
* @return int|null
*/
public static function getUserId()
{
global $USER;
return $USER->GetID();
}
}
Теперь займёмся интерфейсом админки новостей. Давайте опишем его, что бы генератор знал, какие поля он должен отображать, какие табы должны присутствовать в форме редактирования новости:
Описание интерфейса.
<?php
namespace Demo\AdminHelper\News\AdminInterface;
use Bitrix\Main\Localization\Loc;
use DigitalWand\AdminHelper\Helper\AdminInterface;
use DigitalWand\AdminHelper\Widget\DateTimeWidget;
use DigitalWand\AdminHelper\Widget\FileWidget;
use DigitalWand\AdminHelper\Widget\NumberWidget;
use DigitalWand\AdminHelper\Widget\StringWidget;
use DigitalWand\AdminHelper\Widget\UrlWidget;
use DigitalWand\AdminHelper\Widget\UserWidget;
use DigitalWand\AdminHelper\Widget\VisualEditorWidget;
Loc::loadMessages(__FILE__);
/**
* Описание интерфейса (табок и полей) админки новостей.
*
* {@inheritdoc}
*/
class NewsAdminInterface extends AdminInterface
{
/**
* {@inheritdoc}
*/
public function fields()
{
return array(
'MAIN' => array(
'NAME' => Loc::getMessage('DEMO_AH_NEWS'),
'FIELDS' => array(
'ID' => array(
'WIDGET' => new NumberWidget(),
'READONLY' => true,
'FILTER' => true,
'HIDE_WHEN_CREATE' => true
),
'TITLE' => array(
'WIDGET' => new StringWidget(),
'SIZE' => '80',
'FILTER' => '%',
'REQUIRED' => true
),
'TEXT' => array(
'WIDGET' => new VisualEditorWidget(),
'HEADER' => false
),
'SOURCE' => array(
'WIDGET' => new UrlWidget(),
'HEADER' => false
),
'IMAGE' => array(
'WIDGET' => new FileWidget(),
'IMAGE' => true,
'HEADER' => false
),
'DATE_CREATE' => array(
'WIDGET' => new DateTimeWidget(),
'READONLY' => true,
'HIDE_WHEN_CREATE' => true
),
'CREATED_BY' => array(
'WIDGET' => new UserWidget(),
'READONLY' => true,
'HIDE_WHEN_CREATE' => true
),
'MODIFIED_BY' => array(
'WIDGET' => new UserWidget(),
'READONLY' => true,
'HIDE_WHEN_CREATE' => true
),
)
)
);
}
/**
* {@inheritdoc}
*/
public function helpers()
{
return array(
'\Demo\AdminHelper\News\AdminInterface\NewsListHelper',
'\Demo\AdminHelper\News\AdminInterface\NewsEditHelper'
);
}
}
Обратите внимание на описание полей (секция FIELDS). Каждое поле — это какой-то виджет. Виджеты представляет собой класс, занимающийся выводом представления поля, а так же предобработкой данных перед сохранением модели (но увлекаться этим не стоит, управлением данных должна заниматься модель). Виджеты имеют настройки, с помощью которых ими можно управлять. А если настроек недостаточно, вы без труда можете создать свой или расширить существующий виджет.
Далее нужно создать хелперы, которые будут заниматься «отрисовкой» страниц в панели управления. Хелпер списка новостей:
Страницы в панели управления.
<?php
namespace Demo\AdminHelper\News\AdminInterface;
use DigitalWand\AdminHelper\Helper\AdminListHelper;
/**
* Хелпер описывает интерфейс, выводящий список новостей.
*
* {@inheritdoc}
*/
class NewsListHelper extends AdminListHelper
{
protected static $model = '\Demo\AdminHelper\News\NewsTable';
}
И хелпер формы редактирования новости:
<?php
namespace Demo\AdminHelper\News\AdminInterface;
use DigitalWand\AdminHelper\Helper\AdminEditHelper;
/**
* Хелпер описывает интерфейс, выводящий форму редактирования новости.
*
* {@inheritdoc}
*/
class NewsEditHelper extends AdminEditHelper
{
protected static $model = '\Demo\AdminHelper\News\NewsTable';
}
Как видите, всего за пару минут мы написали простую админку управления новостями.
Пример рассмотренного модуля вы можете найти у меня на «Гитхабе». Помните о редакторах, делайте хорошие, удобные интерфейсы в админке, ведь теперь это просто!