Ранний доступ: сниженные цены до 1 июня 2026. Соберите CRM выгодно. Подробнее

Модернизация NXR-Core через модуль

Документация для разработчиков

Документация для разработчиков

NXR-Core поставляется цельным дистрибутивом: при обновлении подменяется дерево приложения. Чтобы не терять доработки, кастом выносится в модуль — отдельный пакет с кодом, маршрутами и ресурсами, который подключается к CRM как расширение. Ниже — практический ориентир для тех, кто пишет такой модуль вручную.

Зачем модуль, а не правки в ядре

Правки напрямую в файлах ядра перезаписываются при следующем обновлении. Модуль живёт вне затираемого дерева (типичный вариант — каталог модулей на сервере) и подключается при старте приложения: так вы сохраняете обновляемость платформы и повторяемость установки на разных инсталляциях.

Уникальное имя модуля (slug)

У модуля должен быть уникальный идентификатор — slug (латиница, обычно snake_case, без префикса mod_): так он хранится в базе CRM и в списке включённых модулей. Не пересекайтесь с другими модулями на той же установке. Перед публикацией убедитесь, что такого slug ещё нет у заказчика. Дубли дают конфликты автозагрузки, маршрутов и миграций. Корневая папка репозитория при этом обычно называется mod_slug (например, slug cash → папка mod_cash) — это не то же самое, что slug в БД.

Типовая структура пакета

Ниже пути — относительно корня пакета: это корень архива или репозитория, обычно каталог mod_slug (например mod_cash). Внутри него лежат mod_config/, app/, modules/slug/ и т.д.; во вложенном пути modules/… повторяется тот же slug, что в CRM (например modules/cash/routes/), без префикса mod_.

После установки ядро подхватывает модуль из нескольких возможных базовых каталогов (в том числе modules/slug, modules/mod_slug, storage/modules/slug, storage/modules/mod_slug — на Windows разделитель может быть \). Код app/, маршруты и ресурсы оказываются в дереве приложения. В хранилище storage/modules/mod_slug для долговременного сопровождения из админки нередко сохраняют только каталог mod_config и файлы в нём; при этом providers.php и остальное из mod_config ядро всё равно находит по тем же правилам поиска. Остальные пункты списка описывают полный пакет в репозитории, а не только эту «урезанную» копию в storage.

  • mod_config/module.xml — метаданные: человекочитаемое имя, версия, кластер, описание.
  • mod_config/providers.php — список классов Service Provider Laravel, которые нужно зарегистрировать.
  • mod_config/params.php — при необходимости форма настроек модуля в админке.
  • app/ — PHP-классы в пространстве имён App\... (например наследники контроллеров ядра, свои сервисы, провайдеры).
  • modules/slug/routes/web.php (и при необходимости api.php) — маршруты модуля; slug совпадает с идентификатором в CRM (не с именем корня mod_…).
  • resources/views/ — Blade-шаблоны; при совпадении путей с ядром можно переопределять отображение через приоритет путей (если платформа это поддерживает).
  • database/migrations/ — миграции только для таблиц модуля; имена файлов и таблиц не должны конфликтовать с ядром.
  • lang/ — переводы строк модуля.

Service Provider: точка входа

В провайдере модуля в методе register() регистрируйте подмены через контейнер Laravel: app()->bind(ИсходныйКласс::class, ВашКласс::class) для контроллеров и сервисов, которые ядро создаёт через DI. Так вы переопределяете отдельные методы в классе-наследнике, не копируя целые файлы ядра.

В boot() уместны подключение композеров представлений, дополнительных маршрутов или подписок на события моделей — если это соответствует версии ядра и вашей архитектуре.

Контроллеры и сервисы

Для изменения поведения экшена: класс extends исходного контроллера из ядра, переопределение нужных методов, затем bind на ваш класс. Убедитесь, что экземпляр действительно создаётся через контейнер, а не через new внутри ядра — иначе подмена не сработает.

Сервисы с внедрением через конструктор обычно удаётся подменить тем же приёмом. Модели Eloquent «в лоб» тем же способом не заменяют: для бизнес-логики данных используйте события модели, наблюдатели или явные сервисы, если ядро их предоставляет.

Другие модули (не только ядро)

Описанный подход в первую очередь рассчитан на доработку ядра NXR-Core. Теоретически те же bind и наследование можно применить и к классам другого установленного модуля, если его контроллеры и сервисы создаются через контейнер Laravel — тогда ваша регистрация в провайдере может переопределить реализацию.

На практике это хрупкий сценарий: порядок загрузки модулей и провайдеров влияет на то, чья подмена «победит»; два модуля, оба подменяющие один и тот же класс, легко конфликтуют. Если целевой модуль внутри себя вызывает new Класс() или статические методы, контейнер не участвует — подмена не сработает. Конфликты маршрутов решаются не только bind, а порядком регистрации путей.

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

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

Представления (Blade)

Дублируйте структуру каталогов представлений и имена файлов, которые нужно переопределить; платформа должна искать шаблоны модуля раньше шаблонов ядра. Альтернатива — собственные имена шаблонов и вызовы из ваших контроллеров после подмены.

Миграции и зависимости

Таблицы модуля именуйте с префиксом или уникальным префиксом slug, чтобы не пересечься с ядром и другими модулями. После обновления ядра прогоните миграции в согласованном с заказчиком порядке и проверьте совместимость наследников с обновлёнными базовыми классами.

Чек-лист перед сдачей

  • Slug модуля уникален и согласован с заказчиком.
  • Провайдер объявлен в mod_config/providers.php и корректно подключается.
  • Подмены зарегистрированы в register(), без лишних глобальных побочных эффектов.
  • Маршруты модуля не дублируют пути ядра без необходимости.
  • После обновления NXR-Core проверены критичные сценарии и совместимость с родительскими классами.
  • Если затрагиваются классы других модулей — осознанно оценён порядок загрузки и риски; после обновления этих модулей сценарии перепроверены.

Материал описывает практику расширения CRM модулем со стороны разработчика и не заменяет внутреннюю спецификацию конкретной сборки. Уточняйте у интегратора версию ядра и согласованный способ поставки модуля на прод.