Розробка кастомного пакета (Extra) MODX
Extra MODX — повнофункціональне розширення: компонент (інтерфейс у менеджері), набір сніпетів, плагінів, чанків, системних налаштувань. Упакований як .transport.zip для встановлення через Package Manager. Це правильний спосіб розповсюджувати та підтримувати складну функціональність.
Структура Extra
core/components/myextra/
├── controllers/
│ └── home.class.php # Контролер MODX
├── docs/
│ └── changelog.txt
├── elements/
│ ├── chunks/
│ ├── plugins/
│ ├── snippets/
│ └── templates/
├── lexicon/
│ └── ru/
│ └── default.inc.php # Переклади
├── model/
│ └── myextra/ # моделі xPDO
│ ├── myitem.class.php
│ ├── mysql/
│ │ ├── myitem.class.php
│ │ └── myitem.map.inc.php
│ └── myextra.mysql.schema.xml
└── processors/
└── mgr/
└── items/
├── getlist.class.php
├── get.class.php
├── create.class.php
├── update.class.php
└── remove.class.php
assets/components/myextra/
├── js/
│ ├── mgr/
│ │ └── myextra.js # Інтерфейс ExtJS
│ └── widgets/
│ └── items.grid.js
└── css/
└── mgr.css
Схема БД xPDO
<!-- core/components/myextra/model/myextra/mysql/myextra.mysql.schema.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<model package="myextra" baseClass="xPDOObject" platform="mysql" version="1.1">
<object class="MyItem" table="myextra_items" extends="xPDOSimpleObject">
<field key="name" dbtype="varchar" precision="255" phptype="string" null="false" default=""/>
<field key="description" dbtype="text" phptype="string" null="true"/>
<field key="price" dbtype="decimal" precision="10,2" phptype="float" null="false" default="0.00"/>
<field key="status" dbtype="tinyint" precision="1" phptype="integer" null="false" default="1"/>
<field key="created_at" dbtype="datetime" phptype="datetime" null="true"/>
<index alias="name" name="name" primary="false" unique="false" type="BTREE">
<column key="name" length="" collation="A" null="false"/>
</index>
</object>
</model>
Модель xPDO
// core/components/myextra/model/myextra/myitem.class.php
class MyItem extends xPDOSimpleObject {
public function getLink(): string {
return $this->xpdo->makeUrl(
$this->xpdo->getOption('myextra.item_page', null, 1),
'',
['id' => $this->get('id')],
'full'
);
}
}
Процесор (операції CRUD)
// core/components/myextra/processors/mgr/items/getlist.class.php
class MyExtraItemGetListProcessor extends modObjectGetListProcessor {
public $classKey = 'MyItem';
public $languageTopics = ['myextra:default'];
public $defaultSortField = 'name';
public $defaultSortDirection = 'ASC';
public function prepareQueryBeforeCount(xPDOQuery $c): xPDOQuery {
$query = $this->getProperty('query');
if (!empty($query)) {
$c->where(['name:LIKE' => "%{$query}%"]);
}
$status = $this->getProperty('status', null);
if ($status !== null && $status !== '') {
$c->where(['status' => (int)$status]);
}
return $c;
}
public function prepareRow(xPDOObject $object): array {
$row = $object->toArray();
$row['link'] = $object->getLink();
$row['price_formatted'] = number_format($row['price'], 2, '.', ' ') . ' ₽';
return $row;
}
}
Сніпет Extra
<?php
// core/components/myextra/elements/snippets/myextra.snippet.php
$basePath = $modx->getOption('myextra.core_path', null,
$modx->getOption('core_path') . 'components/myextra/');
$modx->addPackage('myextra', $basePath . 'model/');
$modx->lexicon->load('myextra:default');
$limit = (int)($scriptProperties['limit'] ?? 10);
$offset = (int)($scriptProperties['offset'] ?? 0);
$tpl = $scriptProperties['tpl'] ?? 'myextra.item';
$c = $modx->newQuery('MyItem');
$c->where(['status' => 1]);
$c->limit($limit, $offset);
$c->sortby('name', 'ASC');
$items = $modx->getCollection('MyItem', $c);
$output = '';
foreach ($items as $item) {
$output .= $modx->getChunk($tpl, $item->toArray());
}
return $output;
Збірка Transport Package
// _build/build.transport.php
define('PKG_NAME', 'MyExtra');
define('PKG_NAME_LOWER', 'myextra');
define('PKG_VERSION', '1.0.0');
define('PKG_RELEASE', 'pl');
// Створення пакета
$builder = new modPackageBuilder($modx);
$builder->createPackage(PKG_NAME_LOWER, PKG_VERSION, PKG_RELEASE);
$builder->registerNamespace(PKG_NAME_LOWER, false, true, '{core_path}components/' . PKG_NAME_LOWER . '/');
// Добавити категорію з елементами
$category = $modx->newObject('modCategory');
$category->set('id', 1);
$category->set('category', PKG_NAME);
// Добавити сніпети, чанки, плагіни...
$snippets = includeSnippets($builder, $modx);
$category->addMany($snippets);
// Створити vehicle
$attr = [
xPDOTransport::PRESERVE_KEYS => false,
xPDOTransport::UPDATE_OBJECT => true,
xPDOTransport::UNIQUE_KEY => 'category',
xPDOTransport::RELATED_OBJECTS => true,
xPDOTransport::RELATED_OBJECT_ATTRIBUTES => ['Snippets' => [...], 'Chunks' => [...]],
];
$vehicle = $builder->createVehicle($category, $attr);
$builder->putVehicle($vehicle);
// Остаточна упаковка
$builder->pack();
Терміни
Розробка Extra з інтерфейсом CRUD у менеджері, 2–3 сніпетами та базовою схемою БД — 2–3 тижні.







