Обработчик шаблонов twig. быстрый старт

Loaders¶

Loaders are responsible for loading templates from a resource such as the file system.

Compilation Cache

All template loaders can cache the compiled templates on the filesystem for future reuse. It speeds up Twig a lot as templates are only compiled once.

Built-in Loaders

Here is a list of the built-in loaders:


loads templates from the file system. This loader can find templates in folders on the file system and is the preferred way to load them:

$loader = new \Twig\Loader\FilesystemLoader($templateDir);

It can also look for templates in an array of directories:

$loader = new \Twig\Loader\FilesystemLoader();

With such a configuration, Twig will first look for templates in and if they do not exist, it will fallback to look for them in the .

You can add or prepend paths via the and methods:

$loader->addPath($templateDir3);
$loader->prependPath($templateDir4);

The filesystem loader also supports namespaced templates. This allows to group your templates under different namespaces which have their own template paths.

When using the , , and methods, specify the namespace as the second argument (when not specified, these methods act on the “main” namespace):

$loader->addPath($templateDir, 'admin');

Namespaced templates can be accessed via the special notation:

$twig->render('@admin/index.html', []);

support absolute and relative paths. Using relative paths is preferred as it makes the cache keys independent of the project root directory (for instance, it allows warming the cache from a build server where the directory might be different from the one used on production servers):

$loader = new \Twig\Loader\FilesystemLoader('templates', getcwd().'/..');

Note

When not passing the root path as a second argument, Twig uses for relative paths.

loads a template from a PHP array. It is passed an array of strings bound to template names:

$loader = new \Twig\Loader\ArrayLoader();
$twig = new \Twig\Environment($loader);

echo $twig->render('index.html', 'name' => 'Fabien']);

This loader is very useful for unit testing. It can also be used for small projects where storing all templates in a single PHP file might make sense.

Tip

When using the loader with a cache mechanism, you should know that a new cache key is generated each time a template content “changes” (the cache key being the source code of the template). If you don’t want to see your cache grows out of control, you need to take care of clearing the old cache file by yourself.

delegates the loading of templates to other loaders:

$loader1 = new \Twig\Loader\ArrayLoader();
$loader2 = new \Twig\Loader\ArrayLoader();

$loader = new \Twig\Loader\ChainLoader();

$twig = new \Twig\Environment($loader);

When looking for a template, Twig tries each loader in turn and returns as soon as the template is found. When rendering the template from the above example, Twig will load it with but the template will be loaded from .

Note

You can also add loaders via the method.

Testing an Extension¶

Functional Tests

You can create functional tests for extensions by creating the following file structure in your test directory:

Fixtures
    filters
        foo.test
        bar.test
    functions
        foo.test
        bar.test
    tags
        foo.test
        bar.test
IntegrationTest.php

The file should look like this:

class Project_Tests_IntegrationTest extends \Twig\Test\IntegrationTestCase
{
    public function getExtensions()
    {
        return 
            new Project_Twig_Extension1(),
            new Project_Twig_Extension2(),
        ];
    }

    public function getFixturesDir()
    {
        return __DIR__.'/Fixtures/';
    }
}

Fixtures examples can be found within the Twig repository tests/Twig/Fixtures directory.

Node Tests

Testing the node visitors can be complex, so extend your test cases from . Examples can be found in the Twig repository tests/Twig/Node directory.

HTML Escaping¶

When generating HTML from templates, there’s always a risk that a variable will include characters that affect the resulting HTML. There are two approaches: manually escaping each variable or automatically escaping everything by default.

Twig supports both, automatic escaping is enabled by default.

The automatic escaping strategy can be configured via the option and defaults to .

Working with Manual Escaping

If manual escaping is enabled, it is your responsibility to escape variables if needed. What to escape? Any variable that comes from an untrusted source.

Escaping works by using the escape or filter:

1
{{ user.username|e }}

By default, the filter uses the strategy, but depending on the escaping context, you might want to explicitly use an other strategy:

1
2
3
4
{{ user.username|e('js') }}
{{ user.username|e('css') }}
{{ user.username|e('url') }}
{{ user.username|e('html_attr') }}

How do blocks work?¶

A block provides a way to change how a certain part of a template is rendered but it does not interfere in any way with the logic around it.

Let’s take the following example to illustrate how a block works and more importantly, how it does not work:

1
2
3
4
5
6
7
8
{# base.twig #}

{% for post in posts %}
{% block post %}
        <h1>{{ post.title }}</h1>
        <p>{{ post.body }}</p>
{% endblock %}
{% endfor %}

If you render this template, the result would be exactly the same with or without the tag. The inside the loop is just a way to make it overridable by a child template:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{# child.twig #}

{% extends "base.twig" %}

{% block post %}
    <article>
        <header>{{ post.title }}</header>
        <section>{{ post.text }}</section>
    </article>
{% endblock %}

Now, when rendering the child template, the loop is going to use the block defined in the child template instead of the one defined in the base one; the executed template is then equivalent to the following one:

1
2
3
4
5
6
{% for post in posts %}
    <article>
        <header>{{ post.title }}</header>
        <section>{{ post.text }}</section>
    </article>
{% endfor %}

Let’s take another example: a block included within an statement:

1
2
3
4
5
6
7
{% if posts is empty %}
{% block head %}
{{ parent() }}

        <meta name="robots" content="noindex, follow">
{% endblock head %}
{% endif %}

Contrary to what you might think, this template does not define a block conditionally; it just makes overridable by a child template the output of what will be rendered when the condition is .

If you want the output to be displayed conditionally, use the following instead:

1
2
3
4
5
6
7
{% block head %}
{{ parent() }}

{% if posts is empty %}
        <meta name="robots" content="noindex, follow">
{% endif %}
{% endblock head %}

See also

block, block, parent, use

Приступаем к делу

Для того чтобы посмотреть, как работает Twig, предлагаю рассмотреть простой пример:

<html>
  <head></head>
  <body>
  <h2>Account successfully created!</h2>

  <p>Hello {{ name }}</p>

  <p>Thank you for registering with us. Your account details are as follows: </p>

  <p style="margin-left: 10px">
  Username: {{ username }} <br/>
  Password: {{ password }}
  </p>

  <p>You've already been logged in, so go on in and have some fun!</p>
  </body>
</html>

Сохраните данный файл templates/thanks.tmpl

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

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

<?php
// подгружаем и активируем авто-загрузчик Twig-а
require_once 'Twig/Autoloader.php';
Twig_Autoloader::register();

try {
  // указывае где хранятся шаблоны
  $loader = new Twig_Loader_Filesystem('templates');

  // инициализируем Twig
  $twig = new Twig_Environment($loader);

  // подгружаем шаблон
  $template = $twig->loadTemplate('thanks.tmpl');

  // передаём в шаблон переменные и значения
  // выводим сформированное содержание
  echo $template->render(array(
    'name' => 'Clark Kent',
    'username' => 'ckent',
    'password' => 'krypt0n1te',
  ));

} catch (Exception $e) {
  die ('ERROR: ' . $e->getMessage());
}
?>

В результате, если вы откроете данную страницу в браузере, то увидите следующее:

Для использования Twig-а, вам нужно пройти следующие шаги:

  1. Инициализировать авто-загрузчик Twig-а, для того чтобы классы шаблонизатора подгружались автоматически.
  2. Инициализировать загрузчик шаблонов. В нашем случае эт Twig_Loader_FileSystem. В качестве аргумента передаём путь к каталогу с шаблонами.
  3. Создать объект самого Twig и передать ему уже сконфигурированные настройки.
  4. Подгрузить нужный нам шаблон с помощью метода loadTemplate, передав в него название используемого шаблона. В качестве результата метод вернёт экземпляр шаблона.
  5. Сформировать массив вида «ключ-значение», где ключи — это названия переменных, а значения — данные, выводимые в шаблоне. Затем этот массив нужно передать в метод render(), который совместит шаблон с переданными данными и вернёт сгенерированный результат.

Using Extensions¶

Twig extensions are packages that add new features to Twig. Register an extension via the method:

$twig->addExtension(new \Twig\Extension\SandboxExtension());

Twig comes bundled with the following extensions:

  • TwigExtensionCoreExtension: Defines all the core features of Twig.
  • TwigExtensionDebugExtension: Defines the function to help debug template variables.
  • TwigExtensionEscaperExtension: Adds automatic output-escaping and the possibility to escape/unescape blocks of code.
  • TwigExtensionSandboxExtension: Adds a sandbox mode to the default Twig environment, making it safe to evaluate untrusted code.
  • TwigExtensionProfilerExtension: Enabled the built-in Twig profiler.
  • TwigExtensionOptimizerExtension: Optimizes the node tree before compilation.
  • TwigExtensionStringLoaderExtension: Defined the
    function to allow loading templates from string in a template.

Настройка базового шаблона

Базовый шаблон представляет собой обычный html документ со специальными вставками:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
    <title>{% block title %}{% endblock %}</title>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
</head>
<body>

<div id="content">
    {% block content %}
    {% endblock %}
</div>

</body>
</html>

В нашем главном шаблоне мы прописываем 2 блока: title и content. Названия блоков выбираем сами.

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

index.php

Общий вид файла index.php

require_once 'lib/Twig/Autoloader.php';
Twig_Autoloader::register();

$loader = new Twig_Loader_Filesystem('templates');
$twig = new Twig_Environment($loader, array(
    'cache'       => 'compilation_cache',
    'auto_reload' => true
));

$books = array(
	array('number' => 'Книга 1', 'title' => 'Гарри Поттер и философский камень', 'date' => '30.06.1997'),
	array('number' => 'Книга 2', 'title' => 'Гарри Поттер и Тайная комната', 'date' => '2.07.1998'),
	array('number' => 'Книга 3', 'title' => 'Гарри Поттер и узник Азкабана', 'date' => '8.07.1999'),
	array('number' => 'Книга 4', 'title' => 'Гарри Поттер и Кубок огня', 'date' => '8.07.2000'),
	array('number' => 'Книга 5', 'title' => 'Гарри Поттер и Орден Феникса', 'date' => '21.07.2003'),
	array('number' => 'Книга 6', 'title' => 'Гарри Поттер и Принц-полукровка', 'date' => '16.07.2005'),
	array('number' => 'Книга 7', 'title' => 'Гарри Поттер и Дары Смерти', 'date' => '21.07.2007')
);

echo $twig->render('books.html', array('books' => $books));

Loaders¶

Loaders are responsible for loading templates from a resource such as the file system.

Compilation Cache

All template loaders can cache the compiled templates on the filesystem for future reuse. It speeds up Twig a lot as templates are only compiled once.

Built-in Loaders

Here is a list of the built-in loaders:

loads templates from the file system. This loader can find templates in folders on the file system and is the preferred way to load them:

$loader = new \Twig\Loader\FilesystemLoader($templateDir);

It can also look for templates in an array of directories:

$loader = new \Twig\Loader\FilesystemLoader();

With such a configuration, Twig will first look for templates in and if they do not exist, it will fallback to look for them in the .

You can add or prepend paths via the and methods:

$loader->addPath($templateDir3);
$loader->prependPath($templateDir4);

The filesystem loader also supports namespaced templates. This allows to group your templates under different namespaces which have their own template paths.

When using the , , and methods, specify the namespace as the second argument (when not specified, these methods act on the “main” namespace):

$loader->addPath($templateDir, 'admin');

Namespaced templates can be accessed via the special notation:

$twig->render('@admin/index.html', []);

support absolute and relative paths. Using relative paths is preferred as it makes the cache keys independent of the project root directory (for instance, it allows warming the cache from a build server where the directory might be different from the one used on production servers):

$loader = new \Twig\Loader\FilesystemLoader('templates', getcwd().'/..');

Note

When not passing the root path as a second argument, Twig uses for relative paths.

loads a template from a PHP array. It is passed an array of strings bound to template names:

$loader = new \Twig\Loader\ArrayLoader();
$twig = new \Twig\Environment($loader);

echo $twig->render('index.html', 'name' => 'Fabien']);

This loader is very useful for unit testing. It can also be used for small projects where storing all templates in a single PHP file might make sense.

Tip

When using the loader with a cache mechanism, you should know that a new cache key is generated each time a template content “changes” (the cache key being the source code of the template). If you don’t want to see your cache grows out of control, you need to take care of clearing the old cache file by yourself.

delegates the loading of templates to other loaders:

$loader1 = new \Twig\Loader\ArrayLoader();
$loader2 = new \Twig\Loader\ArrayLoader();

$loader = new \Twig\Loader\ChainLoader();

$twig = new \Twig\Environment($loader);

When looking for a template, Twig tries each loader in turn and returns as soon as the template is found. When rendering the template from the above example, Twig will load it with but the template will be loaded from .

Note

You can also add loaders via the method.

Whitespace Control¶

New in version 2.8: Tag level Line whitespace control was added in Twig 2.8.

The first newline after a template tag is removed automatically (like in PHP). Whitespace is not further modified by the template engine, so each whitespace (spaces, tabs, newlines etc.) is returned unchanged.

You can also control whitespace on a per tag level. By using the whitespace control modifiers on your tags, you can trim leading and or trailing whitespace.


Twig supports two modifiers:

  • Whitespace trimming via the modifier: Removes all whitespace (including newlines);
  • Line whitespace trimming via the modifier: Removes all whitespace (excluding newlines). Using this modifier on the right disables the default removal of the first newline inherited from PHP.

The modifiers can be used on either side of the tags like in or and they consume all whitespace for that side of the tag. It is possible to use the modifiers on one side of a tag or on both sides:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{% set value = 'no spaces' %}
{#- No leading/trailing whitespace -#}
{%- if true -%}
{{- value -}}
{%- endif -%}
{# output 'no spaces' #}

<li>
{{ value }}    </li>
{# outputs '<li>\n    no spaces    </li>' #}

<li>
{{- value }}    </li>
{# outputs '<li>no spaces    </li>' #}

<li>
{{~ value }}    </li>
{# outputs '<li>\nno spaces    </li>' #}

HTML Escaping¶

When generating HTML from templates, there’s always a risk that a variable will include characters that affect the resulting HTML. There are two approaches: manually escaping each variable or automatically escaping everything by default.

Twig supports both, automatic escaping is enabled by default.

The automatic escaping strategy can be configured via the option and defaults to .

Working with Manual Escaping

If manual escaping is enabled, it is your responsibility to escape variables if needed. What to escape? Any variable that comes from an untrusted source.

Escaping works by using the escape or filter:

1
{{ user.username|e }}

By default, the filter uses the strategy, but depending on the escaping context, you might want to explicitly use an other strategy:

1
2
3
4
{{ user.username|e('js') }}
{{ user.username|e('css') }}
{{ user.username|e('url') }}
{{ user.username|e('html_attr') }}

Creating an Extension¶

The main motivation for writing an extension is to move often used code into a reusable class like adding support for internationalization. An extension can define tags, filters, tests, operators, functions, and node visitors.

Most of the time, it is useful to create a single extension for your project, to host all the specific tags and filters you want to add to Twig.

Tip

When packaging your code into an extension, Twig is smart enough to recompile your templates whenever you make a change to it (when is enabled).

An extension is a class that implements the following interface:

interface \Twig\Extension\ExtensionInterface
{
    /**
     * Returns the token parser instances to add to the existing list.
     *
     * @return \Twig\TokenParser\TokenParserInterface[]
     */
    public function getTokenParsers();

    /**
     * Returns the node visitor instances to add to the existing list.
     *
     * @return \Twig\NodeVisitor\NodeVisitorInterface[]
     */
    public function getNodeVisitors();

    /**
     * Returns a list of filters to add to the existing list.
     *
     * @return \Twig\TwigFilter[]
     */
    public function getFilters();

    /**
     * Returns a list of tests to add to the existing list.
     *
     * @return \Twig\TwigTest[]
     */
    public function getTests();

    /**
     * Returns a list of functions to add to the existing list.
     *
     * @return \Twig\TwigFunction[]
     */
    public function getFunctions();

    /**
     * Returns a list of operators to add to the existing list.
     *
     * @return array<array> First array of unary operators, second array of binary operators
     */
    public function getOperators();
}

To keep your extension class clean and lean, inherit from the built-in class instead of implementing the interface as it provides empty implementations for all methods:

class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
}

This extension does nothing for now. We will customize it in the next sections.

You can save your extension anywhere on the filesystem, as all extensions must be registered explicitly to be available in your templates.

You can register an extension by using the method on your main object:

$twig = new \Twig\Environment($loader);
$twig->addExtension(new Project_Twig_Extension());

Tip

The Twig core extensions are great examples of how extensions work.

Globals

Global variables can be registered in an extension via the method:

class Project_Twig_Extension extends \Twig\Extension\AbstractExtension implements \Twig\Extension\GlobalsInterface
{
    public function getGlobals()
    {
        return 
            'text' => new Text(),
        ];
    }

    // ...
}

Functions

Functions can be registered in an extension via the method:

class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
    public function getFunctions()
    {
        return 
            new \Twig\TwigFunction('lipsum', 'generate_lipsum'),
        ];
    }

    // ...
}

Filters

To add a filter to an extension, you need to override the method. This method must return an array of filters to add to the Twig environment:

class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
    public function getFilters()
    {
        return 
            new \Twig\TwigFilter('rot13', 'str_rot13'),
        ];
    }

    // ...
}

