Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Twig: макросы, свои фильтры, глобальные переменные

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

Переменные в шаблоне

{% set total = price * quantity %}
<p>Итого: {{ total }}</p>

Тесты и операторы

{% if user is defined and user.name is not empty %}
    {{ user.name }}
{% endif %}
 
{{ post.subtitle ?? 'Без подзаголовка' }}
{{ 'Привет, ' ~ user.name }}
{{ loop.index is even ? 'even' : 'odd' }}

Знак ~ соединяет строки, ?? подставляет значение вместо отсутствующего.

Макросы

Макрос — функция, возвращающая разметку:

{# templates/_macros.html.twig #}
{% macro badge(text, color = 'gray') %}
    <span class="badge badge-{{ color }}">{{ text }}</span>
{% endmacro %}
{% import '_macros.html.twig' as ui %}
 
{{ ui.badge('Новое', 'green') }}
{{ ui.badge('Черновик') }}

Свой фильтр

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

// src/Twig/AppExtension.php
namespace App\Twig;
 
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
 
class AppExtension extends AbstractExtension
{
    public function getFilters(): array
    {
        return [
            new TwigFilter('price', $this->formatPrice(...)),
        ];
    }
 
    public function formatPrice(float $amount): string
    {
        return number_format($amount, 2, ',', ' ') . ' ₽';
    }
}
{{ product.price|price }}

Регистрировать класс не нужно: Symfony находит расширения сам. Функции добавляют так же — методом getFunctions() и классом TwigFunction.

Глобальные переменные

Значения, нужные во всех шаблонах, задают в настройках:

# config/packages/twig.yaml
twig:
    globals:
        site_name: 'Мой блог'
        support_email: 'help@example.com'
<footer>{{ site_name }} · {{ support_email }}</footer>

Встроенная переменная app уже содержит полезное: app.user, app.request, app.session, app.environment.

Встраивание контроллера

Блоку «Последние статьи» в боковой колонке нужны данные на каждой странице. Чтобы не передавать их из каждого контроллера, блок выводят отдельным запросом внутри шаблона:

<aside>
    {{ render(controller('App\\Controller\\SidebarController::recent', {limit: 5})) }}
</aside>

Отладка

{{ dump(post) }}

dump() показывает содержимое переменной. Без аргументов — все переменные шаблона.

Частая ошибка

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

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.