📘 Конструктор запросов
query() отдаёт конструктор запросов Illuminate к базе MODX. Это тот же конструктор, что в Laravel, поэтому весь его словарь применим — здесь описано только то, что специфично для PageBlocks.
Имя таблицы — без префикса
Префикс уже знает соединение, поэтому таблица пишется голым именем:
query('site_content') // → modx_site_content
query('pb_block_data') // → modx_pb_block_dataЕсли передать modx_site_content, получится modx_modx_site_content и ошибка «таблица не существует».
Без аргументов query() возвращает само соединение — это нужно для сырых запросов и транзакций:
query()->statement('SET SESSION group_concat_max_len = 100000');
query()->transaction(function () { /* ... */ });Что возвращается
get() отдаёт PbCollection из обычных объектов stdClass. Поля читаются свойствами, а не через геттер:
{foreach query('site_content')->where('template', 4)->orderBy('menuindex')->get() as $page}
<a href="{$page->uri}">{$page->pagetitle}</a>
{/foreach}Это главное практическое отличие от xPDO: $page->get('uri') нет, и поведения модели у строки тоже нет. Если нужна модель — со связями, кастами и скоупами — берите model().
JSON-колонки
PageBlocks много чего хранит в JSON-колонках (data, properties, sync_fields). Сырой конструктор отдаёт их строками. withJsonColumns() разворачивает их за вас:
$rows = query('pb_block_data')
->withJsonColumns(['data'])
->where('model_id', 1)
->get();
// $rows->first()->data - массив, а не строка JSONПовседневные методы
Всё это стандартный конструктор; примеры ниже прогнаны на живом сайте.
Чтение
query('site_content')->get(); // PbCollection строк
query('site_content')->first(); // одна строка или null
query('site_content')->find(1); // по первичному ключу
query('site_content')->where('id', 1)->value('pagetitle'); // одно поле
query('site_content')->pluck('pagetitle'); // плоский список одной колонки
query('site_content')->inRandomOrder()->first(); // случайная строкаПодсчёт и агрегаты
query('site_content')->count();
query('site_content')->max('id');
query('site_content')->min('id');
query('site_content')->avg('id');
query('site_content')->sum('id');
query('site_content')->where('id', 1)->exists();Фильтрация
query('site_content')
->where('template', 4)
->whereIn('id', [1, 2, 3])
->whereNotNull('publishedon')
->orderBy('menuindex')
->limit(10)
->get();Соединения
query('site_content')
->leftJoin('users', 'site_content.createdby', '=', 'users.id')
->select('site_content.*', 'users.username')
->get();Работают join, leftJoin, rightJoin и joinSub. Присоединяемая таблица тоже пишется без префикса.
Объединения
query('site_content')->where('template', 4)
->union(query('site_content')->where('template', 5))
->get();Как посмотреть запрос
toSql() показывает SQL с плейсхолдерами, getBindings() — значения:
$q = query('site_content')->where('template', 4);
$q->toSql(); // select * from `modx_site_content` where `template` = ?
$q->getBindings(); // [4]