Tags

Adding a tag in an extension can be done by overriding the method. This method must return an array of tags to add to the Twig environment:

class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
    public function getTokenParsers()
    {
        return new Project_Set_TokenParser()];
    }

    // ...
}

In the above code, we have added a single new tag, defined by the class. The class is responsible for parsing the tag and compiling it to PHP.

Operators

The methods lets you add new operators. Here is how to add the , , and operators:

class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
    public function getOperators()
    {
        return 
            
                '!' => 'precedence' => 50, 'class' => \Twig\Node\Expression\Unary\NotUnary::class],
            ],
            
                '||' => 'precedence' => 10, 'class' => \Twig\Node\Expression\Binary\OrBinary::class, 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT],
                '&&' => 'precedence' => 15, 'class' => \Twig\Node\Expression\Binary\AndBinary::class, 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT],
            ],
        ];
    }

    // ...
}

Tests

The method lets you add new test functions:

class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
    public function getTests()
    {
        return 
            new \Twig\TwigTest('even', 'twig_test_even'),
        ];
    }

    // ...
}

Filters¶

Creating a filter consists of associating a name with a PHP callable:

// an anonymous function
$filter = new \Twig\TwigFilter('rot13', function ($string) {
    return str_rot13($string);
});

// or a simple PHP function
$filter = new \Twig\TwigFilter('rot13', 'str_rot13');

