Классы pdoTools — полное руководство по работе с pdoTools, pdoFetch и pdoParser

Классы pdoTools Дополнения

Библиотека pdoTools включает три основных класса для работы с базой данных и шаблонизацией в MODX Revolution. Каждый класс решает свои задачи, но все они объединены общей идеей — максимальная производительность и удобство разработки.

Содержание
  1. pdoTools — основной класс библиотеки
  2. Инициализация класса
  3. Ведение лога работы
  4. Временное кеширование данных
  5. Постоянное кеширование через MODX
  6. Утилиты для работы с данными
  7. Метод makePlaceholders
  8. Метод buildTree
  9. Работа с чанками и шаблонизация
  10. Типы чанков
  11. Обработка плейсхолдеров
  12. Производительность шаблонизации
  13. Быстрые плейсхолдеры
  14. Быстрый режим обработки
  15. pdoFetch — класс для работы с базой данных
  16. Инициализация pdoFetch
  17. Создание запроса — метод makeQuery
  18. Работа с TV-параметрами
  19. Метод addTVFilters
  20. Метод addTVs
  21. JOIN операции — метод addJoins
  22. Типы присоединения таблиц
  23. Пример присоединения таблиц в PHP
  24. Пример в сниппете через JSON
  25. Группировка — метод addGrouping
  26. Выбор полей — метод addSelects
  27. Условия выборки — метод addWhere
  28. Фильтрация по TV-параметрам
  29. Чистый SQL в условиях
  30. Сортировка — метод addSort
  31. Выполнение запроса и возврат результатов
  32. Обработка результатов
  33. Методы getArray и getCollection
  34. pdoParser — быстрый парсер тегов MODX
  35. Обработка простых плейсхолдеров
  36. Теги FastField
  37. Шаблонизатор Fenom
  38. Возможности Fenom
  39. Системные настройки Fenom
  40. Порядок запуска шаблонизатора
  41. Кеширование чанков Fenom
  42. Пример использования Fenom
  43. Заключение

pdoTools — основной класс библиотеки

Базовый класс компонента, который наследуют все остальные сниппеты (кроме pdoParser, который расширяет modParser). Класс pdoTools предоставляет инструменты для логирования, кеширования и работы с чанками.

Инициализация класса

Простейший способ получить экземпляр pdoTools:

$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');
    return false;
}

$pdoTools->addTime('pdoTools loaded');

Такой способ инициализации используется во всех сниппетах 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 в своих сниппетах просто для логирования событий. Сниппеты 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) — сохраняет данные в кеш, генерируя ключ из параметров.
  • getCache(array $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/e713939a1827..."
0.0000079: Кэш не найден, генерируем данные
0.0581820: Saved data to cache "default/e713939a1827..."
0.0000181: Данные сохранены в кэш
0.0586412: Total time
1 835 008: Memory usage

При последующих запросах:

0.0000310: pdoTools загружен
0.0007479: Retrieved data from cache "default/e713939a1827..."
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 — массив ключ => значение
  • $plPrefix — префикс для плейсхолдеров
  • $prefix — открывающие символы (по умолчанию [[+)
  • $suffix — закрывающие символы (по умолчанию ]])
  • $uncacheable — генерировать ли некешированные плейсхолдеры

Пример использования:

$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

Строит иерархическое дерево из массива ресурсов, используется сниппетом pdoMenu:

$pdo = $modx->getService('pdoFetch');
$resources = $pdo->getCollection('modResource');
$tree = $pdo->buildTree($resources);
print_r($tree);

Метод вернет структурированное дерево ресурсов вашего сайта.

Работа с чанками и шаблонизация

Это наиболее интересная часть класса pdoTools. Основной метод — getChunk(), вся реализация которого нацелена на максимальную производительность и функциональность.

Типы чанков

getChunk умеет работать с разными типами чанков:

  • @INLINE или @CODE — чанк создается из переданной строки
  • @FILE — чанк получается из файла (только с расширениями .html и .tpl из директории pdotools_elements_path)
  • @TEMPLATE — чанк создается из шаблона сайта (можно указывать ID или имя)
  • @CHUNK или просто строка без @ — выборка обычного чанка из БД

Обработка плейсхолдеров

Все простые плейсхолдеры без условий и фильтров обрабатывает pdoParser:

  • [[%tag]] — строка лексикона
  • [[~id]] — ссылка
  • [[+tag]] — обычные плейсхолдеры
  • [[++tag]] — системные плейсхолдеры
  • [[*tag]] — плейсхолдеры ресурса

Производительность шаблонизации

Рабочий пример с измерением скорости:

$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);

