+7 988 353-52-54 kompman1@yandex.ru

г. Краснодар

Структура модуля и module.json

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

Модуль — папка modules/<id>/. Ядро находит его само: Composer и пересборка не нужны.

modules/mymodule/
  module.json            манифест
  src/                   PHP-код (PSR-4 из манифеста)
  config/services.yaml   сервисы (Symfony DI, autowire)
  migrations/            миграции базы
  templates/             Twig-шаблоны витрины (тема может переопределить)
  blocks/<code>/         свои блоки конструктора
  assets/storefront.css  стили витрины (подключаются сами)
  admin/index.ts         админка модуля (Vue)
  translations/          переводы (messages.ru.yaml…)
  market/                картинки для каталога

module.json

{
    "id": "mymodule",
    "name": "My module",
    "version": "1.0.0",
    "description": "What it does, in English",
    "category": "marketing",
    "icon": "star",
    "license": {"type": "open"},
    "requires": {"core": "^1.3.29", "php": ">=8.3", "modules": {"shop": "^1.2"}},
    "autoload": {"psr-4": {"Acme\\MyModule\\": "src"}},
    "class": "Acme\\MyModule\\MyModule",
    "market": {"title": "Мой модуль", "summary": "…", "description": "…", "preview": "market/preview.jpg"}
}
  • category — раздел каталога: content, commerce, channels, crm, marketing, seo, system.
  • license — open (бесплатный) или commercial с кодом продукта (см. «Лицензирование»).
  • requires.modules — от каких модулей зависит; ядро не даст включить без них.

Класс модуля

final class MyModule extends Module
{
    public function install(ModuleLifecycleContext $context): void
    {
        // типы контента, поля, права — идемпотентно
    }

    public function update(ModuleLifecycleContext $context): void
    {
        $this->install($context);
    }
}

install() вызывается при установке, update() — при обновлении версии. Делайте их идемпотентными: повторный вызов не должен ломать данные.

Сервисы

config/services.yaml — обычный Symfony DI с autowire и autoconfigure:

services:
    _defaults: {autowire: true, autoconfigure: true, public: false}
    Acme\MyModule\:
        resource: '../src/'
        exclude: ['../src/MyModule.php']

Миграции

Класс в migrations/, наследник NewCMS\Core\Database\Migration\AbstractMigration. В MySQL изменения схемы не транзакционны, поэтому проверяйте hasTable() и делайте миграцию повторяемой.

Контроллеры

Классы в src/Controller/, наследники NewCMS\Core\Http\AbstractController, маршруты — атрибутом:

#[Route('/api/admin/v1/mymodule/items', name: 'mymodule.items', methods: ['GET'])]
public function items(): JsonResponse { … }

Адреса /api/admin/v1/… требуют входа в админку и CSRF-токен — проверяйте права через AuthorizationChecker.

Статья помогла?