// or a class static method
$filter = new \Twig\TwigFilter('rot13', 'SomeClass', 'rot13Filter']);
$filter = new \Twig\TwigFilter('rot13', 'SomeClass::rot13Filter');

// or a class method
$filter = new \Twig\TwigFilter('rot13', $this, 'rot13Filter']);
// the one below needs a runtime implementation (see below for more information)
$filter = new \Twig\TwigFilter('rot13', 'SomeClass', 'rot13Filter']);

The first argument passed to the constructor is the name of the filter you will use in templates and the second one is the PHP callable to associate with it.

Then, add the filter to the Twig environment:

$twig = new \Twig\Environment($loader);
$twig->addFilter($filter);

And here is how to use it in a template:

1
2
3
{{ 'Twig'|rot13 }}

{# will output Gjvt #}

When called by Twig, the PHP callable receives the left side of the filter (before the pipe ) as the first argument and the extra arguments passed to the filter (within parentheses ) as extra arguments.

For instance, the following code:

1
2
{{ 'TWIG'|lower }}
{{ now|date('d/m/Y') }}

is compiled to something like the following:

<?php echo strtolower('TWIG') ?>
<?php echo twig_date_format_filter($now, 'd/m/Y') ?>

The class takes an array of options as its last argument:

$filter = new \Twig\TwigFilter('rot13', 'str_rot13', $options);

Environment-aware Filters

If you want to access the current environment instance in your filter, set the option to ; Twig will pass the current environment as the first argument to the filter call:

$filter = new \Twig\TwigFilter('rot13', function (\Twig\Environment $env, $string) {
    // get the current charset for instance
    $charset = $env->getCharset();

    return str_rot13($string);
}, 'needs_environment' => true]);

