Расширение объекта modResource

Представьте себе удивительное увеличение скорости через расширение объекта modResource в MODX
В предыдущей статье Боб Рей рассказывал о расширении объекта modUser. В этой статье пойдёт речь о том же для modResource объекта. Возможно вы уже читали статьи Эверетта о том, как расширить modResource объект. Но чего не было в его статьях — это «зачем» вам нужно расширять modResource.

Зачем?

Первый вопрос, который у вас возникнет при расширении modResource это «зачем мне нужно это делать, если уже есть переменные шаблона?»

Переменные шаблона (ТВ) — отлично подходят для хранения данных связанных с ресурсами и удобно использовать значения по-умолчанию или наследуемые значения. В коммерческом сайте, например, вы можете для каждого товара указать свой размер, вес и цвет и сохранять эти значения в ТВ.

Что же происходит, когда вам нужно найти ресурсы базируясь на значении их ТВ? Предположим, вам нужно найти товар с красным цветом. Ресурсы содержаться в одной таблице, значения ТВ находятся в другой таблице и значения по-умолчанию для ТВ находятся в третьей таблице. Вы можете сделать здоровенный запрос к этим троим таблицам, если умеете, но это не даст вам наследуемые значения или значения по-умолчанию.

Самой сложной проблемой является то, что для любой ТВ, которая имеет наследуемое значение или значение по-умолчанию, действительное значение не находиться в modTemplateVarResource, но вам нужно проверить это. Тогда вам нужно получить ТВ объект, обычно отдельным запросом и спарсить его значение. Если значение наследуемо, то MODX должен пройти по дереву ресурсов пока не найдёт ресурс, где установлена ТВ и если он его не найдёт, то он должен вернуться к ТВ объекту за значением по-умолчанию. Не забываем, что потенциально это должно быть сделано для каждой ТВ каждого получаемого ресурса. Дополнительно, ещё вопрос может быть в том, что получать сырые значения или отрендеренные (ещё один шаг, для каждой ТВ). Все эти шаги требуют отдельного запроса к базе (и могут возникнуть проблемы с сервером, особенно если это шаред сервер).

Ещё одна проблема — это сортировка. Нет быстрого способа посортировать значения ТВ, потому что они находяться в двух разных таблицах и вам нужно проверить каждую, чтобы понять нужно ли вам обращаться ко второй таблице. Сортировка должна быть сделана после проверки их всех.

Вы могли бы получить значения ТВ для всех ресурсов сайта и пройти сквозь них проверяя цвет, но это будет слишком медленно и неэфективно. Вы можете получить каждый ресурс сайтаа и проверить соответствующую ТВ для каждого, но это будет также медленно, если ещё и не хуже. Также вы можете использовать getResources с tvFilters, но это будет ещё медленнее и наименее эффективно. Один пользователь сказал, что выдача одной страницы с несколькими getResources и 10тью ТВ — генерирует больше 240 запросов к базе! Все эти методы включают много кода и много запросов. Как же просто (и несомненно быстрее) было бы всё, если бы можно было просто написать так:

$resourceDataObjects = $modx->getCollection('resourceData', array('color' => 'red'));

foreach($resourceDataObjects as $dataObject) {
    $resource = $dataObject->getOne('Resource');
    /* Делаем тут что-то с ресурсом */
}

Код сверху будет намного эфективнее, чем прохождение через все ресурсы сайта так как запрос будет возвращать только ресурсы с товаром с красным цветом. Мы можем улучшить его существенно, получив все эти ресурсы со всеми дополнительными полями, посортированными по любому полю, одним запросом getCollectionGraph(). В этом примере, посортируем ресурсы по полю pagetitle:

$c = $modx->newQuery('modResource');
$c->sortby('pagetitle', 'ASC');
$c->where(
   array('resourceData.color' => 'red'),
);
$resources = $modx->getCollectionGraph('modResource', '{"resourceData":{}}', $c);

После запуска вышеприведенного кода переменная $resources будет содержать массив всех ресурсов со значением ‘red’ в поле цвета. Поиск будет просто мгновенным, если сравнивать с другими методами, описанными выше, так как происходит только один запрос к базе данных, особенно если на сайте много ресурсов.

Что?

Что значит расширить объект modResource? Вы можете думать об этом как о добавлении эквивалента «User Profile» для каждого ресурса. Прямо как профиль пользователя содержит поля, которые расширяют объект modUser, то связанный объект для нашего modResource содержит поля, которые расширяют исходный объект ресурсов. Если вы используете параметры по умолчанию у ClassExtender’а для расширения объекта modResource, то алиас связанного объекта будет «Data».
С объектом modUser, мы получаем профиль пользователя с помощью кода:

$profile = $user->getOne('Profile');

Для нашего расширенного объекта modResource, аналогичный код будет выглядеть так:

$data = $resource->getOne('Data');

После того, как вы получили объект $data, то вы можете получить любое из его полей используя метод get() совсем как у любого другого объекта MODX:

$data = $resource->getOne('Data');
$color = $data->get('color');

Так как объект $data — это xPDO объект, то вы также можете получить все поля в массив и отдать значения в Tpl чанк с помощью нескольких строк кода:

foreach($resources as $resource) {
    $data = $resource->getOne('Data');
    $output .= $modx->getChunk('productTpl', $data->toArray());
}

Вы можете гадать почему мы оставили в стороне шаг загрузки класса или пакета. ClassExtender опционально регистрирует пакет в Системной настройке extension_packages. Это значит, что пакет (и все его классы) будут автоматически загружены при каждом запросе к сайту. Это значит, что расширенный класс будет доступен на любой странице (включая страницы Менеджера).

Как?

Один способ расширения modResource описан здесь. Он довольно-таки сложен и включает создание схемы, класса, меп-файлов, контроллеров и кучу других шагов.
С помощью ClassExtender теперь есть путь намного проще. Установите ClassExtender и отредактируйте пример схемы для ваших требований (или создайте пользовательскую таблицу базы данны для ваших допольнительных полей). Далее просмотрите «Extend modResource» ресурс и используйте форму, чтобы сделать всё необходимое. Также вам нужно обновить чанк, используемый для ваших дополнительных полей на панели ресурса Create/Edit и возможно вам будет нужно поменять плагин, который выводит и сохраняет поля, но это намного проще способ, чем описанный выше. Скорость работы увеличится значительно.
Смотрите документацию по ClassExtender для более подробных деталей.

Оригинал статьи — Why Extend modResource?

Дополнительно для прочтения: