Свой модуль или код в проекте - когда пора выносить в модуль
Решаем, где жить прикладному коду: в файлах проекта рядом с шаблонами или в своём модуле с установщиком, настройками и версией.
Что нужно знать заранее
Код в каталоге проекта стартует мгновенно и не требует установки вообще. Это верный выбор для правок одного сайта, пока их немного и они не образуют самостоятельную подсистему.
Модуль - это упаковка решения: установщик, версия, настройки, права и события. Он окупается там, где решение ставится на несколько сайтов или его надо включать и выключать целиком.
Файл инициализации перестаёт справляться заметно раньше, чем кажется автору. Полтысячи строк обработчиков в одном файле читаются плохо, а искать в них причину поведения приходится каждому новому разработчику.
Шаги
- Ответить честно, поедет ли этот код на другой проект в обозримом будущем.
- Оценить объём кода: несколько обработчиков или самостоятельная подсистема со своими данными.
- Проверить, нужны ли свои настройки, права доступа и страницы в административной части.
- Выбрать вариант и оформить границу: обращения к решению идут через его классы.
- Заложить время на упаковку, если решение будет продаваться или ставиться нескольким клиентам.
Решение
Держим код проекта разложенным по смыслу:
/local/php_interface/init.php - только подключение файлов, без логики/local/php_interface/events.php - регистрация обработчиков событий проекта/local/lib/Vendor/Catalog/ - классы прикладной логики проекта/local/components/vendor/ - свои компоненты витрины# файл инициализации остаётся коротким и читаемым даже через два годаРазложенный по файлам код проекта решает половину проблем большого файла инициализации. Обработчики видно единым списком, а логика живёт в классах, которые подключаются автозагрузкой.
Регистрируем автозагрузку своих классов:
\Bitrix\Main\Loader::registerNamespace('Vendor\\Catalog', $_SERVER['DOCUMENT_ROOT'] . '/local/lib/Vendor/Catalog');require_once __DIR__ . '/events.php'; // обработчики отдельным файломОформляем решение модулем, когда пора:
class vendor_catalog extends CModule{ public $MODULE_ID = 'vendor.catalog'; public $MODULE_VERSION = '1.0.0';
public function DoInstall(): void { \Bitrix\Main\ModuleManager::registerModule($this->MODULE_ID); $this->installEvents(); // обработчики регистрируются при установке $this->installDB(); // таблицы создаются здесь же }}Установщик - главное отличие модуля от кода проекта. Он умеет создавать таблицы, регистрировать обработчики и убирать всё это обратно, а код в каталоге проекта такого не умеет вовсе.
Регистрируем обработчики модуля постоянно:
$em = \Bitrix\Main\EventManager::getInstance();$em->registerEventHandler('sale', 'OnSaleOrderSaved', $this->MODULE_ID, '\Vendor\Catalog\OrderHandler', 'onSaved');// постоянная регистрация живёт в базе и переживает перезагрузку сайтаХраним настройки решения по имени модуля:
\Bitrix\Main\Config\Option::set('vendor.catalog', 'sync_enabled', 'Y');printf("обмен включён: %s\n", \Bitrix\Main\Config\Option::get('vendor.catalog', 'sync_enabled'));// у модуля появляется своя страница настроек в административном разделеНастройки с именем модуля - ещё одна причина упаковки. Они видны администратору в привычном месте, переживают обновления и не теряются среди чужих значений в файле настроек проекта.
Типичные проблемы
Файл инициализации разросся до тысячи строк.
Вся логика проекта живёт в одном файле без всякого разделения по смыслу. Обработчики и классы раскладывают по отдельным файлам и подключают автозагрузкой.
Решение не ставится на второй сайт.
Код разбросан по каталогу проекта и не собран в переносимую единицу поставки. Для переноса между проектами решение упаковывают в отдельный модуль.
После удаления модуля остались таблицы и обработчики.
В установщике не написан обратный код удаления данных и всех регистраций. Удаление пишут сразу вместе с установкой, а не когда-нибудь потом.
Обработчики перестали работать после переноса.
Они были зарегистрированы на текущий запрос в файле проекта, который не переехал. Постоянную регистрацию обработчиков делают при установке самого модуля.
Настройки решения теряются при обновлении.
Значения лежат в файле настроек проекта вместе с чужими секциями настроек. Настройки решения хранят по имени модуля штатными средствами платформы.
Частые вопросы
Когда точно хватает кода в проекте?
Когда правок немного, они специфичны для одного сайта и не образуют подсистему. Пара обработчиков и один класс упаковки не требуют.
Обязателен ли модуль для продажи решения?
Да, торговая площадка принимает именно модули с установщиком и версией. Код проекта продать нельзя технически.
Можно ли переупаковать код проекта в модуль позже?
Можно, но это отдельная работа: переезд классов, установщик и регистрация событий. Дешевле решить на старте, если перспектива понятна.
Где хранить таблицы решения?
При модуле - создавать их в установщике и удалять при деинсталляции. В коде проекта таблицы приходится заводить миграциями отдельно.
Что делать с общими библиотеками?
Сторонние библиотеки ставят менеджером зависимостей и подключают один раз. Модуль при этом объявляет свои зависимости в документации, а не тащит копии.
Смежное
- Свой модуль - оглавление подтемы
- Файл инициализации: порядок подключения, что доступно, ошибки - устройство файла инициализации подробнее
- Свой модуль: структура, установка, автозагрузка - как устроен модуль внутри
- Права в своём модуле: уровни, проверка, интерфейс настроек - что даёт упаковка в правах
- Публикация своего модуля: требования, обновления, поддержка - если решение пойдёт клиентам
- Сторонняя библиотека в проекте: composer, автозагрузка, выкладка - зависимости решения
- Обработчик события: регистрация, аргументы, отмена действия - два способа регистрации обработчиков
- Модули и решения в 1С-Битрикс - устройство модулей целиком