Прокачиваем навык программирования на Fenom

Информация для разработчиков. Сложность средняя.

Практически все разработчики MODX используют тот или иной шаблонизатор. Большинство в рунете сделали свой выбор в пользу Fenom. Благодаря Василию конечно. Этот шаблонизатор достаточно простой и лёгкий. И его функционала хватает для решения практически всех своих задач. В этой статье мы посмотрим на него немного под другим углом и попробуем его возможности расширения.
Не так давно в pdoTools было добавлено событие «pdoToolsOnFenomInit». Думаю, не все осознали, что это событие даёт. Про собственные модификаторы уже писали. А если заглянуть в документацию Fenom, то можно увидеть, что возможности расширения очень большие. Давайте глянем на примеры.

Добавление пользовательской глобальной переменной

Это может пригодится, например, для много контекстных сайтов. При инициализации Fenom сразу определить нужные значения и использовать их потом в разметке.
// Плагинswitch($modx->event->name){case'pdoToolsOnFenomInit':
            $fenom->addAccessorSmart("site","data",Fenom::ACCESSOR_PROPERTY);// Переменные можно определить статически или динамически по условию
            $fenom->data =["domain"=>'example.ru',"support"=>'support@example.ru'];break;}
А затем в шаблоне добавить
<divclass="copyright">© <ahref="//{$.site.domain}">{$.site.domain}</a></div><divclass="support">Support <ahref="mailto:{$.site.support}">{$.site.support}</a></div>

Пользовательские теги

Добавлять свои собственные теги — офигенная вещь. Причем теги могут быть линейными (как например, include) и блоковыми ({if}...{/if}). Покажу на примере. Определим блок только для администраторов и добавим для этого блоковый тег can.
<div>
    {can}
        {include 'chunkForAdministrators'}
    {/can}
</div>
Осталось подключить тег в плагине
// Плагинswitch($modx->event->name){case'pdoToolsOnFenomInit':
        $fenom->addBlockFunction('can',function(array $params, $content){if(user(user_id())->isMember('Administrator')){return $content;}else{return'Данная информация только для администраторов!';}});break;}
Может пример несколько надуманный, но он показывает возможности пользовательских тегов. Как вариант, можно добавить теги mobile, desktop. Ну в общем, надеюсь, понятно.
В теги можно передавать параметры
// Плагинswitch($modx->event->name){case'pdoToolsOnFenomInit':
        $fenom->addBlockFunction('can',function(array $params, $content){
	    list($group, $param2)= $params;if(user(user_id())->isMember($group){return $content;}});break;}
А передают их так
<div>
    {can 'Administrator' 'param2'}
        {include 'chunkForAdministrators'}
    {/can}
</div>


Ещё пример. Можно легко добавить тег, который будет включать файловый чанк. Назовём его includeFile.
// Плагин
$fenom->addFunction("includeFile",function(array $params){
    $file = MODX_CORE_PATH .'elements/chunks/'. $params[0]; 
    $output ='';if(file_exists($file)) $output = chunk($file, $params[1]);return $output;});
А в шаблоне пишем так:
{includeFile 'chunk.tpl'['var'=>'value','var2'=>'value2']}// указываем имя файла и массив плейсхолдеров
Fenom подключит файл core/elements/chunks/chunk.tpl и распарсит его.

Разрешённые функции

В Fenom количество разрешённых php функций ограничено. Но можно самостоятельно добавить нужную функцию к списку разрешённых.
switch($modx->event->name){case'pdoToolsOnFenomInit':
        $fenom->addAllowedFunctions(['app']);break;}

Заключение

Ну и напоследок расскажу ещё об одном приёме. Бывает иногда нужно прокинуть переменную в шаблонизатор. Т.е. в сниппете чего-то рассчитали или в классе и нужно передать в шаблон. Прямого способа я не знаю. Если есть, поправьте меня. Один из вариантов — сохранять в сессии, а в шаблоне доставать через $.session(). Способ спорный. Раздувать временными данными сессию, увеличивая тем самым и без того растущую как на дрожжах таблицу сессий. Желательно удалять их после использования. В общем, как-то не очень.
Ещё есть способ, как подсказывает Василий в комментариях, через плейсхолдеры. Главное, чтобы название не пересекалось с другими плейсхолдерами, ТВшками и т.п.
После выхода последней версии библиотеки modHelpers сделать этого достаточно легко и не надо заботиться о чистке сессии. Всё что нужно, добавить нужную переменную в контейнер, а затем феномом её вытащить.
// Где-то в коде
$array = array('ids'=>[1,2,3,4,5]);
$object = $modx->getObject('modResource',100);
app()->instance('var.array', $array);// Добавляем префикс "var." для семантики, чтобы было понятно,
app()->instance('var.object', $object);// что это переменные.// В шаблоне/чанке/ресурсе{$array = app('var.array')}{$object = app('var.object')}

Всё возможности в одной статье не опишешь. Но надеюсь, описанные приёмы пригодятся как опытным, так и начинающим разработчикам.