Этот код выводит 10 000 строк всего за 0.17 секунды ! Неважно, что чанк @INLINE — обычный работает с той же скоростью. Если заменить $pdo->getChunk() на $modx->getChunk(), то выйдет уже 8 секунд.

То есть, в данном конкретном примере парсинг чанков MODX медленнее pdoTools в 3000 раз. Это говорит о необходимости упрощать чанки, минимизировать условия и использовать pdoTools.

Быстрые плейсхолдеры

Самые простые условия «пусто/не пусто» заменяются «быстрыми плейсхолдерами». Работает это так:

  • В чанке должен быть тег, например [[+tag]]
  • В чанке должен быть специальный HTML комментарий:
    <!--pdotools_tag значение, если тег не пуст-->
    <!--pdotools_!tag значение, если тег пуст-->

Комментарий именуется исходя из префикса pdotools_ и имени тега. Префикс меняется параметром &nestedChunkPrefix.

Почему именно комментарии? На случай обработки чанка не pdoTools — тогда комментарий просто не отобразится.

Пример использования:

$tpl = '@INLINE
<p>[[+tag]]</p>
<!--pdotools_tag [[+tag]] - значение, если тег не пуст-->
<!--pdotools_!tag значение, если тег пуст-->';

$pls = array('tag' => 1);
echo $pdo->getChunk($tpl, $pls);

$pls = array('tag' => 0);
echo $pdo->getChunk($tpl, $pls);

Результат:

1 - значение, если тег не пуст
значение, если тег пуст

Внутрь быстрого плейсхолдера можно вставлять другие плейсхолдеры и его оригинальное значение. Функционал небольшой по сравнению с фильтрами MODX, но зато очень быстрый.

Быстрый режим обработки

Параметр &fastMode выключает передачу плейсхолдеров в родной парсер MODX. Всё что не смог обработать pdoParser будет просто вырезано.

В последних версиях pdoTools его использовать нет нужды, потому что если pdoParser всё обработал и в чанке не осталось ни одного [[+tag]], результат отдается сразу без запуска modParser.

pdoFetch — класс для работы с базой данных

Этот класс предназначен для работы с любыми таблицами базы данных, неважно какими — лишь бы у MODX был к ним доступ и модель. pdoFetch создает запрос через xPDO, а выполняет через PDO, что дает защиту, гибкость и скорость.

Инициализация pdoFetch

Объект запроса xPDOQuery создается методом makeQuery() исходя из переданных параметров. По умолчанию работает с modResource, но можно указать другой класс.

Важно учитывать, что метод modX::getService() всегда возвращает уже загруженный класс, если он есть. То есть, если вы (или какой-то сниппет) уже проинициализировали pdoFetch, то получите именно этот экземпляр с уже установленными параметрами запроса.

Чтобы гарантированно применить свои параметры используйте pdoFetch::setConfig():

$pdo = $modx->getService('pdoFetch');
$pdo->setConfig(array('class' => 'modUser'));

Метод setConfig может сразу загружать указанные модели компонентов:

$pdo->setConfig(array(
    'class' => 'msResourceFile',
    'loadModels' => 'ms2gallery'
));

pdoTools не знает какой класс принадлежит какому компоненту, поэтому нужно указать директорию дополнения в /core/components.

Создание запроса — метод makeQuery

Создает объект xPDOQuery и добавляет его в приватное свойство класса pdoFetch. Запрос создается для указанного класса или для modResource по умолчанию.

Основная цель pdoFetch — выбрать все данные за один запрос. Если выбираются TV-параметры к ресурсу, то запросов приходится делать несколько.

Работа с TV-параметрами

Метод addTVFilters

Преобразовывает параметр &tvFilters от getResources в понятные для pdoFetch параметры: where и includeTVs. Сам ничего особо не делает, только разбирает чужой формат запроса и передает дальше.

Если вы умеете пользоваться параметром where, то tvFilters вам не нужен.

Метод addTVs

Очень полезный метод — подключает TV-параметры, указанные списком в &includeTVs. Чем больше TV вы укажете, тем больше нужно будет сделать JOIN таблицы modTemplatevarContent. В принципе, это не особо влияет на скорость.

JOIN операции — метод addJoins

Этот метод получает параметры из конфига и отвечает за все подключения таблиц. Например, addTVs сам ничего не подключит, он только разбирает includeTVs и складывает параметры в leftJoin.

Типы присоединения таблиц

leftJoin — выбираются все записи первой (левой) таблицы, даже если они не соответствуют записям во второй (правой) таблице. Используется для присоединения к ресурсу TV-параметров, так как мы не знаем есть они или нет, а вот ресурс нужно выбрать всегда.

rightJoin — выбираются все записи второй (правой) таблицы, даже если они не соответствуют записям в первой (левой) таблице.

innerJoin — внутреннее объединение двух таблиц. Если для строки из одной таблицы нет соответствия в другой, такая строка исключается. innerJoin всегда возвращает данные сразу из двух таблиц.

Пример присоединения таблиц в PHP

Указание параметров для присоединения в pdoFetch:

$pdo->setConfig(array(
    'class' => 'modUser',
    'leftJoin' => array(
        'Profile' => array(
            'class' => 'modUserProfile',
            'on' => 'modUser.id = Profile.internalKey',
        )
    ),
    'select' => array(
        'modUser' => '*',
        'Profile' => 'fullname,email',
    )
));

Мы выбираем класс modUser, затем присоединяем к нему класс modUserProfile под псевдонимом Profile. Присоединение производим по колонке id у modUser и internalKey у modUserProfile. Затем указываем какие столбцы нужны: для modUser все, а для Profile только полное имя и email.

Пример в сниппете через JSON

При вызове сниппетов нельзя указывать массивы, поэтому параметры нужно превратить в JSON:

[[!pdoResources?
&class=`modUser`
&leftJoin=`{
  "Profile": {
    "class": "modUserProfile",
    "on": "modUser.id = Profile.internalKey"
  }
}`
&select=`{
  "modUser": "*",
  "Profile": "fullname,email"
}`
&showLog=`1`
&sortby=`modUser.id`
&sortdir=`ASC`
]]

Лог pdoTools покажет:

0.0000799: pdoTools loaded
0.0000319: xPDO query object created
0.0005212: leftJoined modUserProfile as Profile
0.0001311: Added selection of modUser: ...
0.0000789: Added selection of modUserProfile: fullname, email
0.0000360: Sorted by modUser.id, ASC
0.0019310: SQL executed
0.0001349: Total rows: 3

Группировка — метод addGrouping

Этот метод добавляет группировку в запрос. Нужен только если вы используете JOIN, и одной строке левой таблицы соответствует несколько строк правой.

Обычно группировка нужна для подсчета количества правых строк. Например, количество файлов для каждого ресурса:

[[!pdoResources?
&parents=`0`
&class=`modResource`
&loadModels=`ms2gallery`
&leftJoin=`{
  "Image": {
    "class": "msResourceFile",
    "on": "modResource.id = Image.resource_id AND Image.parent = 0"
  }
}`
&select=`{
  "modResource": "*",
  "Image": "COUNT(Image.id) as images"
}`
&groupby=`modResource.id`
&showLog=`1`
&sortby=`id`
]]

Без группировки по modResource.id получим ровно один результат, потому что MySQL решит, что мы считаем общее количество для всех строк. С группировкой счетчик работает для каждой строки modResource отдельно.

Выбор полей — метод addSelects

Правила выборки полей:

  • Если вы не делаете JOIN, то select можно указывать строкой: &select=`id,pagetitle,longtitle`
  • При использовании JOIN нужен массив JSON:
    &select=`{
      "modResource": "id,pagetitle,longtitle",
      "Image": "url"
    }`
  • Если используются псевдонимы в select, обязательно нужно указать псевдоним таблицы:
    &select=`{
      "modResource": "id,pagetitle",
      "Image": "Image.url as image"
    }`
  • Перечисление всех полей можно заменять звездочкой:
    &select=`{
      "modResource": "*",
      "Image": "Image.url as image"
    }`

