Перейти к содержимому

Публикация своего модуля - требования, обновления, поддержка

Готовим свой модуль к публикации: требования к коду, чистая установка и удаление, механика обновлений и понимание, во что обойдётся поддержка.

Механика

Публикуемый модуль отличается от проектного тремя вещами. У него постоянный идентификатор, начинающийся с кода партнёра; он ставится на чужие проекты, о которых вы ничего не знаете; и он обязан удаляться, не оставляя следов. Всё остальное у него устроено как у обычного модуля платформы.

Установка и удаление - это код, а не архив. Класс установки поднимает таблицы, копирует компоненты, регистрирует обработчики событий и заводит настройки; удаление проходит те же шаги в обратную сторону. Пропущенный шаг в удалении превращается в мусор на чужом сайте.

Обновления идут отдельным механизмом, а не простой перезаписью каталога модуля. Новая версия приезжает архивом, внутри которого лежит сценарий обновления: он копирует файлы и меняет структуру данных. Обычной перезаписи каталога недостаточно, потому что у покупателя может стоять версия, отставшая на несколько выпусков.

Чужие проекты устроены непредсказуемо, и это главная сложность публикации. Другая редакция, другой набор модулей, другая версия PHP, второй сайт, свои обработчики тех же событий - всё это встречается разом, и модуль обязан вести себя предсказуемо или внятно отказываться работать.

Наконец, публикация - это обязательство перед покупателем на годы вперёд. Ошибка в чужом магазине становится вашей задачей вне зависимости от того, чем вы заняты; поэтому решение о публикации принимают, оценив не только выгоду, но и поддержку на годы вперёд.

Отдельно стоит понимать, что покупатель будет ставить модуль на проект с чужой историей: с включённым композитом, с десятком других решений и с обменом, который идёт каждые пять минут. Модуль, проверенный только на аккуратном стенде, встречает всё это в первый же день продаж и ведёт себя совсем не так, как задумывалось.

Шаги

  1. Получить код партнёра и задать по нему постоянный идентификатор модуля вида partner.module.
  2. Написать установку и удаление так, чтобы второе полностью отменяло первое.
  3. Разложить файлы по каталогам установки: компоненты, страницы админки, языковые файлы.
  4. Собрать архив обновления со сценарием и проверить переход с любой прежней версии.
  5. Поставить модуль на чистую копию платформы и пройти сценарии целиком.
  6. Описать требования и ограничения в тексте, который прочитает будущий покупатель.

Код

Задаём идентификатор и версию:

/bitrix/modules/vendor.shop/install/version.php
$arModuleVersion = ['VERSION' => '1.2.0', 'VERSION_DATE' => '2026-08-06 12:00:00'];
// install/index.php
$this->MODULE_ID = 'vendor.shop'; // код партнёра плюс имя модуля
$this->PARTNER_NAME = 'Компания «Вендор»';
$this->PARTNER_URI = 'https://example.org';

Идентификатор модуля начинается с кода партнёра. Он же становится именем каталога и приставкой всех настроек, поэтому меняют его только вместе с выпуском нового модуля, а не новой версии.

Делаем установку и удаление зеркальными:

public function DoInstall()
{
$this->InstallDB(); // таблицы
$this->InstallEvents(); // обработчики событий
$this->InstallFiles(); // компоненты и страницы админки
ModuleManager::registerModule($this->MODULE_ID);
}
public function DoUninstall()
{
ModuleManager::unRegisterModule($this->MODULE_ID);
$this->UnInstallFiles();
$this->UnInstallEvents();
$this->UnInstallDB(); // с вопросом: удалять ли данные покупателя
}

Удаление обязано убирать всё, что поставила установка. Единственное исключение - данные: их удаляют только с явного согласия, потому что случайное удаление модуля не должно стоить покупателю накопленной за год информации.

Копируем файлы туда, где они переживут обновление:

public function InstallFiles()
{
CopyDirFiles(__DIR__ . '/components', $_SERVER['DOCUMENT_ROOT'] . '/bitrix/components', true, true);
CopyDirFiles(__DIR__ . '/admin', $_SERVER['DOCUMENT_ROOT'] . '/bitrix/admin', true, true);
return true;
}
// файлы модуля живут в его каталоге, а в общие каталоги кладут только точки входа

Общие каталоги трогают минимально. Чем меньше файлов модуль раскладывает по чужим местам, тем меньше он конфликтует с другими решениями и тем чище удаляется.

