Fenom и параметры элементов
В прошлой статье мы рассмотрели некоторые особенности реализации шаблонизатора Fenom в MODX и отметили проблемы с кэшированием. Напомню, что сам Fenom кэшированием не занимается. Ему отводится лишь роль дополнительного парсера — обработал контент и отдал его MODX. А MODX позаботится о кэшировании (насколько позволяют его возможности). И тут можно наткнуться на подводный камень.
Рассмотрим следующую ситуацию. Вы вызываете на странице для меню сниппет pdoMenu или для вывода списка ресурсов сниппет pdoResources. Если логика несложная, то и код достаточно простой.
{'pdoMenu' | snippet : [ 'parents' => 0, 'resources' => '-10', 'tpl' => '@INLINE <li>{$pagetitle}</li>' ]}
Как видим, сниппет вызван кэшируемым. А как я отмечал в предыдущей статье, Fenom умеет кэшировать только чанки и сниппеты (в отличие от других тегов и файловых элементов). Поэтому Fenom распарсит этот вызов, передаст управление pdoTools, который создаст объект сниппета, укажет, что это кэшируемый элемент и отдаст его на выполнение MODX.
Отличие логики кэширования MODX синтаксиса от Fenom
Если вы вызываете кэшируемый сниппет через стандартный синтаксис MODX ([[snippet]]
), то после того, как MODX выполнит этот сниппет, он заменит тег вызова сниппета на результат и сохранит в кэше страницы. Таким образом, при повторном просмотре страницы тега уже не будет.
В случае с Fenom сработает другая логика кэширования. MODX не умеет заменять тег Fenom на результат. Поэтому в кэше страницы теги Fenom никогда не удаляются. Но MODX будет сохранять результаты в отдельный кэш элементов. Для этого в массиве ресурса в кэше есть специальный ключ elementCache
. Именно в него сохраняются кэшируемые чанки и сниппеты, вызванные через Fenom. Причем формат следующий — в качестве ключа указан полный код вызова сниппета (включая неуказанные при вызове параметры), а в качестве значения — результат.
Так как теги Fenom не вырезаются из контента кэшируемой страницы, то при каждом просмотре страницы парсер будет вынужден их обрабатывать. В случае с кэшируемым сниппетом он будет формировать полный код тега, а потом проверит кэш элементов по этому ключу.
Например, выше приведённый вызов в кэше будет выглядеть так:
// core/cache/resource/web/resources/1.cache.php 'elementCache' => array( '[[pdoMenu?where=``&showLog=``&fastMode=``&level=`0`&parents=`0`&displayStart=``&resources=`-10`&templates=``&context=``&cache=``&cacheTime=`3600`&cacheAnonymous=``&plPrefix=`wf.`&showHidden=``&showUnpublished=``&showDeleted=``&previewUnpublished=``&hideSubMenus=``&useWeblinkUrl=`1`&sortdir=`ASC`&sortby=`menuindex`&limit=`0`&offset=`0`&rowIdPrefix=``&firstClass=`first`&lastClass=`last`&hereClass=`active`&parentClass=``&rowClass=``&outerClass=``&innerClass=``&levelClass=``&selfClass=``&webLinkClass=``&tplOuter=`@INLINE <ul[[+classes]]>[[+wrapper]]</ul>`&tpl=`@INLINE <li>{$pagetitle}</li>`&tplParentRow=``&tplParentRowHere=``&tplHere=``&tplInner=``&tplInnerRow=``&tplInnerHere=``&tplParentRowActive=``&tplCategoryFolder=``&tplStart=`@INLINE <h2[[+classes]]>[[+menutitle]]</h2>[[+wrapper]]`&checkPermissions=``&hereId=``&select=``&scheme=``&toPlaceholder=``&countChildren=``]]' => '<ul class=""><li>Главная</li><li>Вторая страница</li><li>Последняя страница</li></ul>', ),
Получается, что в случае с Fenom синтаксисом, даже для кэшированных элементов есть небольшой оверхед на парсинг, формирование ключа и проверку массива кэшируемых элементов. Но я хотел рассказать не об этом.
Я выше привёл пример простого вызова сниппета pdoMenu. Как видим, условия для запроса передаются через специальные параметры сниппета («parents», «resources», «showDeleted» и т.п.). Но часто бывают запросы с более сложной логикой и через эти параметры её указать не получится. Для этого придётся задействовать параметр where
, в котором напрямую указать предикаты запроса. А так как Fenom даёт возможность работать в PHP формате, то многие разработчики пользуются этой возможностью и используют массив вместо строки, так как xPDOQuery работает именно с массивом:
{'pdoMenu' | snippet : [ 'tpl' => '@INLINE <li>{$pagetitle}</li>', 'where' => [ 'parent' => 0, 'id:!=' => '-10', ] ]}
Но проблема в том, что MODX не умеет кэшировать массивы в параметрах сниппетов и вместо них формирует случайный хэш. Таким образом, кэш предыдущего вызова будет выглядеть так:
// core/cache/resource/web/resources/1.cache.php 'elementCache' => array( '[[pdoMenu?&where=`cb618cc9874e2dc8afae8845b482d546`&showLog=``&fastMode=``&level=`0`&parents=`0`&displayStart=``&resources=`-10`&templates=``&context=``&cache=``&cacheTime=`3600`&cacheAnonymous=``&plPrefix=`wf.`&showHidden=``&showUnpublished=``&showDeleted=``&previewUnpublished=``&hideSubMenus=``&useWeblinkUrl=`1`&sortdir=`ASC`&sortby=`menuindex`&limit=`0`&offset=`0`&rowIdPrefix=``&firstClass=`first`&lastClass=`last`&hereClass=`active`&parentClass=``&rowClass=``&outerClass=``&innerClass=``&levelClass=``&selfClass=``&webLinkClass=``&tplOuter=`@INLINE <ul[[+classes]]>[[+wrapper]]</ul>`&tpl=`@INLINE <li>{$pagetitle}</li>`&tplParentRow=``&tplParentRowHere=``&tplHere=``&tplInner=``&tplInnerRow=``&tplInnerHere=``&tplParentRowActive=``&tplCategoryFolder=``&tplStart=`@INLINE <h2[[+classes]]>[[+menutitle]]</h2>[[+wrapper]]`&checkPermissions=``&hereId=``&select=``&scheme=``&toPlaceholder=``&countChildren=``]]' => '<ul class=""><li>Главная</li><li>Вторая страница</li><li>Последняя страница</li></ul>', ),
Обратите внимание на параметр where
. Вместо данных, указанных в теге сниппета, он содержит случайный хэш.
В итоге мы ожидаем, что раз сниппет есть в кэше, он отрабатывать уже не будет. А значит задача оптимизации в этой части выполнена. Но по факту, так как MODX при каждом просмотре страницы будет заново формировать полный ключ тега сниппета и каждый раз будет новый хэш параметра where
, то ключ в кэше элементов будет невалидный. А значит сниппет будет выполняться при каждом запросе страницы.
Самое простое решение — вместо массива указывать строку в JSON формате. Тогда MODX сохранить всё как нужно. А pdoTools под капотом переведёт её в массив.
{'pdoMenu' | snippet : [ 'tpl' => '@INLINE <li>{$pagetitle}</li>', 'where' => '{"parent":0,"id:!=":"-10"}' ]}
Теперь и вы об этом знаете. )
П.С. В следующей версии pdoTools я постараюсь исправить эту проблему.
Вы должны авторизоваться, чтобы оставлять комментарии.
Комментарии ()