Собственное дополнение MODX Revolution имеет смысл разрабатывать, когда задача уже не помещается в один сниппет или плагин: нужны свои таблицы, права доступа, фоновые операции, API, импорт/экспорт, CMP в менеджере, обновления и безопасная установка на другие сайты.

Главная цель Extra — не просто «сложить PHP-файлы в core/components». Хорошее дополнение должно устанавливаться, обновляться и удаляться предсказуемо, не требовать ручного редактирования ядра MODX и не терять данные при следующем релизе.

Когда действительно нужен собственный компонент

  • есть отдельная бизнес-сущность и свои таблицы БД;
  • нужен интерфейс управления в MODX Manager;
  • операции должны проверять права пользователя;
  • нужны processors для CRUD, поиска и массовых операций;
  • потребуется API, AJAX или интеграция с внешним сервисом;
  • компонент должен ставиться на несколько проектов;
  • нужны миграции схемы БД и обновление между версиями;
  • важен нормальный uninstall без ручной чистки файлов.

Когда отдельное дополнение избыточно

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

Базовая архитектура Extra

Типичная структура разделяет публичные assets и серверную часть в core. Системные классы, processors, lexicon и модель данных не должны лежать в публичном каталоге без причины.

Пример структуры дополнения

TEXT
myextra/
├─ assets/
│  └─ components/myextra/
│     ├─ js/
│     ├─ css/
│     └─ connector.php
├─ core/
│  └─ components/myextra/
│     ├─ controllers/
│     ├─ elements/
│     │  ├─ snippets/
│     │  ├─ plugins/
│     │  └─ chunks/
│     ├─ lexicon/
│     │  └─ ru/
│     ├─ model/
│     ├─ processors/
│     └─ docs/
└─ _build/
   ├─ resolvers/
   ├─ data/
   └─ build.php

Что за что отвечает

Namespace

Связывает имя компонента с его путями. Без корректного namespace менеджер не сможет стабильно загрузить контроллеры, lexicon и assets.

Service class

Вынесите общую бизнес-логику из сниппетов и processors в сервисный класс. Тогда одна и та же проверка не будет копироваться в пяти файлах, а код проще тестировать.

Processors

CRUD и действия Manager лучше выполнять через processors. Там можно централизованно проверить права, входные данные и вернуть клиенту структурированный ответ.

CMP

Custom Manager Page нужна, когда контентом компонента управляет редактор или администратор. В MODX 2.x многие CMP используют ExtJS. Если компонент должен развиваться дальше, полезно не завязывать всю архитектуру на старые Manager-механизмы: в MODX 3 часть legacy-подходов изменилась, а modAction удалён.

xPDO model

Если компонент хранит собственные сущности, схему БД и модель нужно рассматривать как часть версии компонента. Изменение таблицы без миграции — одна из самых частых причин сломанных обновлений.

Практический порядок разработки

  1. Опишите сущности, роли пользователей и сценарии.
  2. Определите, что хранится в MODX resource/TV, а что — в собственных таблицах.
  3. Создайте сервисный слой и модель данных.
  4. Добавьте processors с permission checks и валидацией.
  5. Только после серверной логики собирайте CMP.
  6. Подготовьте lexicon, настройки и permissions.
  7. Соберите transport package.
  8. Проверьте чистую установку.
  9. Проверьте обновление с предыдущей версии.
  10. Проверьте удаление и сохранность данных по выбранной политике.

MODX 2.x: processor с permission и валидацией

PHP
<?php
class MyExtraItemCreateProcessor extends modObjectCreateProcessor
{
    public $classKey = 'MyExtraItem';
    public $objectType = 'myextra.item';
    public $languageTopics = array('myextra:default');
    public $permission = 'myextra_save';

    public function beforeSet()
    {
        $name = trim((string)$this->getProperty('name'));

        if ($name === '') {
            $this->addFieldError('name', 'Укажите название');
        }

        if (mb_strlen($name, 'UTF-8') > 255) {
            $this->addFieldError('name', 'Название слишком длинное');
        }

        return parent::beforeSet();
    }
}

