Fenom MODX - Документация и примеры

Fenom MODX

Всем привет, дорогие читатели моего блога!

Я уже давно ничего не писал в свой блог, в связи с тем, что у меня есть заказы + учеба. Вообщем времени не так уж много. 

Сегодня я хочу рассказать про шаблонизатор под названием Fenom, привести примеры. Может кто-то уже активно им пользуется, и думаю, что найдет что-нибудь нового и полезного в этой статье.

Давайте сначала разберемся, что из себя представляет Fenom

Fenom - это быстрый и удобный шаблонизатор, который очень схож со Smarty (в плане синтаксиса), но является намного лучше! С его помощью Вы можете ускорить разработку,
время на выполнение запросов, сократить количество чанков, использовать циклы прям в чанках/шаблонах и многое другое

В MODX Fenom появился в 2015 году, с выходом обновления pdoTools 2.0.
Теперь когда вы устанавливается pdoTools, парсер Fenom уже активен, но не обрабатывает страницы и шаблоны сайта

Для того, чтобы включить fenom (обработку страниц и шаблонов сайта), необходимо активировать параметр pdotools_fenom_parser в системных настройках.

Синтаксис

Можете посмотреть официальную документацию, а я буду рассматривать синтаксис, касательно MODX Revolution

Итак, как я уже говорил, синтаксис довольно прост, вместо привычных двойных квадратных скобок в MODX [[ ]] и Fenom используются одинарные фигурные скобки { }

Чтобы использовать более сложные функции, в pdoParser есть служебная переменная {$_modx}, которая даёт безопасный доступ к некоторым переменным и методам системы.

  • {$_modx->resource.id} - вывод id текущего ресурса
  • {$_modx->resource.tv_name} - вывод tv текущего ресурса
  • {$_modx->user}- массив текущего пользователя
  • {$_modx->makeUrl(10)} - ссылка на 10 ресурс
  • {$_modx->config.system_setting} - вывод системной настройки

Игнорирование кода

Так как в Fenom используются фигурные скобки, то возможно возникнет такая проблема, что не будут выполняться какие-то скрипты/стили.
Для этих случаев существует переменная ignore. Для того, чтобы выключить обработку Fenom необходимо просто обернуть скрипты/стили в этот тег:

<style>
{ignore}

