Переходим на Twig (; Часть первая

Прошлый раз статья про Twig была в «Экспериментах и исследования», с тех пор все, что было нужно, исследовали, и эксперимент успешно завершен. По итогу можно отметить такие плюсы использования Twig:
  • мощный шаблонизатор с кучей возможностей из коробки (при этом разработчик может добавить недостающий функционал несколькими способами) и подробной документацией;
  • дополнительная безопасность за счет того, что Twig по умолчанию экранирует весь вывод, а подсунуть со стороны пользователя тэги MODX не получится, так как шаблонизатору они глубоко безразличны;
  • все работает ровно так, как написано в шаблоне, не нужно вникать, что на каком этапе парсится;
  • шаблоны хранятся в файлах, а значит можно использовать GIT и полноценные редакторы, в которых предусмотрена подсветка синтаксиса Twig;
  • отпадает необходимость создавать в админке чанки и мелкие сниппеты; при желании можно легко подменять шаблоны в зависимости от каких-то параметров документа;
  • в два счета можно сменить дизайн прямо на работающем сайте;
  • полученный опыт пригодится в любой системе, использующей шаблонизатор (не обязательно Twig, но принципы работы у всех схожи), пусть даже MODX Revo;
  • вся суета, происходящая в парсере Evo, просто пройдет мимо вас (:
Бонусом к интеграции шаблонизатора прилагается кэшер, умеющий кэшировать в том числе и на время, с поддержкой разных кэш-провайдеров.

Установка

Можно глянуть видео: www.youtube.com/watch?v=lVI1dCR1-VM
Для установки необходимо наличие Composer. Для чего он нужен и как его установить — на эту тему немало статей в интернете. В OpenServer он уже установлен.

Открываем консоль, переходим в корень сайта и выполняем команду:

composer require pathologic/evo-twig

По этой команде Composer загрузит все необходимое и подготовит автозагрузчик классов:


Если Composer отработал успешно, то дальше нужно установить компонент EvoTwig. Взять его можно здесь: github.com/pathologic/evotwig

Компонент состоит из двух плагинов и сниппета.

Плагин replaceTemplateTwig, собственно, реализует интеграцию.

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

Сниппет getCache позволяет кэшировать вывод сниппетов, по ключу или на определенное время. Часто бывает нужно. Параметры этого сниппета:
  • snippetName — имя сниппета для запуска, необязательный параметр;
  • key — ключ кэша, обязательный параметр;
  • lifetime — время жизни кэша в секундах, если нужно кэшировать на время, необязательный параметр;
  • keyGenerator — имя сниппета или функция для генерации ключа, необязательный параметр.

Настройка

Все настраивается в свойствах плагина replaceTemplateTwig:
  • Debug — включает режим отладки. При этом отключается кэширование страниц MODX, а в шаблонах Twig появляется возможность использовать функцию dump для вывода значений переменных.
  • MODX cache — разрешает кэширование MODX. Если включить при использовании Twig-шаблонов, то сайт станет почти статическим, поэтому по умолчанию отключено.
  • Disable Twig for templates — отключает Twig для шаблонов (: Но при этом остается возможность использовать Twig в чанках, загружать шаблоны (уже просто MODX-шаблоны) из файлов, а также кэшировать все, что под руку попадет.
  • Conditional — не очень понятная настройка, включение которой приведет к тому, что MODX будет отдавать при необходимости заголовки Last-modified и Etag.
  • Templates Folder — папка, в которой хранятся файлы шаблонов.
  • Templates Folder for Developers — то же самое, что и Templates Folder,
    но использоваться она будет, когда пользователь залогинен в админке. Пригодится при редактировании шаблонов на живом сайте — скопировали шаблоны в эту папку, отредактировали и после одобрения залили в основную папку.
  • Template extension — расширение у файла с шаблоном. По умолчанию tpl, потому что мне нравится так, но вообще принято вроде как .tpl.html или .html.
  • Cacher — здесь можно выбрать, каким образом кэшировать данные. По умолчанию используется файловая система. Бездумные эксперименты с этой настройкой могут закончиться крахом сайта (:
  • Allowed functions — здесь можно указать, какие PHP-функции разрешено использовать в шаблонах Twig.

Шаблоны

Как уже говорилось, шаблоны хранятся в файлах и могут быть загружены разными способами:
  • файл выбирается в зависимости от шаблона документа и id документа. Для шаблона 2 и id 4 имя файла будет: tpl-2_doc-4.tpl;
  • файл выбирается в зависимости от id документа. Для id 4 имя файла будет: doc-4.tpl;
  • файл выбирается в зависимости от шаблона документа. Для шаблона 2 имя файла будет: tpl-2.tpl.
Очевидно, что такой подход во многих случаях неудобен. Поэтому файлы можно называть произвольно, а в содержимом шаблона в админке писать: @FILE:main.tpl, @FILE:article.tpl и т.п. Для документа с шаблоном _blank такой вызов можно написать прямо в содержимом документа.

Если файл шаблона не найден, то будет использоваться парсер MODX.

Теперь можно перейти к тому, что в этих шаблонах писать. Как и MODX, Twig использует несколько конструкций для вывода данных:
  • переменные — {{ var_name }}
  • функции — {{ function_name() }}
  • фильтры — {{ var_name | striptags | nl2br }}
  • управляющие элементы (теги) — {% if var_name == 'foo' %}{{ var_name }}{% endif %}
{% %} — такими скобками обозначаются условия, циклы и другие управляющие элементы шаблонизатора, а такие скобки {{ }} используются для вывода.

Разницу между MODX и Twig можно изобразить примерно так:
MODXTwig
[*pagetitle*]{{ resource.pagetitle }}
[+placeholder+]{{ plh.placeholder }}
{{ data.placeholder }} (при обработке чанков DLTemplate)
{{ modx.getPlaceholder('placeholder') }}
[(site_name)]{{ config.site_name }}
[!snippet? &foo=`bar`!]
{{ runSnippet('snippet', {foo:'bar'}) }}
{{chunkname}}{{ getChunk('chunkname') }}
{% include 'chunks/chunkname.tpl' %}
А вот ссылки на страницы можно использовать по-прежнему в стиле MODX: [~3~], то же самое относится и к служебным тегам [^qt^], [^q^], [^p^], [^t^], [^s^], [^m^].

Важное отличие от MODX — в шаблоне Twig переменная может быть чем угодно, не только строкой, а задать переменную можно прямо в шаблоне (в MODX это возможно только с помощью плагинов или сниппетов, которые устанавливают глобальные плейсхолдеры).

Все это подробно изложено в документации, поэтому остановлюсь на особенностях интеграции в Evo.

Переменные
В шаблонах страниц можно использовать переменные:
  • modx — тут понятно и так, объект DocumentParser, соответственно можно использовать все api-функции;
  • documentObject — массив $modx->documentObject, в котором содержится вся информация о документе;
  • resource — упрощенный вариант documentObject, в котором все поля хранятся в виде ключ-значение, включая и tv (resource.pagetitle, resource.longtitle, resource.price, resource['product-color'] — это есть в документации Twig, но еще раз обратите внимание, как происходит обращение к массиву);
  • debug — значение соответствующей настройки плагина;
  • config — массив настроек MODX;
  • plh — массив глобальных плейсхолдеров, которые задаются методом setPlaceholder;
  • ajax — по значению этой переменной можно определить был ли ajax-запрос к текущей странице (проверяется заголовок HTTP_X_REQUESTED_WITH);
  • _GET, _POST, _COOKIE, _SESSION — соответствующие массивы.

Для использования Twig в чанках нужно, для начала, чтобы эти чанки обрабатывались классом DLTemplate. То есть такая возможность есть, как минимум, в DocLister, FormLister и их производных. Чтобы применить к чанку Twig, к префиксу этого чанка нужно дописать T_:

&tpl=`@T_FILE:chunks/product` //загрузит из файла, обратите внимание, что имя файла без расширения; папка с файлами и расширение задаются отдельно
&tpl=`@T_CHUNK:product` //использует обычный MODX-чанк
&tpl=`@T_CODE:<p>{{ data.pagetitle }}</p><img src="{{ data['tv.image'] }}">` //почему-то работает и такое


Какие переменные использовать в чанках, зависит от сниппетов, в которых эти чанки обрабатываются. В первую очередь переменные modx и data.
В DocLister добавится переменная DocLister c объектом контроллера.
В FormLister — аналогичная переменная FormLister, а также errors (массив с данными об ошибках), messages (массив сообщений контроллера), plh (массив плейсхолдеров формы).

Расширения Twig
Twig можно расширять различными способами, поэтому к нему добавлено несколько полезных в Evo расширений.

Фильтр modxParser
Обрабатывает строку парсером MODX.

{{ resource.content | modxParser }}
{{ '[*pagetitle*]' | modxParser }}


Фильтр plural
Предназначен для вывода существительных после числительных. Например, такой код выведет «Осталось 11 часов»:
{{ ['Остался %d час', 'Осталось %d часа', 'Осталось %d часов']|plural(11) }}

А такой — «Осталось 2 часа»:
{{ ['Остался %d час', 'Осталось %d часа', 'Осталось %d часов']|plural(2) }}


Функция makeUrl
Генерирует ссылку на документ. Принимает три аргумента:
  • id документа,
  • массив параметров ссылки,
  • флаг типа ссылки, true — если нужно построить абсолютную ссылку, false — относительную (по умолчанию — true).

{{ makeUrl(2) }}
{{ makeUrl(2, {foo: 'bar'}) }}
{{ makeUrl(2, {}, true) }}
{{ makeUrl(2, {bar: 'foo'}, false) }}


Функция runSnippet
Запускает сниппет. Аргументами являются имя сниппета и массив параметров.

Функции getChunk, parseChunk
Вывод чанка и вывод чанка с обработкой. В первом случае функции передается имя чанка, во втором — имя чанка и массив параметров. В обоих случаях используется класс DLTemplate.

Также подключено расширение, которое позволяет использовать функции PHP, их список задается в соответствующей настройке плагина.

В общем-то добавлять собственные фильтры и функции в Twig несложно, описанные выше расширения простые и их можно использовать как пример. Для добавления расширений лучше всего создать плагин на события OnManagerPageInit, OnWebPageInit, OnPageNotFound и вызывать его после плагина replaceTemplateTwig.

На этом вводная часть закончена, вышеизложенного достаточно для старта, главное не лениться читать документацию. В следующих частях я возьму готовую верстку и покажу как я использую Twig на практике и почему больше не вернусь к парсеру MODX (:

16 комментариев

avatar
Святой Эво, это офигенно! До этого использовал твиг, но конечно же не таким образом. Жду продолжения с нетерпением и с терпением =)
avatar
Большое спасибо за долгожданную статью. Очень познавательно.
Будем пробовать.
С нетерпением жду вторую часть
avatar
Класс!!! Ждём продолжения
avatar
В следующих сериях:
— интеграция верстки;
— кэширование;
— ответы на вопросы, если такие возникнут.
avatar
действительно здорово

really great
avatar
&tpl=`@T_CODE:<p>{{ data.pagetitle }}</p>`
Нужно понимать, что data.pagetitle это тоже самое, что data[«pagetitle»]. Поэтому для доступа к dl.wrap или tv.image например, нужно использовать data[«dl.wrap»]
avatar
Здравствуйте!
А для владельцев виртуального хостинга — нужно ставить Composer for MODX Evolution github.com/AgelxNash/MODXComposer?
avatar
Нет, проще будет поставить evo и все нужное на локальном сервере, а потом скопировать папку vendor.
avatar
при включении twig в doclister отваливается возможность указывать глубину выборки. хоть depth=10 поставь, он просто 10 раз продублирует в запросе выборку родителей первого уровня.
один и тот же вызов сниппета:
с включенным replaceTemplateTwig – yadi.sk/d/sOBaqUIj3TSQB2
с выключенным – yadi.sk/i/uALgAlgM3TSQ5a
Комментарий отредактирован 2018-03-16 12:55:27 пользователем arty
avatar
Исправил.
avatar
Ребята, Fenom ожидается на MODX Evo?
avatar
А что не так с твигом?
avatar
Всё с ним ок, просто очень привык к Fenom'у :)
avatar
Круто! Но без композера не обойтись?
У меня такая херь пишется при установке

  Problem 1
    - doctrine/cache v1.7.1 requires php ~7.1 -> your PHP version (7.0.30) does not satisfy that requirement.
    - doctrine/cache v1.7.0 requires php ~7.1 -> your PHP version (7.0.30) does not satisfy that requirement.
    - doctrine/cache 1.8.x-dev requires php ~7.1 -> your PHP version (7.0.30) does not satisfy that requirement.
    - doctrine/cache 1.7.x-dev requires php ~7.1 -> your PHP version (7.0.30) does not satisfy that requirement.
    - pathologic/evo-twig 1.0.0 requires doctrine/cache ~1.7 -> satisfiable by doctrine/cache[1.7.x-dev, 1.8.x-dev, v1.7.0, v1.7.1].
    - Installation request for pathologic/evo-twig ^1.0 -> satisfiable by pathologic/evo-twig[1.0.0].
avatar
Обновив php до 7.2, установился. Но Twig так и не заработал
avatar
Мой любимый редактор для twig-шаблонов — Codelobster
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.