Twig + Symfony

Шаблонизатор Twig

В мире Symfony принято использовать шаблонизатор Twig. Если ранее вы с такими штуками не сталкивались, то возможно хорошо, что twig будет у вас первым. Вещь удобная и лаконичная, конечно же со своими особенностями и синтаксисом, привыкнуть к которым не составит никаких проблем.

Давайте подключим его с помощью composer require template. После подключения рецепта в структуре фреймворка появилась папка templates, а в ней шаблон base.html.twig, который будет общим для всех страниц нашего проекта. Открываем base.html.twig и видим несколько конструкций вида {% block %}. Таким образом размечаются блоки, которые в дальнейшем вы сможете переопределять благодаря наследованию. Именно переопределять! Создавать новые блоки в дочернем шаблоне запрещено.

Давайте перенесем общие части сайта - шапку и подвал из архива в базовый шаблон, а также подключим стили и скрипты. Ну и начнем с последнего. Располагаться "расходники" будут в папке public нашего проекта. Просто скопируйте css, js, img из архива в данный каталог.


Теперь верстка. Всего будет 5 страниц (шапка и футер одинаковы для всех):

  • - список новостей;
  • - создание новости;
  • - список пользователей;
  • - регистрация;
  • - логин.

Сейчас нам нужно оставить только общие части шаблона, удалив все лишнее (попробуйте сначала сделать все самостоятельно). На текущий момент структура должна иметь следующий вид:

Теперь разместим блоки Twig. Нас интересуют title и body. Обратите внимание на title, в нем указано "Welcome!". Данный текст является "заглушкой" и будет отображен, если в дочерних блоках мы не переопределим заголовок.

Обязательно закрывайте блоки с помощью {% endblock %}.

Стили и скрипты подключим с помощью asset, разумеется предварительно их установив при помощи composer require asset. Далее просто начните вводить имя файла и начнет работать автокомплит плагинов, которые мы ранее установили.

Отлично, сделано! Но сейчас нам нечего выводить, есть только шапка и футер. Давайте создадим шаблон для конкретного поста. Для этого создаем папку post в директории templates, а в post создаем index.html.twig, обязательно унаследовав его от базового шаблона с помощью {% extends 'base.html.twig' %}.

Сырой вариант верстки представляет из себя вырванный из контекста блок "col-md-4" базового шаблона.

Сейчас мы имеем только один статичный пост, который при любых обстоятельствах выведет нам одно и то же. Давайте это исправим. Нужно создать конструкцию, в которой посты будут выводиться динамически, каждый со своим текстом и заголовком. Поможет нам в этом цикл for и конструкция {{ object.value }};

Давайте повторим. Мы создали базовый шаблон base.html.twig, в нем шапка и футер. В index.html.twig мы подключаем его с помощью директивы extends, далее переопределяем блок title для конкретной страницы и блок body. Делаем это с помощью одноименных с базовым шаблоном конструкций {% block title %} и {% block body %}. Напомню, что создавая блоки отличные от родителя - схватите ошибку.

Синтаксические конструкции:

  • {{ переменная }} – в двойных фигурных скобках выводится значение переменной. Обращение к объектам производится через точку, {{ variable.name }} без знака '$'.
    К элементам массива обращаемся стандартно через квадратные скобки {{ variable[name] }}. Если значение представляет из себя строку с дефисом, нужно прибегать к конструкции {{ attribute(variable, ‘first-name’) }}.

  • {% условие %} – вывод условий, циклов, а так же подключение блоков. Из циклов в twig есть только for, и используется он по аналогии js, т.е. пишете {% for post in posts %}. Если требуется ключ – {% for key, post in posts %}.

  • {# комментарий #} – блок комментариев.

Последним шагом осталось протестировать все, что мы сделали. Добавим в метод index нашего единственного контроллера несколько постов:

        
    $posts = [
        'post1' => [
            'title' => '1 Заголовок',
            'body' => 'Тело первого поста'
        ],
        'post2' => [
            'title' => '2 Заголовок',
            'body' => 'Тело второго поста'
        ],
        'post3' => [
            'title' => '3 Заголовок',
            'body' => 'Тело третьего поста'
        ],
    ];
        
    

Теперь передаем в метод render нашего контроллера шаблон index.html.twig и массив с постами. В итоге должно получиться так:

Запускаем сервер, проверяем.


Подключение фильтра "truncate"

В шаблонизаторе Twig по умолчанию присутствует большое количество фильтров, которые так или иначе форматируют представление. Для использования фильтров достаточно поставить символ | после переменной, далее имя фильтра. Например, для преобразования текста в верхний регистр нужно добавить upper - post.body | upper.

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

Установка:

  • - подключаем библиотеку composer require twig/extensions. Как видно, Symfony Flex уже не используется.
  • - регистрируем расширение "text extension" из вышеуказаной библиотеки в сервисах. Для этого переходим в папку config, открываем services.yaml и добавляем туда следующий код:
                        
        services:
            twig.extension.text:
                class: Twig_Extensions_Extension_Text
                tags:
                    - { name: twig.extension }
                        
                    
    Что должно получиться:
  • - применим фильтр к шаблону index.html.twig, изменив post.title, post.body на post.title | truncate(50, true), post.body | truncate(100, true) соответственно. Для проверки работоспособности просто изменим массив $posts в контроллере PostController увеличив длину body до 100+ символов. Проверяем:

Лично у меня возникала ошибка после подключения данного расширения. Решалась проблема с помощью очистки кеша php bin/console cache:clear.