Перейти к основному содержимому

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

Twig предоставляет мощные механизмы для организации и переиспользования шаблонов.

Основные шаблоны и переопределения​

Основные шаблоны поставляются вместе с MMO-DEV WEB и доступны только для чтения на рабочем сайте. Чтобы изменить шаблон сайта или личного кабинета, откройте его в панели управления, выберите стиль и создайте переопределение. Изменения сохраняются только в выбранном стиле и не изменяют исходный шаблон продукта.

После обновления MMO-DEV WEB исходный шаблон может измениться, а ваше переопределение сохранится. Совместимые изменения объединяются автоматически. Если одни и те же строки были изменены и в продукте, и в переопределении, панель управления покажет конфликт для сравнения и ручного объединения. Административные шаблоны изменяются только при разработке продукта.

Наследование (extends)​

Наследование позволяет создать базовый макет и переопределять его части в дочерних шаблонах.

Базовый макет​

Базовый макет
{# @site/layout.html.twig #}
<!DOCTYPE html>
<html lang="{{ mw.lang }}">
<head>
<meta charset="UTF-8">
<title>{% block title %}{{ mw.projectName }}{% endblock %}</title>
{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('css/style.css') }}">
{% endblock %}
</head>
<body>
{% block header %}
{% include '@site/partials/header.html.twig' %}
{% endblock %}

<main>
{% block content %}{% endblock %}
</main>

{% block footer %}
{% include '@site/partials/footer.html.twig' %}
{% endblock %}

{% block javascripts %}
<script src="{{ asset('js/app.js') }}"></script>
{% endblock %}
</body>
</html>

Дочерний шаблон​

Дочерний шаблон
{# @site/pages/news.html.twig #}
{% extends '@site/layout.html.twig' %}

{% block title %}Новости - {{ parent() }}{% endblock %}

{% block stylesheets %}
{{ parent() }}
<link rel="stylesheet" href="{{ asset('css/news.css') }}">
{% endblock %}

{% block content %}
<h1>Новости</h1>
{% for article in news %}
<article>
<h2>{{ article.title }}</h2>
<p>{{ article.summary }}</p>
</article>
{% endfor %}
{% endblock %}

parent()​

Функция parent() возвращает содержимое блока из родительского шаблона:

parent()
{% block sidebar %}
{{ parent() }}
{# Добавляем контент к родительскому, а не заменяем #}
<div class="extra-widget">...</div>
{% endblock %}
совет

Тег {% extends %} должен быть первым тегом в шаблоне. Любой текст до него вызовет ошибку.

Включение шаблонов (include)​

Базовое включение​

Базовое включение
{% include '@common/components/alert.html.twig' %}

{# С передачей дополнительных переменных #}
{% include '@common/components/card.html.twig' with {
title: 'Заголовок',
body: 'Содержимое'
} %}

{# Только указанные переменные (без доступа к контексту родителя) #}
{% include '@common/components/card.html.twig' with {
title: 'Заголовок'
} only %}

Условное включение​

Условное включение
{# Игнорировать ошибку, если шаблон не найден #}
{% include '@site/partials/sidebar.html.twig' ignore missing %}

{# Попробовать несколько шаблонов #}
{% include [
'@site/pages/' ~ page ~ '.html.twig',
'@site/pages/default.html.twig'
] %}

Встроенное включение (embed)​

embed - комбинация include и extends. Позволяет включить шаблон и переопределить его блоки:

Встроенное включение (embed)
{# Компонент @common/components/modal.html.twig #}
<div class="modal">
<div class="modal-header">
{% block header %}Заголовок{% endblock %}
</div>
<div class="modal-body">
{% block body %}{% endblock %}
</div>
<div class="modal-footer">
{% block footer %}
<button class="btn">Закрыть</button>
{% endblock %}
</div>
</div>
Встроенное включение (embed)
{# Использование embed #}
{% embed '@common/components/modal.html.twig' %}
{% block header %}Подтверждение удаления{% endblock %}
{% block body %}
<p>Вы уверены, что хотите удалить этот элемент?</p>
{% endblock %}
{% block footer %}
<button class="btn btn-danger">Удалить</button>
<button class="btn">Отмена</button>
{% endblock %}
{% endembed %}

Горизонтальное переиспользование (use)​

use импортирует блоки из другого шаблона (аналог traits в PHP):

Горизонтальное переиспользование (use)
{# blocks/forms.html.twig #}
{% block input %}
<input type="text" name="{{ name }}" value="{{ value }}">
{% endblock %}

{% block textarea %}
<textarea name="{{ name }}">{{ value }}</textarea>
{% endblock %}
Горизонтальное переиспользование (use)
{# Импорт блоков #}
{% use 'blocks/forms.html.twig' %}

{# Теперь блоки input и textarea доступны #}
{{ block('input') }}

{# Переименование при конфликте имён #}
{% use 'blocks/forms.html.twig' with input as form_input %}

Макросы (macro)​

Макросы - переиспользуемые фрагменты шаблона, аналог функций:

Определение​

Определение
{# @common/macros/forms.html.twig #}
{% macro input(name, value, type, attrs) %}
{% set type = type|default('text') %}
{% set attrs = attrs|default({}) %}
<input type="{{ type }}" name="{{ name }}" value="{{ value }}"
{% for attr, val in attrs %} {{ attr }}="{{ val }}"{% endfor %}
>
{% endmacro %}

{% macro select(name, options, selected) %}
<select name="{{ name }}">
{% for value, label in options %}
<option value="{{ value }}"
{% if value == selected %} selected{% endif %}
>{{ label }}</option>
{% endfor %}
</select>
{% endmacro %}

Импорт и использование​

Импорт и использование
{# Импорт всех макросов #}
{% import '@common/macros/forms.html.twig' as forms %}

{{ forms.input('email', '', 'email', {class: 'form-control', required: 'required'}) }}
{{ forms.select('country', {ru: 'Россия', us: 'США'}, 'ru') }}
Импорт и использование
{# Импорт конкретных макросов #}
{% from '@common/macros/forms.html.twig' import input, select %}

{{ input('username', user.name) }}
{{ select('role', roles, user.role) }}

Макросы в том же файле​

Макросы в том же файле
{# Определение и использование в одном шаблоне #}
{% macro badge(text, type) %}
<span class="badge badge-{{ type|default('info') }}">{{ text }}</span>
{% endmacro %}

{# Вызов через _self (устаревший способ) или import #}
{% import _self as self %}
{{ self.badge('Новинка', 'success') }}

Сводная таблица​

МеханизмНазначениеПереопределение блоков
extendsНаследование макетаДа
includeВставка шаблонаНет
embedВставка с переопределениемДа
useИмпорт блоков (traits)Нет (переименование)
macroПереиспользуемые функцииНет