Все ошибки JOIN, Select и Group смотрите в логе pdoTools.

Условия выборки — метод addWhere

Очень важный метод, который берет параметр &where, разбирает его и добавляет условия в запрос.

Задается массивом:

&where=`{"id:>": "15", "published:!=": "0"}`

Если подключены таблицы, можно фильтровать по ним:

&leftJoin=`{
  "Image": {
    "class": "msResourceFile",
    "on": "modResource.id = Image.resource_id AND Image.parent = 0"
  }
}`
&where=`{
  "published:!=": "0",
  "Image.active": "1"
}`

Если у полей таблицы могут быть одинаковые столбцы (обычно id), нужно указывать имя колонки с таблицей:

&where=`{
  "modResource.id:>": "15",
  "published:!=": "0",
  "Image.active": "1"
}`

Фильтрация по TV-параметрам

При фильтрации по подключенным TV псевдонимы обычно указывать не нужно за счет специального метода replaceTVCondition:

&includeTVs=`image,file,mytv`
&where=`{
  "image:LIKE": "%yandex.ru%",
  "OR:file:=": "1",
  "OR:text:!=": ""
}`

Если автозамена не сработает, фильтруйте вот так:

&includeTVs=`image,file,mytv`
&where=`{
  "TVimage.value:LIKE": "%yandex.ru%",
  "OR:TVfile.value:=": "1",
  "OR:TVtext.value:!=": ""
}`

TV присоединяются как TVимятв и фильтровать нужно по значению value.

Чистый SQL в условиях

Если не получается указать нужное условие массивом для xPDO, используйте массив с одной строкой чистого SQL:

&where=`["
TVimage LIKE '%yandex%' OR (TVfile.value = 1 AND TVtext.value != '')
"]`

Обратите внимание на квадратные скобки вместо фигурных. Такое SQL условие попадет в запрос без дополнительных обработок, поэтому смотрите лог на предмет ошибок.

Сортировка — метод addSort

Этот метод добавляет в запрос сортировку и умеет принимать как строку, так и массив. Для простой сортировки по одному полю нужно указать два параметра:

&sortby=`publishedon`
&sortdir=`ASC`

Если в запросе есть JOIN, лучше указывать с именем таблицы:

&sortby=`modResource.publishedon`
&sortdir=`ASC`

Для сортировки по нескольким полям указывайте массив поле => направление:

&sortby=`{
  "modResource.publishedon": "ASC",
  "modUser.id": "DESC"
}`

Выполнение запроса и возврат результатов

Запрос подготавливается методом prepareQuery и выполняется через PDO.

Параметр &return определяет что вернет метод run():

  • sql — строка с готовым SQL запросом, сам он не выполняется
  • ids — список с ID подходящих объектов через запятую (для передачи другому сниппету)
  • data — массив с результатами (при вызове через сниппет вы получите слово Array)
  • tpl — результат запроса, оформленный в указанный чанк &tpl

У сниппетов по умолчанию &return=tpl, а если есть параметр &returnIds, то ids.

Обработка результатов

После выполнения запроса метод run() вызывает prepareRows() — его цель прогнать результаты и подготовить для вывода.

Именно этот метод отвечает за раскодировку JSON полей и подготовку TV, если указаны &prepareTVs или &processTVs.

Также вызывается checkPermissions() — он проверяет разрешения, указанные в одноименном параметре. Учтите, что для проверки разрешений приходится создавать объекты xPDO, что замедляет работу:

&checkPermissions=`list,view`

Методы getArray и getCollection

Эти два метода нужны для быстрой замены родным методам MODX: getObject и getCollection. В отличие от них, они возвращают массивы, а не объекты.

Пример использования getArray:

$pdo = $modx->getService('pdoFetch');
$res = $pdo->getArray('modResource', 1);
print_r($res);

Пример использования getCollection:

$pdo = $modx->getService('pdoFetch');
$resources = $pdo->getCollection('modResource');
foreach ($resources as $res) {
    print_r($res);
}

Эти методы всегда выполняются отдельным экземпляром, чтобы не мешать работающему сниппету. Они выполняются изолированно. Получить вывод лога от них можно только через специальный плейсхолдер:

$pdo = $modx->getService('pdoFetch');
$res = $pdo->getArray('modResource', 1);
print_r($modx->getPlaceholder('pdoTools.log'));

Первым параметром указывается класс для работы, вторым условие where, а третьим любой набор параметров. Например, вот так будет выглядеть выборка всех файлов Тикета:

$files = $pdo->getCollection('TicketFile', array('parent' => 1));
print_r($files);

Пример с JOIN операцией:

$files = $pdo->getCollection('TicketFile', array(), array(
    'innerJoin' => array(
        'Ticket' => array(
            'class' => 'Ticket',
            'on' => 'Ticket.id = TicketFile.parent'
        )
    ),
    'select' => array(
        'TicketFile' => '*',
        'Ticket' => 'pagetitle'
    ),
    'sortby' => array(
        'TicketFile.id' => 'ASC'
    )
));
print_r($modx->getPlaceholder('pdoTools.log'));
print_r($files);

Как видите, эти методы очень удобны для использования в своих сниппетах. На них можно переложить основную работу по добыче данных из БД.

pdoParser — быстрый парсер тегов MODX

pdoParser является заменой класса modParser. Его задача — быстро разбирать теги MODX без создания объектов, как это делает оригинальный парсер.

Обработка простых плейсхолдеров

pdoParser умеет работать только с простыми тегами без фильтров и условий:

  • [[%tag]] — строка лексикона
  • [[~id]] — ссылка
  • [[+tag]] — обычные плейсхолдеры
  • [[++tag]] — системные плейсхолдеры
  • [[*tag]] — плейсхолдеры ресурса
  • [[#tag]] — плейсхолдеры FastField

Теги FastField

Специальные теги FastField были предложены Виталием Киреевым в одноименном дополнении. После согласования с автором, pdoParser был обучен работе с ними.

FastField умеет:

  • Выводить поля ресурсов: [[#15.pagetitle]], [[#20.content]]
  • Выводить TV-параметры ресурсов: [[#15.date]], [[#20.some_tv]]
  • Выводить массивы ресурсов: [[#12.properties.somefield]], [[#15.size.1]]
  • Выводить глобальные массивы: [[#POST.key]], [[#SESSION.another_key]]
  • Распечатывать массивы для отладки: [[#15.colors]], [[#GET]], [[#12.properties]]

Цифра после решетки — это ID ресурса, от которого нужно выбрать данные.

Все эти теги pdoTools обрабатывает без создания объектов modElement, поэтому работает быстрее чем родные методы MODX. Если плейсхолдер вызван с параметрами, он уходит в родной modParser.

Шаблонизатор Fenom

С версии 2.0 в состав pdoTools входит шаблонизатор Fenom. Работает только при включенном pdoParser и если разрешен в системных параметрах.

Возможности Fenom

  • Компилируется в нативный PHP код, который выполняется гораздо быстрее тегов MODX — прирост в среднем 30% — 50%
  • Может работать и в чанках и на страницах сайта
  • Теги Fenom и MODX не мешают друг другу и работают одновременно
  • Если в чанке нет плейсхолдеров MODX, парсер MODX не запускается
  • Если в чанке нет тегов Fenom, он тоже не запускается
  • Поддерживаются даже @INLINE чанки
  • Не нужно никак менять или переписывать свои сниппеты — всё работает через методы pdoTools::getChunk() и pdoTools::parseChunk() автоматически
  • Все ошибки компиляции пишутся в системный журнал

Системные настройки Fenom

  • pdotools_fenom_default — включает обработку синтаксиса Fenom во всех чанках сайта
  • pdotools_fenom_parser — включает обработку синтаксиса Fenom на страницах сайта (контент ресурсов, шаблоны). По умолчанию отключено.
  • pdotools_fenom_php — включает возможность выполнения произвольных функций PHP в шаблонах через {$.php.функция()}. Опция очень опасная, поэтому отключена по умолчанию.
  • pdotools_fenom_modx — работа с объектами modX и pdoTools через переменные {$modx} и {$pdoTools}. Если вы не доверяете своим менеджерам, выключите её, потому что через объект modX можно удалить начисто весь сайт.
  • pdotools_fenom_cache — включает кеширование чанков через кешер MODX. Стоит использовать только на продакшн сайтах при больших и сложных чанках.

Порядок запуска шаблонизатора

Если включен pdoParser и системная опция pdotools_fenom_parser, шаблонизатор запускается до парсера MODX. В этот момент все кешированные чанки и сниппеты на странице обработаны и вы можете использовать конструкции:

{if $.get.test == 1}
  [[!pdoResources?parents=`0`]]
{else}
  [[!pdoMenu?parents=`0`]]
{/if}

В зависимости от $_GET['test'] на странице будет запущен или один сниппет или другой. Парсер MODX же запустил бы оба и результат выполнения одного неподходящего просто не показал.

Внутри чанков Fenom всегда выполняется в первую очередь, позволяя разделять их содержимое для MODX в зависимости от условий.

Вызов тегов Fenom на страницах сайта никак не кешируется.

Кеширование чанков Fenom

По умолчанию этот функционал отключен. Но вы можете включить системную настройку pdotools_fenom_cache и тогда скомпилированные шаблоны будут сохранены в /cache/default/fenom/.

Чанки из БД кэшируются под своими ID, а INLINE именуются как хеш от своего содержимого:

  • Обычный чанк: cache/default/fenom/chunk/90.cache.php
  • INLINE чанк: cache/default/fenom/inline/35e115c27fdc3814b6f41a1015aa67e6.cache.php

Отсюда следует, что нормальные чанки из БД кэшируются намертво и обновляются только при очистке системного кэша, а INLINE чанки при изменении контента сохраняются под новым именем и весь кэш чистить не нужно.

При первом запуске с пустым кешем pdoTools получает нужный чанк, определяет его тип и отдает в Fenom. Тот компилирует шаблон и сохраняет его во внутренний кэш pdoTools методом setStore(). Этот кэш находится в ОЗУ и сохраняется только на время выполнения скрипта.

Если включена опция pdotools_fenom_cache, исходный код скомпилированного шаблона сохраняется на HDD сервера, и при следующем запуске Fenom уже не нужно его компилировать.

Вопрос в том, что для вас будет быстрее — поднять скомпилированный шаблон из кэша или скомпилировать его заново. Обычно на маленьких и простых чанках выигрыша нет, а на больших и сложных разница уже может быть. Время компиляции и работы с кэшем выводится в &showLog=1.

Пример использования Fenom

Стандартный чанк из компонента Tickets:

<div class="comments">
  [[+modx.user.id:isloggedin:is=`1`:then=`
    <span class="comments-subscribe pull-right">
      <label for="comments-subscribe" class="checkbox">
        <input type="checkbox" id="comments-subscribe" value="1" [[+subscribed:notempty=`checked`]] />
        [[%ticket_comment_notify]]
      </label>
    </span>
  `:else=``]]
  <h4 class="title">[[%comments]] (<span id="comment-total">[[+total]]</span>)</h4>
  <div id="comments-wrapper">
    <ol class="comment-list" id="comments">[[+comments]]</ol>
  </div>
</div>

Тот же чанк, переписанный для работы с Fenom:

<div class="comments">
  {if $modx->user->isAuthenticated($modx->context->key)}
    <span class="comments-subscribe pull-right">
      <label for="comments-subscribe" class="checkbox">
        <input type="checkbox" id="comments-subscribe" value="1" {$subscribed != '' ? 'checked' : ''} />
        {$modx->lexicon('ticket_comment_notify')}
      </label>
    </span>
  {/if}
  <h4 class="title">{$modx->lexicon('comments')} (<span id="comment-total">{$total}</span>)</h4>
  <div id="comments-wrapper">
    <ol class="comment-list" id="comments">{$comments}</ol>
  </div>
</div>

Как видите, синтаксис Fenom более читаемый и привычный для PHP разработчиков.

Заключение

Три класса pdoTools работают в связке, обеспечивая максимальную производительность:

  • pdoTools — основной класс для логирования, кеширования и работы с чанками
  • pdoFetch — мощный инструмент для работы с базой данных через PDO с поддержкой JOIN и сложных запросов
  • pdoParser — быстрый парсер тегов MODX с поддержкой шаблонизатора Fenom

Используйте эти классы в своих разработках для создания быстрых и эффективных решений на MODX.

Оцените статью
MODX 3
Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.