Twig: Введение. PHP и Twig: создание шаблонов веб страниц Управляющие конструкции: условные операторы и циклы

Аркады 11.07.2023
Аркады

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

Многие PHP фрэймворки, включая: Zend Frameworkd, Agavi, CackPHP и CodeIgniter, по-своему реализуют разделение бизнес логики и вывод данных. Однако, если вы не любите фрэймворки или ваш проект слишком мал для их использования, то вы можете воспользоваться какой-то отдельной системой построения шаблонов. К счастью, нам есть из чего выбирать. Smartym Savant, Dwoo... этот список можно продолжать и продолжать, однако в этой статье я покажу вам, как работать с шаблонизатором Twig.

Установка

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

Основы

Прежде чем приступить непосредственно к делу, давайте разберёмся с принципом работы шаблонизаторов. Обычное PHP приложение состоит из целого набора страниц, которые включают в себя как статический HTML код (меню, списки, изображения и т.д.), так и динамический контент (вывод данных из БД, xml файла, сервисы, …). С помощью Twig мы можем разделить данные процессы, создавая шаблоны со специальными маркерами, вместо которых в последствии будет вставляться динамический контент.

Значения для данных маркеров формируются в основном PHP скрипте; там же происходит общение с базой данных, xml парсинг и другие всевозможные операции. Таким образом, ваша страница будет строиться на основе 2х источников: шаблона с специальными вставками и PHP скриптов, где мы храним основной функционал. Это даёт возможность PHP разработчикам и дизайнерам одновременно работать над одними и теми же страницами.

Приступаем к делу

Для того чтобы посмотреть, как работает Twig, предлагаю рассмотреть простой пример:

Account successfully created!

Hello {{ name }}

Thank you for registering with us. Your account details are as follows:

Username: {{ username }}
Password: {{ password }}

You"ve already been logged in, so go on in and have some fun!

Сохраните данный файл templates/thanks.tmpl. Обратите внимание на то, что все маркеры, представляющие собой переменные, помещены в двойные фигурные скобки. Подобная запись подскажет Twig-у, где и как осуществлять вставку данных.

Затем, нам необходимо создать основной скрипт, где будет происходить формирование переменных и данных:

В результате, если вы откроете данную страницу в браузере, то увидите следующее:

Для использования Twig-а, вам нужно пройти следующие шаги:

  • Инициализировать авто-загрузчик Twig-а, для того чтобы классы шаблонизатора подгружались автоматически.
  • Инициализировать загрузчик шаблонов. В нашем случае эт Twig_Loader_FileSystem. В качестве аргумента передаём путь к каталогу с шаблонами.
  • Создать объект самого Twig и передать ему уже сконфигурированные настройки.
  • Подгрузить нужный нам шаблон с помощью метода loadTemplate, передав в него название используемого шаблона. В качестве результата метод вернёт экземпляр шаблона.
  • Сформировать массив вида "ключ-значение", где ключи - это названия переменных, а значения - данные, выводимые в шаблоне. Затем этот массив нужно передать в метод render(), который совместит шаблон с переданными данными и вернёт сгенерированный результат.
  • Условия

    Twig также предоставляет нам возможность создавать условные выражения ‘if-else-endif’. Пример:

    Odd or Even {% if div == 0 %} {{ num }} is even. {% else %} {{ num }} is odd. {% endif %}

    В зависимости от числа, которое генерируется в основном PHP скрипте, шаблон отобразит одно из двух сообщений. Вот и скрипт, где генерируется число от 0 до 30 и проверяется на чётность:

    а вот и результат:

    Также мы можем сделать многоуровневые проверки ‘if-elseif-else-endif’. Пример:

    Seasons {% if month > 0 and month 3 and month 6 and month 9 and month

    А вот и вывод:

    Циклы

    Twig также поддерживает цикл ‘for’. Он очень удобен, если нам необходимо пройтись по массиву. Пример:

    Shopping list

      {% for item in items %}
    • {{ item }}
    • {% endfor %}

    В данном примере у нас простой не ассоциативный массив. На каждой итерации мы будем получать по одному элементу и выводить его в элементе списка. Вот и скрипт:

    Результат:

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

    Для того чтобы достучаться до значений массива в шаблоне, сначала пишем имя переменной, в которой хранится сам массив. Затем ставим точку и пишем название ключа, по которому достаём данные:

    Book details

    Title {{ book.title }}
    Author {{ book.author }}
    Publisher {{ book.publisher }}
    Pages {{ book.pages }}
    Category {{ book.category }}

    Результат:

    Такой же подход может быть применён для работы с объектами.

    Дамп данных

    Безусловно циклы вам пригодиться при выводе данных из БД. Пример:

    table { border-collapse: collapse; } tr.heading { font-weight: bolder; } td { border: 1px solid black; padding: 0 0.5em; } Countries and capitals

    {% for d in data %} {% endfor %}
    Country Region Population Capital Language
    {{ d.name|escape }} {{ d.region|escape }} {{ d.population|escape }} {{ d.capital|escape }} {{ d.language|escape }}

    В следующем фрагменте кода я использую PDO подключение к MySQL базе данных ‘world’. Если вы хотите попробовать данный пример, то вам нужно сформировать базу самим:

    Тут стоит отметить несколько вещей:

    Мы используем метод getchObject(), который вернёт нам строки из таблицы в виде объектов. Названия полей будут соответствовать названиям колонок. Затем эти объекты мы помещаем в массив и передаём его в шаблон. В шаблоне, используем цикл и выводим данные.

    В данном примере также используется встроенный в Twig фильтр `escape`. По умолчанию данный фильтр пользуется функцией htmlspecialchars() для фильтровки данных. Это неплохая защита от XSS атак.

    Подгрузка шаблонов

    Также в Twig-е есть ещё одна команда - `include`, которая позволяет подключать содержание других шаблонов. Это может пригодиться, когда вы захотите прикрепить к вашим файлам меню, заголовок или подвал.

    Для демонстрации представьте, что данный код - это главный шаблон:

    {% include "primary.tmpl" %} {% include "secondary.tmpl" %} This is the main page content. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. {% include "footer.tmpl" %}

    Все секции данной страницы находятся в отдельных файлах и подключаются сюда с помощью команды `include`. Давайте посмотрим, как выглядят подключаемые файлы:

    {% for item in nav.primary %} {% endfor %}
    {{ item.name|upper }}

      {% for item in nav.secondary %}
    • {{ item.name }}
    • {% endfor %}

    This page licensed under a Creative Commons License. Last updated on: {{ updated }}.

    А вот и главный PHP скрипт:

    Обратите внимание, что нам не нужно загружать все шаблоны функцией loadTemplate. Главное подключить основной шаблон. Каждый мелкий под-шаблон загрузится автоматом. Переменные и значения, переданные в главный шаблон, будут доступны во всех подключаемых шаблонах.

    Результат:

    Фильтрация данных

    В данной статье мы уже затронули тему фильтров. Давайте посмотрим, какие ещё возможности в данной сфере предоставляет нам Twig.

    Давайте рассмотрим, к примеру, фильтр ‘date’. Данный фильтр даёт нам возможность формировать дату и время, используя нативные для PHP маркеры. Пример:

    {{ "now"|date("d M Y h:i") }}
    {{ "now"|date("d/m/y") }}

    Результат:

    Также вы можете воспользоваться фильтрами `upper`, `lower`, `capitalize`, `title` для контроля заглавных и прописных букв:

    {{ "the cow jumped over the moon"|upper }}
    {{ "the cow jumped over the moon"|capitalize }}
    {{ "the cow jumped over the moon"|title }}
    {{ "The Cow jumped over the Moon"|lower }}

    Результат:

    Фильтр `striptags` уберёт из текста все HTML и XML элементы:

    {{ "I said \"Go away!\""|striptags }}

    Результат:

    Фильтр `replace` позволяет быстро и просто заменять какие-то значения в строке на нужные нам. Пример:

    {{ "I want a red boat"|replace({"red" : "yellow", "boat" : "sports car"}) }}

    Результат:

    Вы уже видели фильтр `escape` в действии. В Twig также есть фильтр, который делает абсолютно противоположное действие - `raw`. Его следует использовать только для html кода, который вы считаете 100% безопасным.

    Escaped output: {{ html|escape }}
    Raw output: {{ html|raw }}

    Если же вам нужно применить `escape` к большому блоку кода, то вы можете воспользоваться синтаксисом `autoescape`, передав булево значение true/false для активации и дезактивации фильтрации `escape`. Пример:

    {% autoescape true %} Escaped output: {{ html }}
    {% endautoescape %} {% autoescape false %} Raw output: {{ html }} {% endautoescape %}

    Теперь вы уже больше знаете о Twig-e и можете использовать условия, циклы и фильтры.

    Мы разобрались с конфигами и значениями параметров. Сегодня научимся выводить настройки в браузере. А чтобы не было скучно просто писать 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-код, который эти данные сохранит. Бонусом внедрим уведомления, чтобы пользователь видел, не забыл ли он нажать кнопочку сохранить.

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

    Добавляем шаблонизатор 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

    Рекомендуем почитать

    Наверх