Хочу представить вашему вниманию свою разработку по быстрому выводу контента на сайтах MODX Revolution.
Как известно, эта система целиком построена на собственной ORM под названием xPDO. Она очень упрощает работу, позволяет писать один универсальный код для разных БД, и еще много чего.
К сожалению, она не может похвастаться скоростью вывода (как, наверное, вообще любая ORM), поэтому я попробовал совместить её плюсы с обычным PDO, добавить лучшую работу с чанками и сделать удобную библиотеку для MODX.
Основные особенности:
- Быстрая работа с БД. Все запросы составляются на xPDO, а выбираются без объектов — на PDO.
- Предварительная обработка простых плейсхолдеров в чанках. Парсер MODX разбирается только со сложными вызовами.
- Код чанков можно указывать прямо при вызове сниппета, загружать обычным образом или из статичных файлов.
- Правильная сортировка, подготовка, обработка и вывод ТВ параметров.
- Ведение подробного журнала работы сниппета с отметками времени, для отладки.
- Удобная загрузка классов и множество функций, которые можно применять в своих разработках.
- В комплекте 8 универсальных сниппетов, которые дают хороший базис разработчику.
Начну с последнего пункта.
8 универсальных сниппетов
Изначально pdoTools был придуман как библиотека для работы других компонентов, например его использует Tickets.
Со временем стало очевидно, что он позволяет с минимальными затратами написать неплохой пакет инструментов, способных заменить стандартные сниппеты MODX.
pdoResources
Сниппет для выборки ресурсов, может заменить getResources. Он поддерживает почти все его возможности, и бладает особенностями:
— подключение других таблиц через разные JOIN
— можно указывать, что именно выбирать из колонок таблиц
— гибкие условия выборки, вплоть до указания чистого SQL
При этом сниппет работает раз в 5 — 10 быстрее.
pdoMenu
Сниппет для генерации меню сайта. Может заменить Wayfinder, поддерживает почти все его параметры и чанки.
Работает быстрее, особенно при первом запуске с холодным кэшем.
pdoPage
Замена для getPage. Генерирует гораздо более правильную пагинацию, и не позволяет пихать некорректные запросы в параметры запроса page и limit.
pdoUsers
Сниппет, который выводит пользовтаелей сайта, умеет фильтровать их по группам и ролям.
pdoCrumbs
Быстрая генерация хлебных крошек, заменяет BreadCrumb.
pdoNeighbors
Вывод соседних документов страниц. То есть: следующий, предыдущий и родитель. Очень удобно использовать для навигации по новостям.
pdoField
Сниппет, получающий любое поле ресурса или его родителя, включая ТВ параметр. Заменяет getResourcesField и UltimateParent.
Умеет выводить «значение по умолчанию».
pdoSitemap
Генерация карты сайта. Очень быстрая замена GoogleSiteMap, разница до 12 раз.
Я специально привел краткое описание сниппетов в начале поста, потому что большинству начинающих пользователей этого будет вполне достаточно, чтобы быстро и комфортно работать в MODX Revoltuion.
На самом деле, при замене стандартных сниппетов аналогами из pdoTools, средний сайт начинает бегать быстрее раза в 2-3. Вы можете заглянуть на страницу документации и подробнее ознакомиться с параметрами и примерами сниппетов здесь.
Прелесть моего дополнения в том, что оно не требует никаких особых манипуляций. Вы просто устанавливаете его из репозитория и можно пользоваться. Если что-то не устраивает, глючит, работает не так, как вы ожидали — старые родные сниппеты по-прежнему с вами, можно использовать их.
А теперь я расскажу, за счет чего pdoTools быстро работает.
Выборка из БД
Для каждой таблицы в MODX существует описание в .map файле. Из коробки система поддерживает 2 базы данных: MySQL и MSSQL, поэтому все запросы в pdoTools генерируются через xPDO.
Начало всегда одинаково:
$q = $modx->newQuery('modResource');
$q->select(array('id', 'pagetitle', 'content'));
$q->sortby('id', 'asc');
$q->limit(10);
А вот дальше мы можем выбрать или объекты:
$resources = $modx->getCollection('modResource', $q);
foreach ($resources as $resource) {
print_r($resource->toArray());
}
Или массивы:
if ($q->prepare() && $q->stmt->execute()) {
$resources = $q->stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($resources as $resource) {
print_r($resource);
}
}
Классический путь MODX Revolution, который используется в компонентах его авторов — выборка через xPDO и дальнейшая работа с объектами. Это удобно, конечно — ведь в модели можно прописать разные преобразования для полей объектов, и проверки.
Но это и очень медленно, к сожалению. Поэтому я использую второй путь — выборку через PDO. Это быстрее в несколько раз.
Грамотная работа с чанками
Чанки, если кто не знает — это такие элементы в дереве MODX, которые содержат только HTML. Они нужны для оформления работы PHP скриптов и отделяют логику от представления в системе.
Вот обычный чанк:
<p>[[+idx]]. <a href="/[[+uri]]">[[+pagetitle]]</a></p>
В чанках могут быть специальные команды для парсера, например:
<p>[[+idx]]. <a href="/[[+uri]]">[[+menutitle:isempty=`[[+pagetitle]]`]]</a></p>
Каждый тег [[+key]] — это будущий объект в парсере MODX. К нему можно указывать разные параметры, фильтры и вообще, программировать таким образом.
Это столько же круто, сколь и медленно.
Поэтому в pdoTools чанки предварительно обрабатываются — всё что можно, заменяется банальным str_replace() из полученнных данных, затем заменяются ссылки [[~[[+id]]]], затем плейсхолдеры лексиконов [[%key]], в вот все, что осталось (10% от изначальной работы) отправляется в парсер MODX.
Конечный результат никак не отличается, но скорость такой обработки в разы выше стандартной.
Пользоваться этим очень просто:
$pdo = $modx->getService('pdoTools');
return $pdo->getChunk('имячанка', array('массив со значениями для подстановки'));
В отиличии от оригинального modX::getChunk(), в pdoTools::getChunk() мы можем пользоваться не только уже подготовленными чанками, но и сразу указывать их с помощью биндинга INLINE:
$pdo = $modx->getService('pdoTools');
$tpl = '@INLINE <p>[[+idx]]. <a href="/[[+uri]]">[[+pagetitle]]</a></p>';
$array = array(
'idx' => 1,
'pagetitle' => 'Имя страницы',
'url' => '/page.html'
);
return $pdo->getChunk($tpl, $array);
Работа с ТВ
pdoTools и его сниппеты стараются уложить всю работу в 1 запрос к базе данных. Поэтому все указанные ТВ параметры присоединяются через LEFT JOIN.
Становится очень удобно фильтровать по ТВ, ведь можно просто указать:
[[!pdoResources?
&parents=`2`
&includeTVs=`myTV`
&where=`{"myTV:>":10}`
]]
И вы получите все ресурсы, из контейнера с id = 2 и значением ТВ myTV больше 10. Можно указывать довольно сложные условия и выборки, поэтому я сделал систему логирования:
Лог работы библиотеки
Почти все сниппеты понимают параметр &shoLog=`1` и выводят менеджеру такую портянку:
По ней очень удобно строить условия и отлаживать запросы в БД.
Использование библиотеки
Библиотека подключается через modX::getService() вот так:
// Если нам нужны только основные функции
$pdo = $modx->getService('pdoTools');
// Если нам нужна работа с БД
$pdo = $modx->getService('pdoFetch');
Первый позволяет быстро работать с чанками:
$pdo->getChunk();
$pdo->parseChunk();
А второй умеет быстро выбирать ресурсы:
$pdo->getObject('modResource', 1);
$pdo->getCollection('modTemplate', array('id:>=' => 2));
Если их скомбинировать, то вот так будет выглядеть весь ваш сайт:
<?php
// Подключем класс
$pdo = $modx->getService('pdoFetch');
// Указываем шаблон
$tpl = '@INLINE <p><a href="/[[+id]]">[[+pagetitle]]</a></p>';
// Выбираем все ресурсы сайта
$resources = $pdo->getCollection('modResource');
$output = '';
foreach ($resources as $resource) {
// Оформляем
$output .= $pdo->getChunk($tpl, $resource);
}
// И добавляем лог
$output .= '<pre>'.$pdo->getTime().'</pre>';
return $output;
Как вам вывод 2012 страниц сайта за полсекунды?
Заключение
Это очень краткая информация о возможностях pdoTools.
Компонент разрабатывается уже почти год и обладает широчайшими возможностями. Честно говоря, трудно описать все, что он умеет, но я стараюсь.
Ссылка на документацию.
Ссылка на репозиторий.
Свежие версии в репозитории Simple Dream.
Стабильные версии в официальном репозитории.
Потестировать без заморочек можно на modx-test.com.
Автор: bezumkin