Context-aware Filters

If you want to access the current context in your filter, set the option to ; Twig will pass the current context as the first argument to the filter call (or the second one if is also set to ):

$filter = new \Twig\TwigFilter('rot13', function ($context, $string) {
    // ...
}, 'needs_context' => true]);

$filter = new \Twig\TwigFilter('rot13', function (\Twig\Environment $env, $context, $string) {
    // ...
}, 'needs_context' => true, 'needs_environment' => true]);

Automatic Escaping

If automatic escaping is enabled, the output of the filter may be escaped before printing. If your filter acts as an escaper (or explicitly outputs HTML or JavaScript code), you will want the raw output to be printed. In such a case, set the option:

$filter = new \Twig\TwigFilter('nl2br', 'nl2br', 'is_safe' => 'html']]);

Some filters may need to work on input that is already escaped or safe, for example when adding (safe) HTML tags to originally unsafe output. In such a case, set the option to escape the input data before it is run through your filter:

$filter = new \Twig\TwigFilter('somefilter', 'somefilter', 'pre_escape' => 'html', 'is_safe' => 'html']]);

Variadic Filters

When a filter should accept an arbitrary number of arguments, set the option to ; Twig will pass the extra arguments as the last argument to the filter call as an array:

$filter = new \Twig\TwigFilter('thumbnail', function ($file, array $options = []) {
    // ...
}, 'is_variadic' => true]);

