Кастомные таблицы в MODX и xPDO: типичные ошибки
Кастомная таблица в MODX — это не просто SQL-таблица: xPDO должен знать её схему и сопоставить поля с объектом. Разбираем ошибки, из-за которых модель не загружается, запросы возвращают пустой результат, а сохранение не меняет данные.

В MODX Revolution 2.8.x таблица может существовать в базе, но xPDO всё равно не найдёт её или не сохранит объект: для этого мало создать SQL-таблицу — нужно корректно описать модель и подключить пакет. Разберём типичные ошибки при работе с кастомными таблицами и способы их проверить, не меняя сразу весь компонент.
Сначала проверьте связку «схема — модель — пакет»
Ниже речь о MODX Revolution 2.8.x и xPDO 2.x. Схема описывает структуру данных, сгенерированные классы и карты объектов связывают эту структуру с PHP, а зарегистрированный пакет позволяет MODX найти описание модели. Ошибка в любом звене может выглядеть одинаково: объект не находится, запрос возвращает пустую коллекцию или запись не появляется.
Перед отладкой подготовьте доступ к базе и файлам компонента. Уточните фактические имена таблиц и полей, префикс таблиц в конфигурации MODX, путь к папке модели и имя PHP-класса. Сверяйте примеры с документацией именно для вашей версии xPDO: у проектов на MODX 3.x структура и способы подключения пакетов могут отличаться.
Четыре ошибки, которые встречаются чаще всего
1. Таблица создана, но xPDO о ней не знает
SQL-запросы к таблице работают, а getObject() ничего не возвращает. Обычно в модели отсутствует карта объекта, пакет не зарегистрирован или при регистрации передан не тот путь. Проверьте, что директория модели содержит файлы, созданные для компонента, и что пакет подключается до первого обращения к его классу.
В MODX Revolution 2.8.x пакет обычно добавляют в контексте объекта MODX. Путь в примере нужно заменить на фактическую папку модели вашего компонента:
$packagePath = MODX_CORE_PATH . 'components/catalog/model/';
$modx->addPackage('catalog', $packagePath);
Имя пакета и расположение файлов должны соответствовать тому, как модель сгенерирована. Не копируйте пример в проект на MODX 3.x без сверки с документацией и устройством установленного компонента.
2. Не совпадают имена класса и таблицы
У xPDO имя PHP-класса — не обязательно имя таблицы. Связь задаётся картой объекта; её определяют при генерации модели из схемы. Если вы переименовали класс или таблицу только в одном месте, модель может загрузиться, но обращаться не туда, либо не загрузиться вовсе.
Сверьте три значения: имя класса в коде, имя объекта в карте и таблицу, к которой эта карта привязана. Отдельно проверьте префикс. Если схема предполагает один префикс, а таблица в базе создана с другим, запрос xPDO будет искать другое имя.
3. В схеме и базе расходятся поля
Частый источник ошибок — столбец добавили вручную в базе, но не обновили схему и модель. В результате SQL видит поле, а объектная модель о нём не знает. Бывает и наоборот: схема ожидает столбец, которого ещё нет в таблице. Сверьте типы, nullable-ограничения, значения по умолчанию и первичный ключ в обоих местах.
Особенно внимательно проверьте первичный ключ и обязательные поля. Если модель ожидает уникальный идентификатор, но в таблице его нет или он не уникален, выборка и сохранение могут вести себя непредсказуемо. Не исправляйте такую проблему только ручным изменением таблицы: затем обновите схему компонента и пересоздайте модель по принятому в проекте процессу.
4. Запись не сохраняется, а ошибка теряется
Вызов save() сам по себе не доказывает, что данные записались. Проверьте его результат, затем посмотрите журнал ошибок MODX и выполните проверочный запрос к базе. Если объект новый, убедитесь, что заданы обязательные поля; если существующий — что вы загрузили именно нужную запись.
Минимальная проверка для модели, которая уже подключена и содержит класс CatalogItem:
$item = $modx->getObject('CatalogItem', ['sku' => $sku]);
if (!$item) {
$item = $modx->newObject('CatalogItem');
$item->set('sku', $sku);
}
$item->set('title', $title);
$saved = $item->save();
if (!$saved) {
$modx->log(modX::LOG_LEVEL_ERROR, 'Не удалось сохранить CatalogItem');
}
Это фрагмент для MODX Revolution 2.8.x с уже подключённой моделью, а не самостоятельный файл. Имена класса и полей замените на те, что описаны в вашей схеме. Не выводите в публичный ответ сайта подробности внутренней ошибки: оставьте их в журнале.
Как диагностировать проблему по симптомам
| Симптом | Что проверить первым | Следующая проверка |
|---|---|---|
| Класс не найден | Регистрацию пакета и путь к модели | Имя класса и наличие карты объекта |
| Объект не находится | Название класса и условия выборки | Имя таблицы, префикс и наличие строки в базе |
| Поле не читается или не сохраняется | Имя поля в схеме и карте | Фактическую структуру таблицы и журнал ошибок |
| Сохранение не даёт ожидаемой записи | Результат save() и обязательные поля | Транзакцию, ограничения базы и итоговую строку в таблице |
Когда выбирать xPDO, а когда обычный SQL
Для таблицы компонента xPDO удобен, если вы хотите работать с объектами, отношениями и общей моделью проекта. Но это добавляет обязанности: поддерживать схему, карту и регистрацию пакета в согласованном состоянии. Для разового сложного отчёта может быть проще запросить данные напрямую через доступный в проекте механизм работы с базой, если вы уверены в параметризации и безопасности запроса. Не смешивайте подходы для одной операции без причины: иначе часть логики окажется в модели, а часть — в SQL, и их будет труднее сопровождать.
Если xPDO «не видит» таблицу, проверяйте не только базу. Важна вся цепочка: имя класса, карта объекта, пакет и префикс.
Граничные случаи: где быстрый фикс ломается
- Рабочая копия и продакшен отличаются. Сравните реальные структуры таблиц в обеих базах: миграция могла примениться только в одном окружении.
- Изменили схему, но оставили старую модель. Перегенерируйте модель по процедуре проекта и проверьте изменения в системе контроля версий.
- Название класса совпадает с другим классом. Проверьте, какие пакеты подключены и нет ли конфликта имён в проекте.
- Поле допустимо пустое в одном месте, но обязательно в другом. Сверьте ограничения базы, карту и данные, которые передаёт код.
Не запускайте генерацию модели или обновление схемы на рабочей базе без резервной копии и понятного плана отката. Сначала проверьте результат на тестовом окружении: некоторые операции меняют структуру таблиц и данные.
Термин. Карта объекта — описание, по которому xPDO связывает PHP-класс с таблицей, её полями и отношениями. Без неё наличие таблицы в базе ещё не означает, что xPDO сможет работать с ней как с объектом.
Что делать дальше
Возьмите одну проблемную таблицу и пройдите цепочку последовательно: сравните схему с базой, проверьте класс и карту, подтвердите путь и регистрацию пакета, затем выполните одну тестовую выборку и сохранение. Зафиксируйте результат в журнале и повторите проверку на тестовом окружении после обновления модели. Если проект работает на MODX 3.x или использует другую версию xPDO, сверяйте подключение пакетов и генерацию модели с документацией этой версии — не переносите настройки из примера механически.
IT-архитектор / SQL-оптимизатор: Поиск N+1, оптимизация запросов, code review, поиск багов.
Спросить за 20 ₽Источники: Документация MODX: xPDO, Репозиторий xPDO на GitHub
Частые вопросы
Почему xPDO не видит таблицу, хотя она есть в базе?
Можно ли добавить поле прямо в базе?
Почему save() не добавляет запись?
Подойдёт ли этот пример для MODX 3.x?
Можно ли использовать xPDO для любой кастомной таблицы?
Что делать, если класс модели не найден после установки компонента?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.