Классы MODX Revolution для разработки на PHP
Классы MODX в PHP: подробное руководство
MODX Revolution построен на основе объектно-ориентированной архитектуры, использующей классы PHP для работы с системой. Главный класс modX предоставляет доступ ко всем подсистемам: ресурсам, пользователям, шаблонам, чанкам, сниппетам и базе данных через ORM xPDO. В этой статье рассматриваются основные классы и варианты их применения с примерами кода.
Как получить доступ к главному объекту modX и инициализировать контекст?
Основной способ работы с MODX - получить экземпляр класса modX. В большинстве случаев он уже доступен в глобальной переменной $modx после старта системы. Если требуется инициализация вне стандартного цикла, используется метод initialize().
// Пример получения и инициализации modX
$modx = new modX();
$modx->initialize('web'); // контекст 'web' (фронт)
$modx->getService('error','error.modError');
Modx php class (классы modx в php)
После инициализации становятся доступны все методы: getObject, getCollection, runSnippet и другие. Проблемы: если контекст не указан или указан неверно, возникает ошибка modX::initialize() - context does not exist. Решение - убедиться в наличии контекста в базе данных.
Типичная ошибка:
Попытка обратиться к $modx до его инициализации - вызовет фатальную ошибку. Используйте проверку: if ($modx instanceof modX) { ... }.
Как получить объект ресурса (страницы) по ID?
Для работы с контентом используется метод getObject класса modX с указанием класса modResource. Это позволяет загрузить один ресурс.
$id = 123;
$resource = $modx->getObject('modResource', $id);
if ($resource) {
echo $resource->get('pagetitle');
echo $resource->get('content');
}
Результат (если ресурс с id = 123 существует):
Заголовок страницы
Текст контента...
Проблемы: если ID не существует, возвращается null. Ошибка игнорируется, но последующий вызов методов на null вызовет исключение. Рекомендуется проверять результат перед использованием.
Ошибка:
Вызов ->get() на null. Решение - выполнить проверку if ($resource) { ... }.
Как создать нового пользователя через класс modUser?
Для создания пользователя используется класс modUser. Объект создаётся с помощью newObject, затем заполняются поля и вызывается save().
$user = $modx->newObject('modUser');
$user->set('username', 'newuser');
$user->set('password', md5('strongpassword')); // но лучше использовать $modx->user->hashPassword()
$user->set('active', true);
if ($user->save()) {
echo 'Пользователь создан, ID: '.$user->get('id');
} else {
echo 'Ошибка создания пользователя';
}
Проблемы: пароль должен быть зашифрован правильным алгоритмом. Устаревший md5 не рекомендуется. MODX предоставляет метод hashPassword() объекта modUser. Необходимо также назначить группу пользователя (дополнительный вызов $user->joinGroup(1,'Member')).
Ошибка:
Сохранение без пароля - база данных выдаст ошибку. Убедитесь, что все обязательные поля заполнены.
Как выполнить произвольный SQL запрос через xPDO?
Класс xPDO (базовый ORM в MODX) позволяет выполнять прямые запросы с помощью метода query(). Это может быть полезно для сложных выборок, неудобных через getCollection.
$sql = "SELECT * FROM modx_site_content WHERE published = 1 LIMIT 10";
$result = $modx->query($sql);
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
echo $row['pagetitle'].'<br>';
}
Результат - список заголовков опубликованных ресурсов. Проблемы: имена таблиц могут различаться в зависимости от префикса. Рекомендуется использовать $modx->getTableName() для получения правильного имени. Также следует избегать SQL-инъекций, используя подготовленные выражения.
Ошибка:
Выполнение запроса с пользовательскими данными без экранирования - уязвимость. Используйте $modx->prepare() и execute() вместо прямого query.
Как создать свой процессор (класс modProcessor) для обработки формы?
Процессоры - стандартный способ обработки данных в MODX. Создаётся класс, наследующий modProcessor, и реализуется метод process(). Процессоры легко вызываются через $modx->runProcessor().
// Файл: core/components/myapp/processors/web/form/save.class.php
class myappWebFormSaveProcessor extends modProcessor {
public function process() {
$name = $this->getProperty('name');
$email = $this->getProperty('email');
// валидация и сохранение в БД
return $this->success('Форма сохранена', array('id' => 1));
}
}
// Вызов процессора
$response = $modx->runProcessor('web/form/save', $_POST, array('processors_path' => MODX_CORE_PATH.'components/myapp/processors/'));
if ($response->isError()) {
echo $response->getMessage();
} else {
echo $response->getMessage();
}
Проблемы: неправильный путь к процессору или отсутствие класса. Убедитесь, что файл существует и путь зарегистрирован. Также возможна ошибка при отсутствии прав доступа - процессоры проверяют policy.
Ошибка:
Вызов несуществующего процессора - ответ 'Processor not found'. Проверьте путь и конфигурацию.
Расширенные примеры работы с классами MODX
Ниже приведены более сложные и редко встречающиеся в документации сценарии использования классов MODX.
Создание сервисного класса для работы с API
В MODX можно зарегистрировать свой сервис через метод getService(). Сервисный класс подключается один раз и сохраняет состояние.
// Файл: core/components/myapp/model/myapp/myapp.class.php
class MyApp {
private $modx;
private $config = array();
public function __construct(modX &$modx, array $config = array()) {
$this->modx =& $modx;
$this->config = $config;
}
public function getItems($limit = 10) {
$c = $this->modx->newQuery('modResource');
$c->where(array('published' => 1));
$c->limit($limit);
return $this->modx->getCollection('modResource', $c);
}
}
// Регистрация сервиса
$myapp = $modx->getService('myapp', 'MyApp', MODX_CORE_PATH.'components/myapp/model/myapp/', $config);
$items = $myapp->getItems(5);
foreach ($items as $item) {
echo $item->get('pagetitle').'<br>';
}
Результат - вывод пяти опубликованных ресурсов. Проблемы: путь к классу должен быть корректен, класс должен быть определён до вызова getService. Ошибка Class not found - проверьте autoload или include.
Работа с системными событиями через класс modEventHandler
События в MODX позволяют подключать свою логику в различных точках системы. Создание обработчика осуществляется через класс modPlugin и присоединение к событию.
$modx->addEventListener('OnBeforeDocFormSave', 'myPlugin');
function myPlugin($event) {
$resource =& $event->params['resource'];
$resource->set('pagetitle', 'Превью: '.$resource->get('pagetitle'));
}
Этот код меняет заголовок ресурса перед сохранением. Проблемы: если функция не определена, вызовет ошибку. Лучше использовать класс-плагин с методом run().
class MyPlugin {
public function run($event) {
$resource =& $event->params['resource'];
// логика
}
}
$modx->addEventListener('OnBeforeDocFormSave', array('MyPlugin', 'run'));
Использование xPDO для сложных JOIN-запросов
ORM xPDO поддерживает построение запросов с объединением таблиц. Пример получения ресурсов вместе с полями пользователя-автора.
$c = $modx->newQuery('modResource');
$c->innerJoin('modUser', 'Author', 'modResource.createdby = Author.id');
$c->select(array('modResource.*', 'Author.username'));
$c->where(array('modResource.published' => 1));
$resources = $modx->getCollection('modResource', $c);
foreach ($resources as $resource) {
echo $resource->get('pagetitle').' - автор: '.$resource->get('username').'<br>';
}
Результат - заголовки ресурсов с никами авторов. Проблемы: неправильные имена таблиц или полей. Используйте $modx->getAlias() для уточнения. При использовании большого количества JOIN может упасть производительность - рекомендуется индексировать поля.
Создание своего класса модели с наследованием modResource
Иногда нужно расширить стандартный класс ресурса. Для этого создаётся новый класс, наследующий modResource, и регистрируется в системе.
class MyResource extends modResource {
public function getPageTitle() {
return 'Спец: '.$this->get('pagetitle');
}
}
// После регистрации в расширении можно использовать:
$resource = $modx->getObject('MyResource', 10);
echo $resource->getPageTitle();
Требуется настроить xPDO так, чтобы класс был известен. Обычно это делается через файл map и схему. Подробнее - в документации по созданию пользовательских моделей.