Выпускаем обновление сценарием:

// updater.php внутри архива обновления
if ($updater->CanUpdateKernel()) {
$updater->CopyFiles('install/components', 'components');
}
$updater->Query("ALTER TABLE b_vendor_shop ADD COLUMN STATUS varchar(20)", true);
// сценарий должен переживать переход с любой прежней версии, а не только с соседней

Обновление приходит архивом со своим сценарием. Он выполняется у покупателя, чью версию вы не выбирали, поэтому изменения структуры пишут так, чтобы повторный запуск ничего не ломал.

Проверяем на чистой копии:

1. пустая установка платформы нужной редакции
2. установка модуля, проход по всем его сценариям
3. удаление модуля и проверка: не осталось ли таблиц, файлов и настроек
4. установка прежней версии и обновление до новой
5. повтор на второй редакции и на втором сайте

Модуль ставят на пустую копию, а не на свой проект. На своём проекте работает половина того, что на самом деле тянется из его настроек, и именно эта половина ломается у первого покупателя.

Сообщаем о несовместимости внятно:

if (!\Bitrix\Main\Loader::includeModule('sale')) {
$APPLICATION->ThrowException('Модуль требует установленного модуля «Интернет-магазин»');
return false; // отказываемся работать, а не падаем на первой строке
}
if (version_compare(SM_VERSION, '22.0.0', '<')) {
$APPLICATION->ThrowException('Нужна версия главного модуля не ниже 22.0');
return false;
}
// проверку версии делают до установки таблиц: откатывать половину сложнее

Отказ с понятным сообщением стоит дешевле любой поддержки. Покупатель, увидевший строку про недостающий модуль, решает вопрос сам за минуту, а покупатель, увидевший белый экран, пишет вам письмо и ждёт ответа сутки.

Ограничения

Модуль не имеет права править файлы ядра и чужих модулей. Это не рекомендация, а условие публикации: решение, которое переписывает штатные файлы, ломается при первом же обновлении продукта у покупателя.

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

Поддержка растягивается на годы вперёд и стоит дороже самой разработки. Покупатель, купивший модуль сегодня, придёт с вопросом через два года, и к этому моменту у него будет другая версия платформы, другая версия PHP и полностью забытые вами подробности.

Цену и условия поддержки продумывают до публикации, а не после первых продаж. Бесплатный модуль с сотней установок отнимает столько же времени, сколько платный, но не даёт ни рубля на это время, и решение об этом принимают заранее.

Публикация требует и текста для покупателя, а не только одного рабочего кода. Описание, снимки экрана, список требований и понятная инструкция по настройке отнимают не меньше времени, чем последний рабочий модуль, и без них модуль не покупают.

Типичные проблемы

После удаления модуля в базе остались его таблицы.

Удаление не отменяет всего того, что делала его собственная установка. Шаги удаления пишут зеркально шагам установки, один в один.

У покупателя модуль сломался после обновления продукта.

Модуль правил файлы ядра или полагался на их внутреннее устройство. Публикуемый модуль работает только со своим собственным каталогом файлов и своих таблиц.

Обновление не встаёт на старую версию.

Сценарий обновления рассчитан только на переход с соседней версии. Он должен переживать переход с любой прежней версии этого модуля.

Модуль падает на младшей редакции.

Код обращается к модулю, которого в этой редакции платформы попросту нет вовсе. Наличие нужных модулей проверяют и внятно сообщают самому покупателю об их отсутствии.

На чистой копии модуль не работает.

Он опирался на настройки и на данные вашего собственного рабочего проекта сайта. Проверку ведут на пустой установке, а не на своём сайте.

Частые вопросы

Можно ли опубликовать модуль без кода партнёра?

Нет: идентификатор модуля строится из него. Код получают в партнёрском кабинете до разработки.

Удалять ли данные покупателя при удалении модуля?

Только с явного подтверждения. Молчаливое удаление накопленных данных - худшее, что может сделать модуль.

Как проверить обновление с давней версии?

Поставить ту версию на чистую копию и обновить. Другого честного способа нет.

Сколько времени занимает поддержка?

Больше, чем разработка, и растянута на годы. Это стоит оценить до публикации, а не после.

Обязательно ли поддерживать второй сайт и язык?

Для публикуемого модуля - да: у покупателя может быть и то, и другое. Проверяют это на той же чистой копии.

Смежное

Первоисточник