body {font-size: 16px; background-color: #000;}

{/ignore}
</style>

Подключение счетчика Яндекс Метрики:

{'<!-- Yandex.Metrika counter -->
<script type="text/javascript" >
   (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
   m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
   (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");

   ym(9999999999, "init", {
        clickmap:true,
        trackLinks:true,
        accurateTrackBounce:true,
        webvisor:true,
   });
</script>
<noscript><div><img src="https://mc.yandex.ru/watch/9999999999" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter -->' | jsToBottom : true}

Если нужно в Head, тогда jsToHead 

Плейсхолдеры с точкой или тире

В MODX как вы знаете существуют TV параметры у ресурса или плейсхолдеры с точкой (данные массивов). Так как они не соответсвуют правилам наименования, то в Fenom для доступа к плейсхолдерам и TV существуют служебная переменная {$_pls}

<!-- Вывод сразу -->
{$_pls['tag.subtag']}

<!-- Или через переменную -->
{var $tv_name = $_pls['tv-name']}
{$tv_name}

Как запустить сниппет в Fenom?

Я знаю два способа, как запустить сниппет в Fenom, какой использовать, решать только Вам.

1 способ:

{'!pdoPage' | snippet : [
    'parents' => $_modx->resource.id, 
    'limit' => 5,
    'toPlaceholder' => 'result'
]}

{'result' | placeholder}
{'page.total' | placeholder}
{'page.nav' | placeholder}

2 способ:

{$_modx->runSnippet('!pdoPage', [
    'parents' => $_modx->resource.id, 
    'limit' => 5,
    'toPlaceholder' => 'result'
])}

{$_modx->getPlaceholder('result')}
{$_modx->getPlaceholder('page.total')}
{$_modx->getPlaceholder('page.nav')}

Если необходимо вызвать pdopage без параметров:

#1 способ
{'!pdoPage' | snippet}

#2 способ
{$_modx->runSnippet('!pdoPage')}

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

Условие IF

#Устанавливаем id текущей страницы в переменную
{set $id = $_modx->resource.id}
#Условие
{if $id == '1'}
<p>Главная страница</p>
{else}
<p>Не главная</p>
{/if}

Условие IF с использованием тренарного оператора

#Устанавливаем id текущей страницы в переменную
{set $id = $_modx->resource.id}
#Условие
{$id == 1 ? '<p>Главная страница</p>' : '<p>Не главная</p>'}

Перебор с использованием switch/case

{switch  $_modx->resource.id}
{case 1}
    <p>Главная страница</p>
{case 2}
    <p>О компании</p>
{case 3}
    <p>Услуги</p>
{default}
  <p>Для остальных id</p>
{/switch}

Вывод чанка

{include 'myChank'}

Если не передаете параметры, то вот так

{insert 'myChank'}

Получение значения TV у произвольного ресурса:

{1 | resource: 'tv_name'}

*1 - id ресурса

Вывод MIGX через Fenom для текущего ресурса:

{set $rows = json_decode($_modx->resource.tv_images, true)}
{foreach $rows as $row}
    {$row.image}
{/foreach}

Вывод MIGX через Fenom для определенного ресурса:

{set $rows = json_decode(1 | resource: 'tvname', true)}
{foreach $rows as $row}
    {$row.image}
{/foreach}

Информация о прозводителе в miniShop2

{$_modx->makeUrl($_pls['vendor.resource'])}
{$_pls['vendor.name']})
{$_modx->getPlaceholder('vendor.name')}

Получение изображения через переменную с точкой ($_pls)

{$_pls["tv.img"] | phpthumbon : "w=300&h=200&zc=1"}
//Без префикса
{$img | phpthumbon : "w=300&h=200&zc=1"}

Получение превью изображений в корзине

{if $product['120x90']?}
<img src="{$product['120x90']}" alt="{$product.pagetitle}" title="{$product.pagetitle}"/>
{else}
<img src="{'assets_url' | option}components/minishop2//web/ms2_small.png" 
srcset="{'assets_url' | option}components/minishop2/img/web/ms2_small@2x.png 2x" 
alt="{$product.pagetitle}" title="{$product.pagetitle}"/>
{/if}

Модификатор дата

{$_modx->resource.publishedon | date_format:"%d-%m-%Y %H:%M:%S"}

Вывысти текущий год

{'' | date : 'Y'}

Проверка авторизации

{$_modx->isAuthenticated()}
{$_modx->hasSessionContext('web')}
{$_modx->hasPermission('load')}

Получение данных по id (FastField)

{id | параметр : [доп указания]}

{3 | url : ['scheme' => 'full'] : ['param' => 'value']}   // генерируем url
{3 | resource : 'my_tv'}                                  // выводим TV поле у ресурса
//Выводим заголовок дедушки
{set $parent_id = $_modx->resource.parent} //Получаем id родителя
{set $grand_parent_id  = $parent_id | resource : 'parent' } //Получаем id дедушки
{$grand_parent_id  | resource : 'pagetitle'} //выводим заголовок

Создание и расширение базового шаблона

Названием шаблона base

<!doctype html>
<html lang="ru">
  <head>
    <base href="{'site_url' | config}" />
    <title>{$_modx->resource.longtitle} - {'site_name' | config} </title>
  </head>
  <body>
    
    {insert 'header'}

    // расширяем шаблон
    {block 'main'}
           {insert 'main'}
    {/block}
 
     {insert 'footer'}
     {insert 'js'}
  </body>
</html>

Расширяем шаблон base

// расширяем шаблон    
{extends 'template:base'}

{block 'main'}
       {insert 'other_main'}
{/block}

Источник: docs.modx.pro

13.07.2017 / 75406

No avatar

Комментарии (34)

  1. РАзработчик на MODx 30 ноября 2021, 08:56 # 0
    pdoTools — наумкинское дерьмо, одна из причин скатывания проектов на модх в яму. Почему все начали это использовать? Все инструменты в модх и без этого обеспечивают полный инструментарий
    1. Алексей 13 октября 2022, 15:13 # 0
      Не наумовское. И не такое уж дерьмо, поинтереснее родного парсера особенно когда условия сложные)
    2. Комментарий был удален.
      1. Анна 22 июня 2019, 14:09 # 0
        А как вызывать migx через fenom из другого ресурса? Такую инфу думаю можно и к статье дополнить
        1. Игорь 22 июня 2019, 21:03 # 0
          Уже есть :)
          Получение значения TV у произвольного ресурса:
          {1 | resource: 'tv_name'}
          1. Max 14 августа 2019, 23:44 # 0
            что-то не пойму как в такой конструкции указать чтобы бралось из ресурса 1
            {set $rows = json_decode($_modx->resource.tvname, true)}
                                        {foreach $rows as $idx => $row}
                                            {$row.title}
                                            {$row.description} 
                    {/foreach}
            Спасибо заранее)
            1. Max 15 августа 2019, 23:16 # 0
              отвечу сам себе)
              {set $rows = json_decode(1 | resource: 'tvname', true)}
              1. Игорь 16 августа 2019, 08:48 # 0
                Рад что поняли
              2. Rahim 23 января 2019, 10:06 # 0
                Как использовать phpthumbon на MIGX IMAGE

                {$row.image | phpthumbon : "w=300&h=200&zc=1"}
                возвращает пустую заглушку
                1. Rahim 23 января 2019, 11:15 # 0
                  Ответь
                  {("uploads/" ~ $row.image) | phpthumbon : 'w=620&h=500&zc=1&f=jpg&q=100'}
                  1. Игорь 22 июня 2019, 21:03 # 0
                    Лучше запустить сниппет
                  2. Андрей 01 ноября 2018, 11:52 # 0
                    Условие IF
                    #Устанавливаем id текущей страницы в переменную
                    {set $id = $_modx->resource.id}
                    #Условие
                    {if $id == '1'}
                    Главная страница
                    {else}
                    Не главная
                    {/if>

                    "{/if>" — опечатка, там должна быть закрывающая "}"
                    1. Гость 29 июня 2018, 14:28 # 0
                      Это тоже безумкиншина? Нафиг…
                      1. Разработчик на MODx 30 ноября 2021, 08:58 # 0
                        Полностью поддерживаю вас, коллега
                      2. Денис 27 марта 2018, 13:11 # 0
                        Отличный сайт! В закладки!
                        1. ytkin 26 апреля 2018, 01:32 # 0
                          школьник делает лучше
                          1. Денис 04 мая 2018, 22:52 # 0
                            Зачем такое писать?
                          2. Андрей 01 марта 2018, 14:11 # 0
                            Здравствуйте. Подскажите пожалуйста, а как перевести в Fenom встроенный PHx? Вот к примеру имеется такой вывод, но не очень понятно как всё это через Fenom сделать.

                            [[*seodescription:empty=`[[*pagetitle:stripString=`"`:stripString=`.`]]`]]
                            1. Андрей 28 февраля 2018, 18:31 # 0
                              Подскажите а есть какие-нибудь аналоги {noscript}{/noscript} в феном? Мне нужно яваскрипт голый подрубить, но феном перестаёт работать из-за использования в JS фигурных скобок, как такие скрипты выделить?
                              1. Игорь 28 февраля 2018, 22:47(Комментарий был изменён) # 0
                                Да, есть. Тег
                                {ignore}{/ignore}
                                Я об этом написал в статье
                              2. Александр 07 февраля 2018, 14:41 # 0
                                помогите переписать на Fenom
                                <!--ec_reply_text <div class="ec-message__reply">[[+reply_author]]<p>[[+reply_text]]</p></div>-->
                                <!--ec_reply_author <p><strong>[[+reply_author]]</strong></p>-->
                                1. Игорь 22 июня 2019, 21:05 # 0
                                  Это плейсхолдеры
                                2. Михаил 01 февраля 2018, 14:25 # 0
                                  Как на fenom переписать такую конструкцию:
                                  <a role="button" class="btn" title="[[#39.pagetitle]]" href="[[~39]]">
                                  1. Игорь 01 февраля 2018, 15:31 # 0
                                    Вот так:
                                    <a role="button" class="btn" title="{39 | resource : 'pagetitle'}" href="{$_modx->makeUrl('39')}">
                                    Написал с телефона, может есть ошибки
                                  2. Андрей 05 января 2018, 21:14 # 0
                                    Добрый день. Подскажите, как можно оптимизировать данный код? Смысл в том, что у меня при создании ресурса проверяется есть ли нужная категория и если ее нет, то она создается. И так 4 раза (4 вложенных друг в друга категории). Но я нутром чую, что код можно сократить сильно. Помогите пожалуйста.
                                    @INLINE {var $output}
                                    {* Получаем ID корневого раздела *}
                                    {var $id = ('!pdoResources' | snippet : [
                                        'parents' => $_task['parent'],
                                        'where' => [
                                            'pagetitle' => $category_parent,
                                            'isfolder' => 1,
                                        ],
                                        'limit' => 1,
                                        'returnIds' => 1,
                                    ])}
                                    
                                    {* Если в базе не нашли *}
                                    {if $id is empty}
                                        {* Создаем новый раздел *}
                                        {var $resp = $_modx->runProcessor('resource/create', [
                                            'class_key' => 'msCategory',
                                            'pagetitle' => $category_parent,
                                            'context_key' => $_task['context'],
                                            'parent' => $_task['parent'],
                                            'isfolder' => 1,
                                            'published' => 1,
                                        ])}
                                    	
                                        {if $resp.response.object['id']?}
                                            {var $id = $resp.response.object['id']}
                                        {/if}
                                        
                                        {if $id?}
                                            {* Копируем взаимодействие раздела с опциями из основного раздела *}
                                            {var $resp = $_modx->runProcessor('category/option/duplicate', [
                                                'category_from' => $_task['parent'],
                                                'category_to' => $id,
                                            ], [
                                                'processors_path' => (('core_path' | option) ~ 'components/minishop2/processors/mgr/'),
                                            ])}
                                    		
                                        {/if}
                                    {/if}
                                    
                                    {* Получаем ID дочернего к корневому раздела *}
                                    	{var $id2 = ('!pdoResources' | snippet : [
                                    		'parents' => $id,
                                    		'where' => [
                                    			'pagetitle' => $category_children,
                                    			'isfolder' => 1,
                                    		],
                                    		'limit' => 1,
                                    		'returnIds' => 1,
                                    	])}
                                    	{* Если в базе не нашли *}
                                    {if $id2 is empty}
                                        {* Создаем новый раздел *}
                                        {var $resp2 = $_modx->runProcessor('resource/create', [
                                            'class_key' => 'msCategory',
                                            'pagetitle' => $category_children,
                                            'context_key' => $_task['context'],
                                            'parent' => $id,
                                            'isfolder' => 1,
                                            'published' => 1,
                                        ])}
                                    	
                                        {if $resp2.response.object['id']?}
                                            {var $id2 = $resp2.response.object['id']}
                                        {/if}
                                        
                                        {if $id2?}
                                            {* Копируем взаимодействие раздела с опциями из основного раздела *}
                                            {var $resp2 = $_modx->runProcessor('category/option/duplicate', [
                                                'category_from' => $id,
                                                'category_to' => $id2,
                                            ], [
                                                'processors_path' => (('core_path' | option) ~ 'components/minishop2/processors/mgr/'),
                                            ])}
                                        {/if}
                                    {/if}
                                    
                                    {* Получаем ID раздела бренда *}
                                    	{var $id3 = ('!pdoResources' | snippet : [
                                    		'parents' => $id2,
                                    		'where' => [
                                    			'pagetitle' => $category_brand,
                                    			'isfolder' => 1,
                                    		],
                                    		'limit' => 1,
                                    		'returnIds' => 1,
                                    	])}
                                    	{* Если в базе не нашли *}
                                    {if $id3 is empty}
                                        {* Создаем новый раздел *}
                                        {var $resp3 = $_modx->runProcessor('resource/create', [
                                            'class_key' => 'msCategory',
                                            'pagetitle' => $category_brand,
                                            'context_key' => $_task['context'],
                                            'parent' => $id2,
                                            'isfolder' => 1,
                                            'published' => 1,
                                        ])}
                                    	
                                        {if $resp3.response.object['id']?}
                                            {var $id3 = $resp3.response.object['id']}
                                        {/if}
                                        
                                        {if $id3?}
                                            {* Копируем взаимодействие раздела с опциями из основного раздела *}
                                            {var $resp3 = $_modx->runProcessor('category/option/duplicate', [
                                                'category_from' => $id2,
                                                'category_to' => $id3,
                                            ], [
                                                'processors_path' => (('core_path' | option) ~ 'components/minishop2/processors/mgr/'),
                                            ])}
                                        {/if}
                                    {/if}
                                    
                                    {* Получаем ID раздела модели *}
                                    	{var $id4 = ('!pdoResources' | snippet : [
                                    		'parents' => $id3,
                                    		'where' => [
                                    			'pagetitle' => $category_model,
                                    			'isfolder' => 1,
                                    		],
                                    		'limit' => 1,
                                    		'returnIds' => 1,
                                    	])}
                                    	{* Если в базе не нашли *}
                                    {if $id4 is empty}
                                        {* Создаем новый раздел *}
                                        {var $resp4 = $_modx->runProcessor('resource/create', [
                                            'class_key' => 'msCategory',
                                            'pagetitle' => $category_model,
                                            'context_key' => $_task['context'],
                                            'parent' => $id3,
                                            'isfolder' => 1,
                                            'published' => 1,
                                        ])}
                                    	
                                        {if $resp4.response.object['id']?}
                                            {var $id4 = $resp4.response.object['id']}
                                        {/if}
                                        
                                        {if $id4?}
                                            {* Копируем взаимодействие раздела с опциями из основного раздела *}
                                            {var $resp4 = $_modx->runProcessor('category/option/duplicate', [
                                                'category_from' => $id3,
                                                'category_to' => $id4,
                                            ], [
                                                'processors_path' => (('core_path' | option) ~ 'components/minishop2/processors/mgr/'),
                                            ])}
                                        {/if}
                                    {/if}
                                    
                                    {* Выводим ID *}
                                    {$id4}
                                    {/var}{$output | strip : true}
                                    1. Константин 28 декабря 2017, 07:14 # 0
                                      Есть ли минусы в том, чтобы перевести все на феном?

                                      Я не в восторге что изначально modx хранит все в админке и дергать код из нее в редактор и обратно это не гуд и долго. Но если и шаблоны и чанки посадить не феном, реальный прирост скорости и удобства будет? Или будет примерно «шило на мыло». Убрав все радостные возгласы «наконец-то все по человечески» и всякие эмоции. Чисто и сухо — сухой прирост скорости разработки?
                                      1. Игорь 28 декабря 2017, 07:59 # 0
                                        Минусов никаких нет.
                                        Нужно постараться сделать так, чтобы не запускался родной парсер modx.То есть максимально переписать все вызовы на Fenom. Скорость загрузки сайта в разы уменьшится.

                                        По поводу хранения кода в базе, то Вас никто не обязывает его там хранить. Можно полностью перенести работу с сайтом в IDE. Василий Наумкин даже выпустил специально для этого пакет.
                                        Вот ссылка: modx.pro/news/13793/
                                        1. AI 22 октября 2018, 00:05 # 0
                                          кому-то нравится Fenom, кому-то — Twig. Есть еще любители Blade, Volt и еще ряд других. Если каждый будет выпускать свои наработки и использовать то, что ему нравится, то получится, что применяя их дополнения в MODX можно развести целый зоопарк.
                                          Вместо того, чтобы использовать то, что в самом MODX уже есть — SMARTY.

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

                                          Просто Безумкину вот нравится Fenom и все тут. Или используйте весь его зоопарк pdoTools или идите лесом. Такой вот подход.
                                          1. Димыч 11 декабря 2018, 15:56 # 0
                                            Наумкину — респект и уважуха.
                                            Не нравится феном — не используйте, в чем проблема?
                                            1. Andrey 11 апреля 2019, 15:47 # 0
                                              «Скорость загрузки сайта в разы уменьшится.»
                                              Предположу… имелось ввиду скорость увеличится, а время загрузки уменьшится )))
                                              1. Разработчик на MODx 30 ноября 2021, 08:59 # 0
                                                Минусов нет? Не смешите так
                                                1. Разработчик на MODx 30 ноября 2021, 08:59 # 0
                                                  Наумкин — отстой, хуже говнокода еще не видел
                                                2. Иван 11 декабря 2017, 01:53 # 0
                                                  здравствуйте. Во втором способе вызова снипета забыли закрыть круглую скобку в конце.
                                                  1. Алекс 19 ноября 2017, 09:22 # 0
                                                    Спасибо за примеры.