Статьи

Расширение шаблонов веток: наследование, фильтры и функции

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

Ограничения в библиотеках шаблонов

Наиболее распространенным ограничением, которое есть во многих библиотеках шаблонов, является невозможность расширения возможностей шаблона. Например, обычно все ссылки на файлы CSS и JavaScript включаются в верхний или нижний колонтитул страницы, поэтому мы создаем шаблон верхнего колонтитула и включаем этот файл во все наши страницы. Но что, если у нас есть страница, которая должна инициализировать карту Google при загрузке страницы? JavaScript для карты должен вызываться только с этой одной страницы, но многим разработчикам без необходимости включать все файлы JavaScript и CSS в один заголовок.

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

<!DOCTYPE html>
<html>
 <head>
  <link rel="stylesheet" href="style.css">
  <script src="jQuery.js" type="text/javascript"></script>
 </head>

… И шаблон карты может выглядеть так:

 <script src="googlemaps.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
    $("#google_map").google_map();
});
</script>
<div id="google_map"></div>

Общие CSS и JavaScript упоминаются в заголовке, а специфичный для карты код находится внутри шаблона страницы. Хотя это работает, в идеале мы должны хранить все эти ссылки в одном месте для согласованности и чистоты кода, а не разбивать их по разным файлам.

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

Расширение шаблонов веток

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

 <!DOCTYPE html>
<html>
 <head>
  {% block head %} Sample Content {% endblock %}
 </head>
 <body>
 </body>
</html>

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

 {% extends "parent.html" %}
{% block head %} Head 1 {% endblock %}

В дочернем элементе мы расширяем родительский шаблон, используя ключевое слово extends, за которым следует имя файла шаблона. Затем мы переопределяем головной блок, чтобы он содержал динамически расширенный контент. Отказ от блока заголовка в дочернем шаблоне заставит родителя использовать контент, который он уже определил по умолчанию.

Теперь, когда у нас есть общее представление о том, как наследование работает в Twig, давайте создадим более полный макет страницы.

 <!DOCTYPE html>
<html>
 <head>
  {% block head %}
  <link rel="stylesheet" href="style.css">
  <script src="jQuery.js" type="text/javascript"></script>
  {% endblock %}
 </head>
 <body>
  <div id="grid">{% block content %} {% endblock %}</div>
  <div id="info">{% block sidebar %} {% endblock %}</div>
  <div id="footer">
   {% block widget1 %} {% endblock %}
   {% block widget2 %} {% endblock %}
   {% block widget3 %} {% endblock %}
   {% block footer %}
   &copy; 2013 example.com
   {% endblock %}
  </div>
 </body>
</html>

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

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

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

 {% block head %}
{{ parent() }}
<script src="jquery.plugin.js"></script>
{% endblock %}

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

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

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

Роль Twig Filters

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

 {{ "Varible content" | trim() }}

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

Новые фильтры создаются с использованием анонимных функций PHP и класса Twig_SimpleFilter

 <?php
$filter = new Twig_SimpleFilter("highlight", function ($key) {
    switch (trim($key)) {
        case "book_category":
            echo '<span class="books_color">';
            break;
        case "cd_category":
            echo '<span class="cd_color">';
            break;
        case "ebook_category":
            echo '<span class="ebook_color">';
            break;
        default:
            // nothing
    }
});
$twig->addFilter($filter);

Я создал новый фильтр с именем «highlight», а затем добавил его в среду Twig с помощью addFilter() Категория будет передана фильтру как переменная, и внутри функции мы переключаем категорию и выводим элемент с определенным классом CSS для генерации динамического выделения в сетке.

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

 {% block content %}
 {% for product in products %}
  <div>
   {% filter highlight %}
   {{ product.category }}
   {% endfilter %}
   {{ product.product }}
   </span>
  </div>
 {% endfor %}  
{% endblock %}

Роль веток

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

 <?php
$function = new Twig_SimpleFunction("function_name", function ($arg1, $arg2) {
    // implementation
});
$twig->addFunction($function);

Опять же, мы можем использовать анонимные функции для создания динамических функций Twig. Первый параметр класса Twig_SimpleFunction Функция добавляется в среду Twig с помощью addFunction()

Давайте предположим, что мы используем библиотеку для работы с полями формы, такими как текстовые поля, флажки и т. Д. Обычно мы просто пишем необходимый HTML-код прямо в шаблонах, например:

 <input type="text" name="fname" class="chosen">

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

 <?php
$function = new Twig_SimpleFunction("form_text", function ($name, $id, $value = "", $class = "form_text") {
    echo '<input type="text" name="'.$name.'" id="'.$id.'" value="'.$value.'" class="'.$class.'">";
});
$twig->addFunction($function);

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

 {{ form_text("fname", "fname", "", "chosen") }}

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

Резюме

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

Дайте мне знать ваш опыт работы с Twig и ваши мысли о процессе расширения шаблона. В ожидании ответа от вас.

Изображение через Fotolia