return 'MyExtraItemCreateProcessor';

Сниппет, который передаёт работу сервисному классу

PHP
<?php
/** @var modX $modx */

$corePath = $modx->getOption(
    'myextra.core_path',
    null,
    $modx->getOption('core_path') . 'components/myextra/'
);

$serviceFile = $corePath . 'model/myextra/myextra.class.php';

if (!is_file($serviceFile)) {
    $modx->log(modX::LOG_LEVEL_ERROR, '[MyExtra] Service file not found: ' . $serviceFile);
    return '';
}

require_once $serviceFile;

$service = new MyExtra($modx, array(
    'corePath' => $corePath,
));

return $service->run();

Архитектурный чек-лист компонента

СлойЧто проверятьТипичная ошибка
Namespaceпути core/assets, lexiconкомпонент работает только на сервере разработчика
Service layerбизнес-логика отдельно от UI
и processors
Processorpermission, validation, errorsдействие доступно без нужного права
CMPзагрузка JS/CSS, ошибки AJAXпустая вкладка из-за ошибки xtype или JS
xPDO model
ема, индексы, миграцииновая версия ожидает колонку, которой нет
Transport Packageclean install/update/remove
старой версии
Resolverидемпотентность и rollbackповторная установка ломает таблицы
Frontend
путейassets работают только в одном домене

Почему нельзя писать всё прямо в плагине

Плагин вызывается на событиях MODX. Если в нём смешать SQL, бизнес-логику, HTML и работу с внешним API, любой сбой начинает затрагивать весь сайт. Плагин лучше использовать как точку входа, а основную работу передавать сервису.

Права доступа — часть архитектуры

Скрыть кнопку в Manager недостаточно. Серверный processor должен сам проверять permission, потому что запрос можно отправить напрямую. Для операций удаления, экспорта, импорта и изменения системных настроек лучше создавать отдельные permissions.

Transport Package: что проверить до релиза

  • версия одинакова в manifest, package metadata и документации;
  • в пакет попадают только нужные файлы;
  • resolvers используют реальные пути исходников;
  • чистая установка создаёт namespace, menu, settings и таблицы;
  • обновление не удаляет пользовательские данные;
  • повторный resolver не создаёт дубли;
  • uninstall ведёт себя так, как описано в документации;
  • после установки очищается нужный кэш;
  • ошибки установки попадают в журнал и не скрываются.

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

  1. Новый MODX без компонента → чистая установка.
  2. Предыдущая стабильная версия → обновление.
  3. Откат к backup → повторное обновление.
  4. Пользователь без permission → проверка запрета операции.
  5. Некорректные данные → проверка серверной валидации.
  6. Пустая база → проверка empty states CMP.
  7. Большая таблица → пагинация и производительность.
  8. Удаление пакета → проверка файлов, меню, namespace и данных.

MODX 2.8 и MODX 3

Если дополнение должно жить дольше одного проекта, заранее определите матрицу совместимости. Код, написанный строго под Manager MODX 2.x, не всегда переносится в MODX 3 без изменений. Особенно осторожно относитесь к устаревшим Manager-механизмам и жёсткой привязке к старому ExtJS-коду.

Что должно получиться в конце

Готовое дополнение — это не набор PHP-файлов, а воспроизводимый продукт: исходники, структура компонента, transport package, миграции, permissions, документация установки и понятная процедура обновления. Именно это отличает компонент, который можно сопровождать годами, от разовой доработки.

Технические критерии для собственного дополнения MODX

Собственное дополнение оправдано, когда типовые extras не поддерживают необходимую модель данных, сложный процесс согласования либо интеграцию с внешним API. До разработки составьте карту таблиц, перечень разрешений менеджера, список processors/endpoint и системных событий. Для установки предусмотрите транспортный пакет с проверяемыми резолверами и стратегией миграции существующих данных.

Критерии приёмки: чистая установка; обновление поверх старой версии; сохранение данных после обновления; контроль доступа; журналирование ошибок; удаление без потери сторонних ресурсов. Номер версии пакета сам по себе не подтверждает, что файлы и элементы MODX обновились.