Русскоязычная документация по Twig - PHP шаблонизатору. Руководство по Твиг на русском языке
Тег extends используется для наследования шаблонов.
Примечание: Как и в PHP Twig не допускает множественного наследования. Однако, Twig поддерживает горизонтальное use.
Давайте определим базовый шаблон, base.html, для простой страницы с двумя колонками:
<!DOCTYPE html>
<html>
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
<title>{% block title %}{% endblock %} - Мой сайт</title>
{% endblock %}
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
<div id="footer">
{% block footer %}
© Copyright 2013 <a href="http://example.com/">Вы</a>.
{% endblock %}
</div>
</body>
</html>
В этом примере тегом the block определяется 4 блока, которые мы и заменим. Все теги block сообщат шаблонизатору, что в последствии их можно будет переопределить
Дочерний шаблон может выглядеть так:
{% extends "base.html" %}
{% block title %}Главная{% endblock %}
{% block head %}
{{ parent() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Главная</h1>
<p class="important">
Приветсвую на своем потрясном сайте!
</p>
{% endblock %}
Тег extends здесь ключевой, он сообщает шаблонизатору кто "родитель" шаблона и существует ли он. Когда шаблон обрабаотывается, сначала обрабаотывается родительский. Тег наследования extends должен быть первым в шаблоне.
Следует учесть, что так как блок footer не определен, то используется родительский
Вы можете постоянно переопределять block блоком с таким же именем. Такие преобразования возможны потому что блоки работают в обоих направлениях.
Если вы хотите вывести блок несколько раз, вы можете использовать функцию block:
<title>{% block title %}{% endblock %}</title>
<h1>{{ block('title') }}</h1>
{% block body %}{% endblock %}
Возможно отображать значение родительского блока, используя функцию parent:
{% block sidebar %}
<h3>Заголовок</h3>
{{ parent() }}
{% endblock %}
Twig позволяет указывать какой именно блок стоит закрыть:
{% block sidebar %}
{% block inner_sidebar %}
...
{% endblock inner_sidebar %}
{% endblock sidebar %}
Конечно после тега endblock слово должно содержать название блока.
Блоки могут быть вложены друг в друга. По умолчанию блоки имеют доступ к переменным других областей видимости
{% for item in seq %}
<li>{% block loop_item %}{{ item }}{% endblock %}</li>
{% endfor %}
Для блоков с небольшим содержимым можно использовать сокращения. Следующие конструкции одинаковы:
{% block title %}
{{ page_title|title }}
{% endblock %}
{% block title page_title|title %}
Twig поддерживает динамическое наследование, используя переменную в качестве названия:
{% extends some_var %}
Если переменная имеет значение объекта Twig_Template Twig использует это как родительский шаблон:
// {% extends layout %}
$layout = $twig->loadTemplate('some_layout_template.twig');
$twig->display('template.twig', array('layout' => $layout));
Вы можете указать массив названий шаблонов. Первый найденный шаблон будет использоваться в качестве родителя:
{% extends ['layout.html', 'base_layout.html'] %}
В качестве названия может быть использовано любое выражение, на пример:
{% extends standalone ? "minimum.html" : "base.html" %}
В этом примере шаблон будет унаследован "minimum.html", если standalone вернет true, в противном случае "base.html"
Блоки позволяют менять все, что находится внутри них, но никак не влияют на то, что происходит вокруг них
В следующем примере можно увидеть, как блоки работают, и что самое главное - как они не работают:
{# base.twig #}
{% for post in posts %}
{% block post %}
<h1>{{ post.title }}</h1>
<p>{{ post.body }}</p>
{% endblock %}
{% endfor %}
Если вы напишете такой блок, то при обработке на каждой итерации цикла, содержимое блока post будет перезаписанно:
{# child.twig #}
{% extends "base.twig" %}
{% block post %}
<article>
<header>{{ post.title }}</header>
<section>{{ post.text }}</section>
</article>
{% endblock %}
Теперь при обработке дочернего шаблона, "родительский" цикл использует "детское" определение блока и в итоге получится это:
{% for post in posts %}
<article>
<header>{{ post.title }}</header>
<section>{{ post.text }}</section>
</article>
{% endfor %}
Давайте попробуем другой пример с if условием:
{% if posts is empty %}
{% block head %}
{{ parent() }}
<meta name="robots" content="noindex, follow">
{% endblock head %}
{% endif %}
Вопреки тому, что вы могли подумать, этот шаблон не определит блок условно, а только сделает переписываемым "дочерний" шаблон и будет выведен, если условие будет выполнено.
Если вы хотите, чтобы вывод блока был определен условно, напишите следующую конструкцию:
{% block head %}
{{ parent() }}
{% if posts is empty %}
<meta name="robots" content="noindex, follow">
{% endif %}
{% endblock head %}