Be warned that passed to a variadic filter cannot be checked for validity as they will automatically end up in the option array.

Dynamic Filters

A filter name containing the special character is a dynamic filter and the part will match any string:

$filter = new \Twig\TwigFilter('*_path', function ($name, $arguments) {
    // ...
});

The following filters are matched by the above defined dynamic filter:


A dynamic filter can define more than one dynamic parts:

$filter = new \Twig\TwigFilter('*_path_*', function ($name, $suffix, $arguments) {
    // ...
});

The filter receives all dynamic part values before the normal filter arguments, but after the environment and the context. For instance, a call to will result in the following arguments to be passed to the filter: .

5 последних уроков рубрики «PHP»

Когда речь идёт о безопасности веб-сайта, то фраза «фильтруйте всё, экранируйте всё» всегда будет актуальна. Сегодня поговорим о фильтрации данных. Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак

В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода. Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение

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

Условия

Twig также предоставляет нам возможность создавать условные выражения ‘if-else-endif’. Пример:

<html>
  <head></head>
  <body>
    <h2>Odd or Even</h2>
    {% if div == 0 %}
      {{ num }} is even.
    {% else %}
      {{ num }} is odd.
    {% endif %}
  </body>
</html>

В зависимости от числа, которое генерируется в основном PHP скрипте, шаблон отобразит одно из двух сообщений. Вот и скрипт, где генерируется число от 0 до 30 и проверяется на чётность:

<?php
include 'Twig/Autoloader.php';
Twig_Autoloader::register();

try {
  $loader = new Twig_Loader_Filesystem('templates');

  $twig = new Twig_Environment($loader);

  $template = $twig->loadTemplate('numbers.tmpl');

  // генерируем случайное число
  // и проверяем его на чётность
  $num = rand (0,30);
  $div = ($num % 2);

  echo $template->render(array (
    'num' => $num,
    'div' => $div
  ));

} catch (Exception $e) {
  die ('ERROR: ' . $e->getMessage());
}
?>

а вот и результат:

Также мы можем сделать многоуровневые проверки ‘if-elseif-else-endif’. Пример:

<html>
  <head></head>
  <body>
    <h2>Seasons</h2>
    {% if month > 0 and month <= 3 %}
      Spring is here, watch the flowers bloom!
    {% elseif month > 3 and month <= 6 %}
      Summer is here, time to hit the beach!
    {% elseif month > 6 and month <= 9 %}
      Autumn is here, watch the leaves slowly fall!
    {% elseif month > 9 and month <= 12 %}
      Winter is here, time to hit the slopes!
    {% endif %}
  </body>
</html>

А вот и скрипт, где мы генерируем номер месяца и передаём его в шаблон:

<?php
include 'Twig/Autoloader.php';
Twig_Autoloader::register();

