pdoTools
pdoTools — основной класс компонента pdoTools.

Оглавление
pdoTools — основной класс компонента, который наследуют все остальные (кроме pdoParser — он наследует modParser).
Инициализация
Простая инициализация класса:
$pdoTools = $modx->getService('pdoTools');
Этот метод всегда вернёт оригинальный pdoTools.
Вы можете указать другой путь к классу в системных настройках, чтобы его подменить и расшить, тогда инициализировать лучше так:
$fqn = $modx->getOption('pdoTools.class', null, 'pdotools.pdotools', true);
if ($pdoClass = $modx->loadClass($fqn, '', false, true)) {
$pdoTools = new $pdoClass($modx, $scriptProperties);
}
elseif ($pdoClass = $modx->loadClass($fqn, MODX_CORE_PATH . 'components/pdotools/model/', false, true)) {
$pdoTools = new $pdoClass($modx, $scriptProperties);
}
else {
$modx->log(modX::LOG_LEVEL_ERROR, 'Could not load pdoTools from "MODX_CORE_PATH/components/pdotools/model/".');
return false;
}
$pdoTools->addTime('pdoTools loaded');
Такое способ инициализации используется во всех сниппетах pdoTools, так что вы можете изменить их функциональность своей версией pdoTools.
Ведение лога
Важная особенность pdoTools — он умеете вести лог того, что делает. Для этого вам доступны методы
- addTime (string $message) — добавляет новую запись в лог.
- getTime (bool $string [true]) — добавляет итоговое время и возвращает либо отформатированную строку (по умолчанию), либо массив время => сообщение.
Например, вот этот код:
$pdo = $modx->getService('pdoTools');
$pdo->addTime('pdoTools инициализирован');
print_r($pdo->getTime());
Выведет:
0.0000150: pdoTools инициализирован
0.0000272: Total time
1 572 864: Memory usage
То есть, вы можете подключать pdoTools в своих сниппетах, просто для логирования событий. Понятно дело, что его сниппеты сами всё пишут в лог, и как правило, менеджер может его почитать параметром &showLog=`1`
.
Кэширование
pdoTools умеет кэшировать произвольные данные на время выполнения скрипта. Вы тоже можете этим пользоваться.
- setStore (string $name, mixed $object, string $type [«data"]) — добавляет любые данные во временное хранилище.
- getStore (string $name, string $type [«data"]) — получает или данные, или null.
Например, вам по ходу работы сниппета нужно закэшировать имена юзеров, чтобы не выбирать их каждый раз. Тогда вы можете проверить, есть ли нужный юзер в кэше, и если нет — получить его:
foreach ($users as $id) {
$user = $pdo->getStore($id, 'user');
if ($user === null) {
if (!$user = $modx->getObject('modUser', $id)) {
$user = false;
}
$pdo->setStore($id, $user, 'user');
}
elseif ($user === false) {
echo 'Не могу найти юзера с id = ' . $id;
}
else {
echo $user->get('username');
}
}
В этом коде мы сохраняем юзеров в отдельный namespace user
, чтобы не мешать другим сниппетам, и проверяем наличие юзера в кэше. Обратите внимание, что по условиям примера, кэш может вернуть или null
(юзер еще не получался), или false
(юзер не найден). В любом случае, запрос в БД будет только один на каждого юзера.
Сам pdoTools кэширует таким образом вызовы чанков. Данные сохраняются только на время работы скрипта, то есть, они не пишутся на жесткий диск.
Есть и более продвинутое кэширование, методами MODx:
- setCache (mixed $data, array $options) — сохраняет данные $data в кэш, генерируя ключ из
$options
. - getCache (array $options) — выдает данные, согласно
$options
.
Здесь данные уже сохраняются на диск, время кэширования можно передавать в массиве параметров:
$pdo = $modx->getService('pdoTools');
$options = array(
'user' => $modx->user->get('id'),
'page' => @$_REQUEST['page'],
'cacheTime' => 10,
);
$pdo->addTime('pdoTools загружен');
if (!$data = $pdo->getCache($options)) {
$pdo->addTime('Кэш не найден, генерируем данные');
$data = array();
for ($i = 1; $i <= 100000; $i ++) {
$data[] = rand();
}
$data = md5(implode($data));
$pdo->setCache($data, $options);
$pdo->addTime('Данные сохранены в кэш');
}
else {
$pdo->addTime('Данные загружены из кэша');
}
print_r($data);
Таким образом, в зависимости от юзера и страницы будут получены какие-то данные и сохранены в кэш. Если зайдёт другой юзер — он получит свой кэш.
В первый раз наш код покажет примерно такое
0.0000281: pdoTools загружен
0.0004001: No cached data for key "default/e713939a1827e7934ff0242361c06b4b10c53d97"
0.0000079: Кэш не найден, генерируем данные
0.0581820: Saved data to cache "default/e713939a1827e7934ff0242361c06b4b10c53d97"
0.0000181: Данные сохранены в кэш
0.0586412: Total time
1 835 008: Memory usage
А затем вот такое:
0.0000310: pdoTools загружен
0.0007479: Retrieved data from cache "default/e713939a1827e7934ff0242361c06b4b10c53d97"
0.0000081: Данные загружены из кэша
0.0007918: Total time
1 572 864: Memory usage
Как видите, pdoTools и сам прекрасно пишет работу с кэшем в лог, так что вам можно это не логировать.
Утилиты
Здесь всего два метода.
makePlaceholders
makePlaceholders (array $data, string $plPrefix, string $prefix ['[[+'], string $suffix [']]'], bool $uncacheable [true]) — Принимает массив ключ => значение и возвращает два массива плейсхолдеры => значения, используется для шаблонизации.
Первый параметр — массив данных, затем можно указать префикс для плейсхолдеров, открывающие и закрывающие символы, а также отключить генерацию некэшированных плейсхолдеров.
$data = array(
'key1' => 'value1',
'key2' => 'value2',
);
$pls = $pdo->makePlaceholders($data);
print_r($pls);
Результат:
Array
(
[pl] => Array
(
[key1] => [[+key1]]
[!key1] => [[!+key1]]
[key2] => [[+key2]]
[!key2] => [[!+key2]]
)
[vl] => Array
(
[key1] => value1
[!key1] => value1
[key2] => value2
[!key2] => value2
)
)
Дальше можно обработать какой-то html шаблон вот так:
$html = str_replace($pls['pl'], $pls['vl'], $html);
buildTree
buildTree (array $resources) — строит иерархическое дерево из массива ресурсов, используется pdoMenu.
$pdo = $modx->getService('pdoFetch');
$resources = $pdo->getCollection('modResource');
$tree = $pdo->buildTree($resources);
print_r($tree);
И вы увидите дерево ресурсов своего сайта. Обратите внимание, что для использования getCollection()
нужно загружать pdoFetch.
Шаблонизация (работа с чанками)
Это, наверное, самая интересная часть класса pdoTools.
Метод здесь всего один — это getChunk()
, однако вся его реализация рассчитана на максимальную производительность и функциональность.
Все плейсхолдеры в чанки, какие только может, обрабатывает pdoParser. Условие одно — плейсхолдер должен быть без условий и фильтров. То есть:
[[%tag]]
— строка лексикона.[[~id]]
— ссылка.[[+tag]]
— обычные плейсхолдеры.[[++tag]]
— системные плейсхолдеры.[[*tag]]
— плейсхолдеры ресурса.
Еще getChunk в pdoTools умеет работать с разными типами чанков:
- @INLINE, @CODE — чанк создаётся из полученной строки.
- @FILE — чанк получается из файла. Для исключения инъекций, файлы могут быть только с расширением html и tpl, а директория для их выборки задаётся системной настройкой pdotools_elements_path.
- @TEMPLATE — чанк создаётся из шаблона сайта, можно указывать его id или имя.
- @CHUNK или просто строка, без @префикса — выборка обычного чанка из БД.
Рабочий пример:
$tpl = '@INLINE <p>[[+param]] - [[+value]]</p>';
$res = '';
for ($i = 1; $i <= 10000; $i++) {
$pls = array('param' =>$i, 'value' => rand());
$res .= $pdo->getChunk($tpl, $pls);
}
print_r($pdo->getTime());
print_r($res);
Вот вам и простейшая шаблонизация при помощи pdoTools.
Этот код выводит 10 .000 строк всего за 0.17 секунды! Причем, неважно, что чанк @INLINE, обычный работает с той же скоростью. А если заменить $pdo->getChunk()
на $modx->getChunk()
, то выходит уже 8 секунд!
То есть, в данном конкретном примере парсинг чанков MODx медленнее pdoTools в 3000 раз — 8 секунд, против 0.17. Это говорит о том, что нужно максимально упрощать свои чанки, поменьше использовать условий и подключать pdoTools.
Чем же можно заменить условия? Самые простые «пусто\не пусто» заменяются «быстрыми плейсхолдерами». Работает это так:
- В чанке должен быть какой-то тег, например
[[+tag]]
. - В чанке должен быть специальный html комментарий в таком виде:
<!--pdotools_tag значение, если тег не пуст-->
<!--pdotools_!tag значение, если тег пуст, появилось только в версии 1.9.3-->
Как видите, комментарий именуется исходя из префикса pdotools_ и имени тега. Префикс меняется параметром &nestedChunkPrefix=``
.
Почему именно такие условия, зачем держать быстрый плейсхолдер в комментарии? Очень просто — это на случай обработки чанка не pdoTools.
Пример:
$tpl = '@INLINE
<p>[[+tag]]</p>
<!--pdotools_tag [[+tag]] - значение, если тег не пуст-->
<!--pdotools_!tag значение, если тег пуст, появилось только в версии 1.9.3, выпущенной сегодня-->
';
$pls = array('tag' => 1);
echo $pdo->getChunk($tpl, $pls);
$pls = array('tag' => 0);
echo $pdo->getChunk($tpl, $pls);
Получаем
1 - значение, если тег не пуст
значение, если тег пуст, появилось только в версии 1.9.3
Как видите, внутрь быстрого плейсхолдера можно вставлять и другие плейсхолдеры, и его оригинальное значение. Конечно, это небольшой функционал, по сравнению с фильтрами MODx, но зато очень быстро.
Есть еще один интересный параметр обработки плейсхолдеров — &fastMode. Он выключает передачу плейсхолдеров в родной парсер MODx, и то, что не смог обработать pdoParser просто будет вырезано.
В последних версиях pdoTools его использовать нет нужды, потому что если pdoParser всё обработал, и в чанке не осталось ни одного [[+tag]]
, то он сразу отдаёт результат, не трогая modParser. Но вы можете его включить как принудительное требование для тех людей, которые меняют чанки — чтобы они не могли использовать трехэтажные конструкции.
С версии 2.0 pdoTools включает в свой состав шаблонизатор Fenom, что позволяет отказаться от тегов MODx и писать в чанках более продвинутую логику. Про работу с Fenom читайте в разделе pdoParser.
Время запросов: 0,1069 s
Количество запросов: 24
Источник: cache