Что такое шаблонизатор Twig и зачем он нужен? PHP и Twig: создание шаблонов веб страниц Как вывести в шаблоне значение пользовательского поля заказа.


В этой статье рассмотрим Twig теги - конструкции шаблонизатора, которые выполняют разнообразные задачи, такие как: условные операторы, циклы, экранирование данных, создание макросов, использование наследования шаблонов, запись в переменные и многое другое. В общем виде они записываются с помощью открывающего тега и закрывающего (именуется префиксом end). Закрывающий тег нужен не для всех конструкций. Пример абстрактного тега выглядит так:

{% tag %} {% endtag %}

Управляющие конструкции: условные операторы и циклы Тег if

Тег if в Twig сравним с условным оператором if в PHP. В простейшей форме вы можете использовать его, чтобы проверить выражение на истинность:

{% if label_display == "after" %} {{ label }} {% endif %}

Вы также можете проверить массив или строку на существование:

{% if page.footer_fifth %} {{ page.footer_fifth }} {% endif %}

Twig шаблонизатор предполагает дополнительные проверки в условиях:

empty - проверяет, является ли переменная пустой:

{# возвращает true, если переменная foo равна null, false, пустой массив, или пустая строка #} {% if foo is empty %} ... {% endif %} {# возможен вариант с оператором отрицания not #} {% if foo is not empty %} ... {% endif %}

even и odd - возвращает true если данное число является четным или нечетным, соответственно:

{{ if var is even }} ... {% endif %} {{ if var is odd }} ... {% endif %}

iterable - проверяет, является ли переменная массивом или объектом (экземпляром класса, имплементирующего интерфейс Traversable):

{% if users is iterable %} {% for user in users %} Hello {{ user.name }}! {% endfor %} {% else %} {# users вероятно являетcя строкой #} Hello {{ users }}! {% endif %}

null - возвращает true, если переменная равна NULL :

{{ if var is null }} ... {% endif %}

constant - проверяет, имеет ли переменная точно такое же значение, как константа. Вы можете использовать либо глобальные константы, либо константы класса:

{% if status is constant("MARK_NEW") %} {{ "New"|t }} {% elseif status is constant("MARK_UPDATED") %} {{ "Updated"|t }} {% endif %}

divisible - проверяет, делится ли переменная на число:

{% if loop.index is divisible by(3) %} ... {% endif %}

same as - проверяет, указывают ли две переменные на одну ячейку памяти. Аналогичен оператору эквивалентности === в php:

{% if foo.attribute is same as(false) %} foo.attribute эквивалентен значению "false" {% endif %}

defined - проверяет, определена ли переменная:

{# defined работает как с именами переменных #} {% if foo is defined %} ... {% endif %} {# так и с атрибутами переменных #} {% if foo.bar is defined %} ... {% endif %} {% if foo["bar"] is defined %} ... {% endif %}

В условиях можно использовать логические операторы and, or, not:

{% if not page %} {% if foo and bar %} {% if foo or bar %} {# Возможны и сложные составные условия #} {% if (a and b) or (c and d) %}

В условиях имеется возможность использовать регулярные выражения

{% if phone matches "/^[\\d\\.]+$/" %} {% endif %}

Можно также проверить, начинается ли или заканчивается строка с определенного символа:

{% if "Drupal" starts with "D" %} {% endif %} {% if "Drupal" ends with "l" %} {% endif %}

Также вы можете использовать более сложные выражения if-elseif (кстати switch-case в Twig отсутствует ):

{% if rows %} {{ rows }} {% elseif empty %} {{ empty }} {% else %} else output {% endif %}

Тег for

Тег for аналогичен конструкции for в php и осуществляет "перебор" элементов массива или свойств объекта, если объект является экземпляром класса, имплементирующего Traversable интерфейс.

В качестве примера рассмотрим шаблон поля и в нем перебор множественных значений поля:

{% for item in items %} {{ item.content }} {% endfor %}

Переменные, доступные внутри цикла:

  • loop.index - Текущая итерация цикла (начинается с 1)
  • loop.index0 - Текущая итерация цикла (начинается с 0)
  • loop.revindex - Количество итераций с конца цикла (начинается с 1)
  • loop.revindex0 - Количество итераций с конца цикла (начинается с 0)
  • loop.first - Флаг равный True, если текущая итерация является первой
  • loop.last - Флаг равный True, если текущая итерация является последней
  • loop.length - Количество элементов в последовательности
  • loop.parent - Родительский контекст (используется для вложенных циклов)

В отличие от PHP нельзя прервать или продолжить цикл (continue и break). Однако можно создавать правила, позволяющие пропускать элементы по условиям for-if . В примере ниже неактивные пользователи пропускаются в итерациях:

    {% for user in users if user.status %}
  • {{ user.name }}
  • {% endfor %}

Также в Twig возможна конструкция for-else для выполнения действий, если массив или объект оказался пустым:

    {% for user in users %}
  • {{ user.name }}
  • {% else %}
  • {{ no_found|t }}
  • {% endfor %}

В Twig также возможны итерации с перебором и ключей, и значений

{% for key, value in values %}

  • {{ key }}: {{ value }}
  • {% endfor %}

    Наследование шаблонов в Twig

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

    Тег extends

    Рассмотрим использование наследования и тега extends на примере шаблона для блока block.html.twig и его дочерних шаблонов. Базовый родительский шаблон блока содержит код в упрощенном виде:

    {{ title_prefix }} {% if label %} {{ label }} {% endif %} {{ title_suffix }} {% block content %} {{ content }} {% endblock %}

    В шаблоне прописан код, который будет выводиться и в дочерних шаблонах. Содержимое шаблона, которое доступно для переопределения в дочерних шаблонах находится внутри тегов block. У каждой секции block имеется свое имя, которое будет использовано при переопределении. В данном примере есть только один блок с именем content. Весь код вне тегов block будет выведен как есть и его переопределить уже нельзя. Если в дочернем шаблоне вывод блока не будет переопределен, то код блока будет взят из базового шаблона. В качестве дочернего шаблона рассмотрим шаблон для блока с вкладками (в Drupal 8 они вынесены в отдельный блок) block--local-tasks-block.html.twig:

    {# Будет унаследован block.html.twig из текущей темы #} {% extends "block.html.twig" %} {% block content %} {% if content %} {{ content }} {% endif %} {% endblock %}

    Наследовать шаблоны можно также из модулей и других тем:

    {# Будет унаследован block.html.twig из модуля block (core/modules/block/templates/block.html.twig) #} {% extends "@block/block.html.twig" %} {# Будет унаследован block.html.twig из темы classy из каталога block/ (core/themes/classy/templates/block/block.html.twig) #} {% extends "@classy/block/block.html.twig" %}

    При переопределении блока родительского шаблона, содержимое из родительского блока перезаписывается, но если в блоке нужно выводить содержимое родительского блока, то используется Twig функция parent()

    {% block content %} Header ... {{ parent() }} {# Выведет содержимое родительского блока #} {% endblock %}

    Тег block

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

    Макросы в Twig

    Макросы можно сравнить с функциями в языках программирования. Они нужны для многократного использования часто используемых частей html кода и при этом макросы могут принимать параметры, что позволяет динамически изменять вставляемый код. Статический же блок с html кодом можно сохранить с помощью тега set. Макросы отличаются от php функций следующими особенностями:

    • аргументы по умолчанию в макросах задаются внутри тела макроса;
    • аргументы в макросах всегда являются опциональными (необязательными);
    • если в макрос передается больше аргументов, чем описано параметров, то все они будут содержаться в переменной varargs.

    Как и php функции макросы не имеют доступа к глобальным переменным шаблона. Для передачи переменных из шаблона при необходимости нужно использовать специальная переменную _context.

    Тег macro

    Тег macro определяет новый макрос. В качестве простейшего примера рассмотрим макрос, который рендерит элемент формы input, при этом input type, name, value, size макрос содержит в качестве параметров (type и size задаются по умолчанию):

    {% endmacro %}

    {# Импортируем макросы из forms.html.twig в текущий шаблон #} {% import "forms.html" as forms %} {# Вызываем макрос #}

    {{ forms.input("username") }}

    Если макрос определен и используется в одном и том же шаблоне, то для его импорта используется специальная переменная _self.

    {% import _self as forms %}

    {{ forms.input("username") }}

    Если нужно использовать макрос в другом макросе, но в том же самом шаблоне, то макрос импортируется локально внутри другого макроса:

    {% macro input(name, value, type, size) %} {% endmacro %} {% macro wrapped_input(name, value, type, size) %} {% import _self as forms %} {{ forms.input(name, value, type, size) }} {% endmacro %}

    В Drupal 8 в шаблоне menu.html.twig макрос menu_links() определяется и используется в одном и том же шаблоне и дополнительно сам макрос используется рекурсивно внутри самого себя для вывода вложенных пунктов меню:

    {% import _self as menus %} {{ menus.menu_links(items, attributes, 0) }} {% macro menu_links(items, attributes, menu_level) %} {% import _self as menus %} {% if items %} {% if menu_level == 0 %} {% else %}

      {% endif %} {% for item in items %} {{ link(item.title, item.url) }} {% if item.below %} {{ menus.menu_links(item.below, attributes, menu_level + 1) }} {% endif %} {% endfor %}
    {% endif %} {% endmacro %}

    Тег import

    Тег import импортирует все макросы из указанного шаблона:

    {# forms.html.twig #} {# Описываем макрос input() #} {% macro input(name, value, type, size) %} {% endmacro %} {# Описываем макрос textarea() #} {% macro textarea(name, value, rows, cols) %} {{ value|e }} {% endmacro %} {# Импортируем в другой шаблон макросы из forms.html.twig #} {% import "forms.html" as forms %} Username {{ forms.input("username") }} Password {{ forms.input("password", null, "password") }}

    {{ forms.textarea("comment") }}

    Тег from

    Тег from импортирует только указанные макросы из шаблона:

    {# Импортируем из forms.html.twig макросы: input() с алиасом input_field и textarea() #} {% from "forms.html" import input as input_field, textarea %} Username {{ input_field("username") }} Password {{ input_field("password", "", "password") }}

    {{ textarea("comment") }}

    Тег include

    Тег include включает в себя имя шаблона и возвращает отображаемое содержимое этого файла в текущий шаблон. Все переменные текущего шаблона будут доступны в подключаемых шаблонах. С помощью include можно некоторые блоки кода вынести в отдельные шаблоны:

    {# header.html.twig #} {{ header }} {# footer.html.twig #} {{ footer }} {# page.html.twig - available variables: header, footer #} {% include "header.html" %} Body {% include "footer.html" %} {# Результат: Header Body Footer #}

    Можно добавить дополнительные переменные, передавая их после with:

    {# template.html.twig будет иметь доступ к переменным из контекста текущего шаблона и добавленным переменным #} {% include "template.html" with {"foo": "bar"} %} {% set vars = {"foo": "bar"} %} {% include "template.html" with vars %} {# Можно также добавлять несколько переменных #} {% include "template.html" with {"foo": var1, "bar" : var2} %} {# Будут доступны в template.html.twig переменные foo и bar #}

    Или можно отключить доступ к контексту путем добавления only.

    {# Только foo переменная будет доступна в template.html.twig #} {% include "template.html" with {"foo": "bar"} only %} {# В template.html.twig доступа к переменным не будет #} {% include "template.html" only %}

    Вы можете отменить include при помощи инструкции ignore missing, и тогда Twig будет игнорировать подключение несуществующего шаблона. Размещается инструкция ignore missing сразу за именем шаблона:

    {% include "sidebar.html" ignore missing %} {% include "sidebar.html" ignore missing with {"foo": "bar"} %} {% include "sidebar.html" ignore missing only %}

    Можно предоставить и список шаблонов, которые проверяются на предмет существования до включения.

    {% include ["page_detailed.html", "page.html"] %} {% include ["special_sidebar.html", "sidebar.html"] ignore missing %}

    Пример использования include в Drupal 8 можно посмотреть в шаблоне темы Classy links--node.html.twig:

    {% if links %} {% include "links.html.twig" %} {% endif %} {# В подключаемом шаблоне links.html.twig доступны все переменные из links--node.html.twig #}

    Тег set

    Внутри шаблонов можно создавать переменные с помощью тега set:

    {# Записываем в переменную строку #} {% set foo = "foo" %} {# Записываем в переменную массив #} {% set foo = %} {# Записываем в переменную ассоциативный массив #} {% set foo = {"foo": "bar"} %} {# символ ~ осуществляет конкатенацию строк #} {% set foo = "foo" ~ "bar" %} {# Результат: foo содержит "foobar" #} {% set foo, bar = "foo", "bar" %} {# Создано две переменных foo и bar #}

    С помощью тега set в переменную можно записать блок кода:

    {% set foo %} ... {% endset %}

    Тег spaceless

    Тег spaceless можно использовать для удаления пробелов между HTML-тегами, а также содержимого внутри HTML-тегов или пробелов в простом тексте:

    {% spaceless %} foo {% endspaceless %} {# Результат: foo #}

    Тег autoescape

    В зависимости от того, включено или нет автоматическое экранирование, вы можете отметить фрагмент шаблона для экранирования или же отключить эту функцию, используя тег autoescape (в Drupal 8 автоэкранирование включено в контексте html):

    {% autoescape %} Автоэкранирование в этом блоке осуществляется методами HTML. {% endautoescape %} {% autoescape "html" %} Автоэкранирование в этом блоке осуществляется методами HTML. {% endautoescape %} {% autoescape "js" %} Автоэкранирование в этом блоке осуществляется методами js. {% endautoescape %} {% autoescape false %} Автоэкранирование отключено. Содержимое блока выводится без изменений. {% endautoescape %}

    Тег verbatim

    Тег verbatim маркирует секцию и сообщает шаблонизатору не обрабатывать содержимое блока:

    {% verbatim %}

      {% for item in items %}
    • {{ item }}
    • {% endfor %}
    {% endverbatim %} {# Результат:
      {% for item in items %}
    • {{ item }}
    • {% endfor %}
    #}

    Тег filter

    Тег filter позволяет применять стандартные фильтры шаблонизатора Twig для блоков данных шаблонов. Просто разместите код внутри секции "filter":

    {% filter upper %} Drupal 8 {% endfilter %} {# Результат: "DRUPAL 8" #}

    Можно также создавать комбинации фильтров:

    {% filter lower|escape %} SOME TEXT {% endfilter %} {# Результат: "some text" #}

    Если в теге используется фильтры escape или e, то drupal их заменит на свой фильтр drupal_escape .

    Тег do

    Тег do работает так же, как стандартное выражение с переменной {{ var }} , с той разницей, что ничего не выводится. На практике применим, если нужно вызвать функцию или метод объекта, которые что либо могут возвращать или выводить, но в выводе шаблона эти данные не нужны отображать.

    {% do 1 + 2 %} {% do product.delete() %}

    Тег trans

    Тег trans специфичен для Drupal 8. Этот тег позволяет переводить текст (используя токены) внутри тега используя функцию t() или TranslationManager::formatPlural() , если внутри тега использована конструкция {% plural ... %} :

    Мы разобрались с конфигами и значениями параметров. Сегодня научимся выводить настройки в браузере. А чтобы не было скучно просто писать html, подключим к проекту шаблонизатор Twig. Ему и будет посвящена основная часть статьи.

    У Twiga отличный функционал и простой синтаксис. В дебри лезть не будем, нам хватит и малой части его возможностей. Начинаем.

    Подключаем Twig и рендерим первый шаблон.

    Хотел скачать последнюю версию twig-a 2.x, но обломался. Он ставится через composer, а я в нем не шарю. Подозреваю, что composer мало чем отличается от фронтовых npm или bower, но погружаться сейчас не будем. Кто в теме, сделают composer require "twig/twig:^2.0" и без меня, а я как нормальный php-шник скачиваю версию 1.x через Download zip и не парюсь. Качать отсюда https://github.com/twigphp/Twig/tree/1.x

    Ищем твигу местечко в проекте. Создадим папку admin/lib/Twig и закинем туда библиотеку. Идеально, смогли и без composer-a.

    Идем дальше. Твигу нужна папка cache, куда он может свободно записывать отрендеренные шаблоны. Дискуссионный вопрос, куда определяют папку кэша нормальные пацаны? Я без фантазии создал прямо в admin - admin/cache. Ну и бог с ней. Главное, убедитесь, что в нее разрешена запись юзеру www-data. Если сидите на винде, то пофиг. А если нет, то смените владельца и дайте права на запись в cache

    $ sudo chown -R www-data:www-data ./cache $ sudo chmod -R 755 ./cache/

    Последнее, что нужно твигу - знать, где брать шаблоны. Для этого сделаем папку admin/templates и закинем в нее index.html c содержимым Hello, {{name}} . Ага, уже постигаем магию. Значение name будет передаваться в шаблон извне, из php-файла.

    Давайте в admin/index.php подключим twig и отрендерим шаблон. Испокон веков автор фигачил разметку в index.php, а сейчас нет. Повзрослел. php-файл займется тем, чем и должен - логикой приложения. Даже звучит приятно, значит, пора реализовывать.

    // Подключаем шаблонизатор require_once "./lib/Twig/Autoloader.php"; // Инициализируем Twig Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem("./templates"); $twig = new Twig_Environment($loader, array("cache" => "./cache", "debug" => true)); // Рендерим шаблон echo $twig->render("index.html", array("name" => "Twig"));

    В первой строке подключаем сам твиг. Дальше инициализация. В документации я прочитал, если возникнет Непредвиденный Случай и почему-то НЕ СРАБОТАЕТ, то напишите Twig_Autoloader::register();
    Я человек-удача и тот самый случай поймал. Написал, что велено, и все стало хорошо. Надеюсь, Вам повезет больше и вместо 10 строк уложитесь в 9.

    Дальше в $loader и $twig загружаем среду или что-то такое нужное для шаблонизатора. Указываем в параметрах путь к папкам шаблонов и кеша и важный параметр debug=true. На боевом сайте debug убирайте, но пока оставьте. Иначе при изменении шаблона в templates/index.html твигу будет наплевать и он сразу возьмет срендеренный из кэша. И будем удивляться, чо это шаблон правим, а в браузере не меняется.

    Итак, обновим страницу и видим текст Hello, Twig . Поздравляю, наш первый шаблон отработал. Но прежде чем наполнять его полезным содержимым, немного изменим index.php. А точнее подключим класс админки и в шаблон отдадим не name=Twig, а настройки. Получится вот так.

    // Подключаем шаблонизатор и класс админки require_once "./lib/Twig/Autoloader.php"; require_once "./admin.class.php"; // Инициализируем Twig Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem("./templates"); $twig = new Twig_Environment($loader, array("cache" => "./cache", "debug" => true)); // Создаем объект админки $admin = new Admin(); // Рендерим шаблон echo $twig->render("index.html", array("settings" => $admin->getSettings()));

    Редактируем шаблон.

    В предыдущей статье засветился прототип. На него и ориентируемся. Нам понадобится заготовка html-документа и простая форма с названиями параметров и значениями.

    Конечно, форма будет на bootstrap. Однажды я раздуплюсь и покажу какой-нибудь другой css-фреймворк, но пока лень. Оправдываю себя тем, что мы же с вами не css-ы верстаем, а ПРИЛОЖЕНИЯ ПРОГРАММИРУЕМ. Пока отмазка работает, возвращаемся к шаблону.

    Заготовку беру с сайта bootstrap. В head скопипастим такое

    А body придется писать самим.

    Выглядит как обычная бутстраповская форма, но с твиговскими вставками.
    Разберем по очереди.

    {% for item in settings %}

    Перебираем в цикле настройки и для каждой выводим label и input в форме.

    item.key используется и как айди, и как название name инпута, и как значение for в label. Такой важный нужный key.
    item.title - заголовок настройки.

    А это текстовое поле со значением.

    Теперь обновляем страницу и видим список настроек с нужными значениями. Красота! Поменяйте значения полей в config/values.json. Работает, опять красота.

    На этом позитивном предложении автор закончил бы статью, но нельзя. Потому что внимательный читатель скажет: стоп, а картиночка-то не та! С прототипом не сходится. А любознательный читатель еще и спросит: а зачем в первом уроке столько мутили с конфигами и разными типами данных? Чтобы сейчас выводить их тупо в инпуты? Конечно, читатель прав. Поэтому автор сходит выпить чаю и напишет еще пару абзацев.

    Итак, продолжаем. Мы хотим выводить разные инпуты-селекты в зависимости от типа найстройки. В этом помогут условия twig и поле type из конфига настроек. В наличии 4 типа настроек: text, number, checkbox и select. Под каждую из них делаем условие. Вместо

    пишем так

    {% if item.type == "text" %} {% endif %} {% if item.type == "number" %} {% endif %} {% if item.type == "checkbox" %}

    {% endif %} {% if item.type == "select" %} {% for option in item.list %} {{ option }} {% endfor %} {% endif %}

    Вроде прям много и развесисто, но посмотрим ближе и станет яснее.

  • текстовый инпут просто обернули в условие item.type == "text"
  • number - тот же инпут, только с type="number"
  • для checkbox отдельная верстка. Логично, чекбокс же, не просто инпут.
    Не забываем про атрибут checked, который ставится в зависимости от item.value (true или false).
    Интересно, что у самого чекбокса нет атрибута name со значением item.key. Зато name есть у скрытого инпута рядом с чекбоксом.
    Спойлер: так удобнее для отправки формы на бекенд, в следующей статье убедимся.
  • у select-а есть цикл, потому что выводим список возможных значений из поля item.list
  • Теперь еще раз обновим страницу. У меня получилось так

    Вот теперь все. Можно поиграть с настройками и значениями в json-файлах и посмотреть, как оно успешно раскидывается по формочке.

    Если прониклись твигом и хотите узнать больше, то вот документация на русском. https://x-twig.ru/intro/

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

    Небольшой опрос напоследок и до встречи!

    На сегодняшний день существует большое количество способов осуществить вывод на html страницу. Всё чаще и чаще для этих целей веб разработчики пользуются так называемыми шаблонизаторами. Сегодня мы рассмотрим небольшой пример использования шаблонизатора Twig.

    Особенности Twig
    • феноменально быстрая скорость работы (в сравнении с другими шаблонизаторами)
    • компиляция шаблонов в хорошо оптимизированный PHP код
    • применение “наследования” (можно определить базовый и дочерние шаблоны)
    • позволяет создавать и использовать макросы
    Установка

    Существует множество способов установки Twig-a. Самый простой и быстрый - это скачивание компонента с GitHub , после чего архив необходимо распаковать, и перекинуть каталог lib в папку с нашим проектом.

    Структура проекта

    Ну а теперь давайте приступим к делу и рассмотрим структуру нашего небольшого проекта:

    • compilation_cache
    • lib
      • Twig
    • templates
      • base.html
      • books.html
    • index.php

    Весь функционал, связанный с подключением и настройкой Twig-а, содержится в файле index.php .

    В папке templates мы будем хранить файлы шаблонов. В нашем случае, этих файлов 2: base.html с базовым html кодом и books.html с выводом списка книг.

    В каталоге compilation_cache будут помещаться PHP файлы, созданные Twig-ом для работы.

    Подключение и базовая конфигурация Twig-a

    Итак, первое что нам необходимо сделать, так это подключить Twig:

    Require_once "lib/Twig/Autoloader.php"; Twig_Autoloader::register();

    После этого сообщаем шаблонизатору, где у нас хранятся файлы шаблонов. В качестве аргумента передаём путь к каталогу templates :

    $loader = new Twig_Loader_Filesystem("templates");

    Затем создаём объект шаблонизатора и указываем ещё несколько опций:

    $twig = new Twig_Environment($loader, array("cache" => "compilation_cache", "auto_reload" => true));

    Параметру cache передаём путь к каталогу compilation_cache . Активируем опцию auto_reload, для того чтобы при обновлении страницы Twig заново обрабатывал шаблоны, и мы видели изменения. Если этого не сделать, то шаблонизатор просто закэширует страницы. Когда же работа над проектом будет завершена, эту опцию можно убрать, чтобы ваши страницы закэшировались и грузились ещё быстрее.

    Данные

    Для реализации нашего небольшого примера, возьмём список книг и сформируем массив вида ключ - значение:

    $books = array(array("number" => "Книга 1", "title" => "Гарри Поттер и философский камень", "date" => "30.06.1997"), array("number" => "Книга 2", "title" => "Гарри Поттер и Тайная комната", "date" => "2.07.1998"), array("number" => "Книга 3", "title" => "Гарри Поттер и узник Азкабана", "date" => "8.07.1999"), array("number" => "Книга 4", "title" => "Гарри Поттер и Кубок огня", "date" => "8.07.2000"), array("number" => "Книга 5", "title" => "Гарри Поттер и Орден Феникса", "date" => "21.07.2003"), array("number" => "Книга 6", "title" => "Гарри Поттер и Принц-полукровка", "date" => "16.07.2005"), array("number" => "Книга 7", "title" => "Гарри Поттер и Дары Смерти", "date" => "21.07.2007"));

    Загрузка файла и передача данных

    Для того чтобы передать данные в какой-то шаблон и вывести html результат, нам необходимо воспользоваться методом render(); В качестве первого аргумента передаём название файла шаблона, который будем выводить. В качестве второго -массив вида ключ - значение. В дальнейшем по заданным ключам мы будем получать доступ к нашим данным в самих шаблонах.

    Echo $twig->render("books.html", array("books" => $books));

    index.php

    Общий вид файла index.php

    Require_once "lib/Twig/Autoloader.php"; Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem("templates"); $twig = new Twig_Environment($loader, array("cache" => "compilation_cache", "auto_reload" => true)); $books = array(array("number" => "Книга 1", "title" => "Гарри Поттер и философский камень", "date" => "30.06.1997"), array("number" => "Книга 2", "title" => "Гарри Поттер и Тайная комната", "date" => "2.07.1998"), array("number" => "Книга 3", "title" => "Гарри Поттер и узник Азкабана", "date" => "8.07.1999"), array("number" => "Книга 4", "title" => "Гарри Поттер и Кубок огня", "date" => "8.07.2000"), array("number" => "Книга 5", "title" => "Гарри Поттер и Орден Феникса", "date" => "21.07.2003"), array("number" => "Книга 6", "title" => "Гарри Поттер и Принц-полукровка", "date" => "16.07.2005"), array("number" => "Книга 7", "title" => "Гарри Поттер и Дары Смерти", "date" => "21.07.2007")); echo $twig->render("books.html", array("books" => $books));

    Настройка базового шаблона

    Базовый шаблон представляет собой обычный html документ со специальными вставками:

    {% block title %}{% endblock %} {% block content %} {% endblock %}

    В нашем главном шаблоне мы прописываем 2 блока: title и content. Названия блоков выбираем сами.

    В последствии, в эти общие блоки мы будем внедрять характерную для дочерних страниц информацию.

    Настройка шаблона вывода книг

    Для начала в дочернем шаблоне нам необходимо указать шаблон родителя:

    {% block title %}Серия романов о Гарри Поттере{% endblock %}

    Затем, пишем содержание, которое внедрится в блок под названием content в базовом шаблоне:

    {% block content %} Серия романов о Гарри Поттере {% for book in books %} {{book.number}}. "{{book.title}}" - {{book.date}} {% endfor %} {% endblock %}

    Тут же в цикле for (Twig for) мы проходимся по всем книгам, которые передали в данный шаблон с помощью записи $twig->render("books.html", array("books" => $books)); и для извлечения значений обращаемся к элементам массива по ключам: {{book.number}}, {{book.title}} и так далее.

    Таким образом, после срабатывания метода $twig->render("books.html", array("books" => $books)) , Twig подгрузит шаблон books.html и сформирует html содержание. Далее он распознает, что books.html - это дочерний шаблон base.html, и поместит сформированное содержание в базовый шаблон. После всего этого Twig вернёт нам полноценную html страницу.

    Итог

    Пример работы данного скрипта вы можете посмотреть в demo или скачать архив с готовым примером.

    Ждём впечатлений в комментариях. Если вас заинтересовала данная тема, то в дальнейшем мы продолжим разговор о шаблонизаторе Twig.

    Добавляем шаблонизатор Twig как плагин для WordPress.
    Возможно, многие из вас сейчас крутят у веска пальцем и задаются вопросом – «Зачем это нужно?», и возможно вполне правы, наверняка это весьма сумасшедшая идея, но я все же скажу – «а почему бы и нет?».

    Для начала познакомимся с Twig. Что это такое? – Twig это PHP шаблонизатор нового поколения, написанный Fabien Potencier, создателем фреймворка Symfony, в последней версии которого он как раз используется.

    Как говорится на официальном сайте, данного чуда:

    Быстрый – Twig компилирует шаблоны и при желании складывает их в Кеш, при этом скомпилированный PHP код полностью соответствует ООП, оптимизирован и скорость его последующей работы равна скорости работы обычного PHP кода.

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

    Гибкий – Twig оснащен гибким лексическим и синтаксическим анализатором кода, это позволяет разработчику определять собственные пользовательские теги и фильтры.

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

    Думаю предельно понятно почему я решил использовать именно твиг в качестве шаблонизатора для CMS WordPress, кроме всего это будет способствовать организации кода в шаблоне. Но главной причиной можно считать любопытство и интерес к данной задумке, удовлетворение не преодолимого желания привинтить твиг к своему блогу.

    Я не очень люблю смешивать HTML и PHP теги, по этому в самописных проектах я предпочитаю использовать паттерн MVC, но в данном случаи такой возможности нет. Поэтому, после долгих размышлений, о том как реализовать мою идею, было принято решение написать плагин, который будет обеспечивать все необходимые задачи и позволит использовать twig.

    Сначала я создал папку с именем плагина wp_twig_engine, затем в неё копируем папку Lib шаблозатора, скачать шаблонизатор с офф. сайта , таким образом, мы превратили весь набор скриптов твига в плагин для WP.

    Затем создаем главный файл плагина: WP-twig.php, с содержимым

    Просмотр кода PHP

    Просмотр кода PHP