try {
  $loader = new Twig_Loader_Filesystem('templates');

  $twig = new Twig_Environment($loader);

  $template = $twig->loadTemplate('seasons.tmpl');

  // получаем номер месяца
  $month = date('m', mktime());

  echo $template->render(array (
    'month' => $month
  ));

} catch (Exception $e) {
  die ('ERROR: ' . $e->getMessage());
}
?>

А вот и вывод:

Including other Templates¶

The include function is useful to include a template and return the rendered content of that template into the current one:

1
{{ include('sidebar.html') }}

By default, included templates have access to the same context as the template which includes them. This means that any variable defined in the main template will be available in the included template too:

1
2
3
{% for box in boxes %}
{{ include('render_box.html') }}
{% endfor %}

The included template is able to access the variable.

The name of the template depends on the template loader. For instance, the allows you to access other templates by giving the filename. You can access templates in subdirectories with a slash:

1
{{ include('sections/articles/sidebar.html') }}

Synopsis¶

A template is a regular text file. It can generate any text-based format (HTML, XML, CSV, LaTeX, etc.). It doesn’t have a specific extension, or are just fine.

A template contains variables or expressions, which get replaced with values when the template is evaluated, and tags, which control the template’s logic.

Below is a minimal template that illustrates a few basics. We will cover further details later on:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
    <head>
        <title>My Webpage</title>
    </head>
    <body>
        <ul id="navigation">
        {% for item in navigation %}
            <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
        {% endfor %}
        </ul>

        <h1>My Webpage</h1>
        {{ a_variable }}
    </body>
</html>

Template Inheritance¶

The most powerful part of Twig is template inheritance. Template inheritance allows you to build a base “skeleton” template that contains all the common elements of your site and defines blocks that child templates can override.

It’s easier to understand the concept by starting with an example.

Let’s define a base template, , which defines an HTML skeleton document that might be used for a two-column page:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
    <head>
        {% block head %}
            <link rel="stylesheet" href="style.css" />
            <title>{% block title %}{% endblock %} - My Webpage</title>
        {% endblock %}
    </head>
    <body>
        <div id="content">{% block content %}{% endblock %}</div>
        <div id="footer">
            {% block footer %}
                &copy; Copyright 2011 by <a href="http://domain.invalid/">you</a>.
            {% endblock %}
        </div>
    </body>
</html>

In this example, the block tags define four blocks that child templates can fill in. All the tag does is to tell the template engine that a child template may override those portions of the template.

A child template might look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{% extends "base.html" %}

{% block title %}Index{% endblock %}
{% block head %}
{{ parent() }}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% endblock %}
{% block content %}
    <h1>Index</h1>
    <p class="important">
        Welcome to my awesome homepage.
    </p>
{% endblock %}

The extends tag is the key here. It tells the template engine that this template “extends” another template. When the template system evaluates this template, first it locates the parent. The extends tag should be the first tag in the template.

Note that since the child template doesn’t define the block, the value from the parent template is used instead.

It’s possible to render the contents of the parent block by using the parent function. This gives back the results of the parent block:

1
2
3
4
5
{% block sidebar %}
    <h3>Table Of Contents</h3>
    ...
{{ parent() }}
{% endblock %}

Tip

The documentation page for the extends tag describes more advanced features like block nesting, scope, dynamic inheritance, and conditional inheritance.

Настройка шаблона вывода книг

Для начала в дочернем шаблоне нам необходимо указать шаблон родителя:

{% extends "base.html" %}

Далее в блок title запишем название дочерней страницы, которая обработается Twig-ом и вставится между тегами title в базовом шаблоне:

{% block title %}Серия романов о Гарри Поттере{% endblock %}

Затем, пишем содержание, которое внедрится в блок под названием content в базовом шаблоне:

{% block content %}
<h1>Серия романов о Гарри Поттере</h1>

<div id="books">
    {% for book in books %}
    <div class="book">
    	<strong>{{book.number}}</strong>. "<em>{{book.title}}"</em> - {{book.date}}
    </div>
    {% endfor %}
</div>
{% endblock %}

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

Таким образом, после срабатывания метода , Twig подгрузит шаблон books.html и сформирует html содержание. Далее он распознает, что books.html — это дочерний шаблон base.html, и поместит сформированное содержание в базовый шаблон. После всего этого Twig вернёт нам полноценную html страницу.


С этим читают