Расширение Twig
Twig можно расширить различными способами; вы можете добавить дополнительные теги, фильтры, тесты, операторы, глобальные переменные и функции. Вы даже можете расширить сам парсер с помощью посетителей узлов.
Примечание
Первый раздел этой главы описывает, как расширить Twig. Если вы хотите повторно использовать свои изменения в разных проектах или поделиться ими с другими, вам следует создать расширение, как описано в следующем разделе.
Внимание
При расширении Twig без создания расширения Twig не сможет повторно скомпилировать ваши шаблоны при обновлении PHP-кода. Чтобы увидеть свои изменения в реальном времени, отключите кэширование шаблонов или упакуйте свой код в расширение (см. следующий раздел этой главы).
Прежде чем расширять Twig, вы должны понять различия между всеми возможными точками расширения и когда их использовать.
Во-первых, помните, что Twig имеет две основные конструкции языка:
-
{{ }}: используется для вывода результата вычисления выражения; -
{% %}: используется для выполнения операторов.
Чтобы понять, почему Twig предоставляет так много точек расширения, давайте посмотрим, как реализовать генератор Lorem ipsum (он должен знать количество слов для генерации).
Вы можете использовать lipsum тег:
{% lipsum 40 %}
Это работает, но использование тега для lipsum не является хорошей идеей по крайней мере по трём основным причинам:
-
lipsumне является конструкцией языка; -
Тег выводит что-то;
-
Тег негибкий, так как его нельзя использовать в выражении:
{{ 'some text' ~ {% lipsum 40 %} ~ 'some more text' }}
На самом деле, редко нужно создавать теги; и это хорошая новость, потому что теги — это самая сложная точка расширения.
Теперь давайте используем lipsum фильтр:
{{ 40|lipsum }}
Опять же, это работает. Но фильтр должен преобразовывать переданное значение во что-то другое. Здесь мы используем значение для указания количества слов для генерации (так, 40 является аргументом фильтра, а не значением, которое мы хотим преобразовать).
Далее, давайте используем lipsum функцию:
{{ lipsum(40) }}
Вот и всё. В этом конкретном примере точка расширения — создание функции. И вы можете использовать её везде, где принимается выражение:
{{ 'some text' ~ lipsum(40) ~ 'some more text' }}
{% set lipsum = lipsum(40) %}
Наконец, вы также можете использовать объект глобальных переменных с методом, способным генерировать текст Lorem ipsum:
{{ text.lipsum(40) }}
Как правило, используйте функции для часто используемых функций и глобальные объекты для всего остального.
Помните об этом, когда хотите расширить Twig:
| Что? | Сложность реализации? | Как часто? | Когда? |
|---|---|---|---|
| макрос | простая | часто | Генерация контента |
| глобальный | простая | часто | Объект-помощник |
| функция | простая | часто | Генерация контента |
| фильтр | простая | часто | Преобразование значений |
| тег | сложная | редко | DSL-конструкция языка |
| тест | простая | редко | Булево решение |
| оператор | простая | редко | Преобразование значений |
Глобальные переменные
Глобальная переменная похожа на любую другую переменную шаблона, за исключением того, что она доступна во всех шаблонах и макросах:
$twig = new \Twig\Environment($loader);
$twig->addGlobal('text', new Text());
Затем вы можете использовать переменную text в любом шаблоне:
{{ text.lipsum(40) }}
Фильтры
Создание фильтра состоит из сопоставления имени с PHP-вызываемым:
// 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']);
Первый аргумент, передаваемый конструктору \Twig\TwigFilter, — это имя фильтра, который вы будете использовать в шаблонах, а второй — PHP-вызываемый, который с ним нужно связать.
Затем добавьте фильтр в среду Twig:
$twig = new \Twig\Environment($loader);
$twig->addFilter($filter);
И вот как его использовать в шаблоне:
{{ 'Twig'|rot13 }}
{# will output Gjvt #}
При вызове Twig PHP-вызываемый получает левую часть фильтра (перед символом | |) в качестве первого аргумента и дополнительные аргументы, передаваемые фильтру (в скобках ()) в качестве дополнительных аргументов.
Например, следующий код:
{{ 'TWIG'|lower }}
{{ now|date('d/m/Y') }}
скомпилируется примерно следующим образом:
<?php echo strtolower('TWIG') ?>
<?php echo twig_date_format_filter($now, 'd/m/Y') ?>
Класс \Twig\TwigFilter принимает массив опций в качестве последнего аргумента:
$filter = new \Twig\TwigFilter('rot13', 'str_rot13', $options);
Фильтры, учитывающие среду
Если вы хотите получить доступ к текущей экземпляру среды в своем фильтре, установите опцию needs_environment в значение true; Twig передаст текущую среду в качестве первого аргумента вызову фильтра:
$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]);
Фильтры, учитывающие контекст
Если вы хотите получить доступ к текущему контексту в своем фильтре, установите опцию needs_context в значение true; Twig передаст текущий контекст в качестве первого аргумента вызову фильтра (или второго, если needs_environment также установлено в true) :
$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]);
Автоматическое экранирование
Если включено автоматическое экранирование, вывод фильтра может быть экранирован перед печатью. Если ваш фильтр действует как экранировщик (или явно выводит HTML или JavaScript-код), вам нужно будет получить исходный вывод. В этом случае установите опцию is_safe:
$filter = new \Twig\TwigFilter('nl2br', 'nl2br', ['is_safe' => ['html']]);
Некоторые фильтры могут потребоваться для работы со входными данными, которые уже экранированы или безопасны, например, при добавлении (безопасных) HTML-тегов к исходно небезопасным данным. В этом случае установите опцию pre_escape для экранирования входных данных перед их проходом через ваш фильтр:
$filter = new \Twig\TwigFilter('somefilter', 'somefilter', ['pre_escape' => 'html', 'is_safe' => ['html']]);
Многоаргументные фильтры
Добавлено в версии 1.19: Поддержка многоаргументных фильтров была добавлена в Twig 1.19.
Если фильтр должен принимать произвольное количество аргументов, установите опцию is_variadic в значение true; Twig передаст дополнительные аргументы в качестве последнего аргумента вызову фильтра в виде массива:
$filter = new \Twig\TwigFilter('thumbnail', function ($file, array $options = []) {
// ...
}, ['is_variadic' => true]);
Будьте осторожны, что именованные аргументы, переданные многоаргументным фильтру, не могут быть проверены на правильность, так как они автоматически окажутся в массиве опций.
Динамические фильтры
Имя фильтра, содержащее специальный символ *, является динамическим фильтром, и часть * будет соответствовать любой строке:
$filter = new \Twig\TwigFilter('*_path', function ($name, $arguments) {
// ...
});
Следующие фильтры соответствуют определённому динамическому фильтру:
product_pathcategory_path
Динамический фильтр может определять более одной динамической части:
$filter = new \Twig\TwigFilter('*_path_*', function ($name, $suffix, $arguments) {
// ...
});
Фильтр получает все значения динамических частей перед обычными аргументами фильтра, но после среды и контекста. Например, вызов 'foo'|a_path_b() приведет к передаче в фильтр следующих аргументов: ('a', 'b', 'foo').
Устаревшие фильтры
Добавлено в версии 1.21: Поддержка deprecated фильтров была добавлена в Twig 1.21.
Вы можете пометить фильтр как устаревший, установив опцию deprecated в значение true. Вы также можете указать альтернативный фильтр, который заменит устаревший, если это имеет смысл:
$filter = new \Twig\TwigFilter('obsolete', function () {
// ...
}, ['deprecated' => true, 'alternative' => 'new_one']);
Когда фильтр устарел, Twig выводит уведомление об устаревании при компиляции шаблона с его использованием. См. Отображение уведомлений об устаревании для получения дополнительной информации.
Функции
Функции определяются точно так же, как и фильтры, но вам необходимо создать экземпляр \Twig\TwigFunction.
$twig = new \Twig\Environment($loader);
$function = new \Twig\TwigFunction('function_name', function () {
// ...
});
$twig->addFunction($function);
Функции поддерживают те же функции, что и фильтры, за исключением опций pre_escape и preserves_safety.
Тесты
Тесты определяются точно так же, как фильтры и функции, но вам необходимо создать экземпляр \Twig\TwigTest.
$twig = new \Twig\Environment($loader);
$test = new \Twig\TwigTest('test_name', function () {
// ...
});
$twig->addTest($test);
Тесты позволяют создать пользовательскую логику для оценки булевых условий. В качестве простого примера создадим Twig-тест, который проверяет, являются ли объекты «красными»:
$twig = new \Twig\Environment($loader);
$test = new \Twig\TwigTest('red', function ($value) {
if (isset($value->color) && $value->color == 'red') {
return true;
}
if (isset($value->paint) && $value->paint == 'red') {
return true;
}
return false;
});
$twig->addTest($test);
Функции-тесты всегда должны возвращать true/false.
При создании тестов вы можете использовать опцию node_class для предоставления настраиваемой компиляции тестов. Это полезно, если ваш тест можно скомпилировать в PHP-примитивы. Это используется многими встроенными в Twig тестами:
namespace App;
use Twig\Environment;
use Twig\Node\Expression\TestExpression;
use Twig\TwigTest;
$twig = new Environment($loader);
$test = new TwigTest(
'odd',
null,
['node_class' => OddTestExpression::class]);
$twig->addTest($test);
class OddTestExpression extends TestExpression
{
public function compile(\Twig\Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('node'))
->raw(' % 2 != 0')
->raw(')')
;
}
}
Вышеприведённый пример демонстрирует, как создать тесты, использующие класс узла. Класс узла имеет доступ к одному подузлу, называемому node. Этот под узел содержит значение, которое проверяется. Когда используется фильтр odd в коде, таком как:
{% if my_value is odd %}
Под узел node будет содержать выражение my_value. Тесты, основанные на узлах, также имеют доступ к узлу arguments. Этот узел будет содержать различные другие аргументы, которые были предоставлены вашему тесту.
Добавлено в версии 1.36: Поддержка динамических тестов была добавлена в Twig 1.36.
Если вы хотите передать переменное количество позиционных или именованных аргументов в тест, установите опцию is_variadic в значение true. Тесты поддерживают динамические имена (см. динамические фильтры для синтаксиса).
Теги
Одной из самых увлекательных особенностей движка шаблонов, такого как Twig, является возможность определения новых языковых конструкций. Это также самая сложная функция, так как вам необходимо понять, как работают внутренние механизмы Twig.
Большую часть времени тег не нужен:
-
Если ваш тег генерирует вывод, используйте функцию вместо него.
-
Если ваш тег изменяет содержимое и возвращает его, используйте фильтр вместо него.
Например, если вы хотите создать тег, который преобразует текст в формате Markdown в HTML, создайте фильтр
markdownвместо этого:{{ '**markdown** text'|markdown }}
Если вы хотите использовать этот фильтр для больших объёмов текста, оберните его тегом apply:
{% apply markdown %} Title ===== Much better than creating a tag as you can **compose** filters. {% endapply %}
Примечание
Тег
applyбыл добавлен в Twig 1.40; используйте тегfilterв предыдущих версиях.
-
Если ваш тег не выводит ничего, но существует только из-за побочного эффекта, создайте функцию, которая ничего не возвращает, и вызовите её через тег filter.
Например, если вы хотите создать тег, который записывает текст в журнал, создайте функцию
logвместо этого и вызовите её через тег do:{% do log('Log some things') %}
Если вы всё ещё хотите создать тег для новой языковой конструкции, отлично!
Давайте создадим тег set , который позволяет определять простые переменные внутри шаблона. Тег можно использовать следующим образом:
{% set name = "value" %}
{{ name }}
{# should output value #}
Примечание
Тег set является частью ядра расширения и, как следствие, всегда доступен. Встроенная версия немного мощнее и по умолчанию поддерживает несколько назначений.
Для определения нового тега требуется три шага:
- Определение класса Token Parser (ответственный за разбор кода шаблона);
- Определение класса Node (ответственный за преобразование разбора кода в PHP);
- Регистрация тега.
Регистрация нового тега
Добавьте тег, вызвав метод addTokenParser на экземпляре \Twig\Environment:
$twig = new \Twig\Environment($loader);
$twig->addTokenParser(new Project_Set_TokenParser());
Определение парсера токенов
Теперь давайте посмотрим на фактический код этого класса:
class Project_Set_TokenParser extends \Twig\TokenParser\AbstractTokenParser
{
public function parse(\Twig\Token $token)
{
$parser = $this->parser;
$stream = $parser->getStream();
$name = $stream->expect(\Twig\Token::NAME_TYPE)->getValue();
$stream->expect(\Twig\Token::OPERATOR_TYPE, '=');
$value = $parser->getExpressionParser()->parseExpression();
$stream->expect(\Twig\Token::BLOCK_END_TYPE);
return new Project_Set_Node($name, $value, $token->getLine(), $this->getTag());
}
public function getTag()
{
return 'set';
}
}
Метод getTag() должен возвращать тег, который мы хотим разобрать, в данном случае set.
Метод parse() вызывается всякий раз, когда парсер встречает тег set. Он должен вернуть экземпляр \Twig\Node\Node, который представляет собой узел (процесс создания узлов Project_Set_Node описан в следующем разделе).
Процесс разбора упрощен благодаря ряду методов, которые вы можете вызвать из потока токенов ($this->parser->getStream()):
-
getCurrent(): Получает текущий токен в потоке. -
next(): Переходит к следующему токену в потоке, но возвращает старый. -
test($type),test($value)илиtest($type, $value): Определяет, является ли текущий токен определённого типа или значения (или того и другого). Значение может быть массивом нескольких возможных значений. -
expect($type[, $value[, $message]]): Если текущий токен не соответствует заданному типу/значению, генерируется синтаксическая ошибка. В противном случае, если тип и значение верны, токен возвращается, и поток перемещается к следующему токену. -
look(): Рассматривает следующий токен, не потребляя его.
Разбор выражений выполняется путём вызова parseExpression(), как мы это сделали для тега set.
Подсказка
Чтение существующих классов TokenParser — лучший способ узнать все нюансы процесса разбора.
Определение узла
Класс Project_Set_Node сам по себе довольно короткий:
class Project_Set_Node extends \Twig\Node\Node
{
public function __construct($name, \Twig\Node\Expression\AbstractExpression $value, $line, $tag = null)
{
parent::__construct(['value' => $value], ['name' => $name], $line, $tag);
}
public function compile(\Twig\Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('$context[\''.$this->getAttribute('name').'\'] = ')
->subcompile($this->getNode('value'))
->raw(";\n")
;
}
}
Компилятор реализует гибкий интерфейс и предоставляет методы, которые помогают разработчику генерировать красивый и удобочитаемый код PHP:
-
subcompile(): Компилирует узел. -
raw(): Пишет заданную строку как есть. -
write(): Пишет заданную строку, добавляя отступы в начале каждой строки. -
string(): Пишет строку в кавычках. -
repr(): Пишет представление PHP заданного значения (см.\Twig\Node\ForNodeдля примера использования). -
addDebugInfo(): Добавляет строку из исходного файла шаблона, относящуюся к текущему узлу, как комментарий. -
indent(): Увеличивает отступ сгенерированного кода (см.\Twig\Node\BlockNodeдля примера использования). -
outdent(): Уменьшает отступ сгенерированного кода (см.\Twig\Node\BlockNodeдля примера использования).
Создание расширения
Основная мотивация для написания расширения — перемещение часто используемого кода в многократно используемый класс, например, добавление поддержки интернационализации. Расширение может определять теги, фильтры, тесты, операторы, функции и посетителей узлов.
Большую часть времени полезно создать одно расширение для вашего проекта, чтобы разместить все специфичные теги и фильтры, которые вы хотите добавить в Twig.
Подсказка
При упаковке кода в расширение, Twig достаточно умён, чтобы перекомпилировать ваши шаблоны всякий раз, когда вы внесёте изменения (когда auto_reload включено).
Расширение — это класс, который реализует следующий интерфейс:
interface Twig_ExtensionInterface
{
/**
* Initializes the runtime environment.
*
* This is where you can load some file that contains filter functions for instance.
*
* @deprecated since 1.23 (to be removed in 2.0), implement \Twig\Extension\InitRuntimeInterface instead
*/
function initRuntime(\Twig\Environment $environment);
/**
* Returns the token parser instances to add to the existing list.
*
* @return (Twig_TokenParserInterface|Twig_TokenParserBrokerInterface)[]
*/
function getTokenParsers();
/**
* Returns the node visitor instances to add to the existing list.
*
* @return \Twig\NodeVisitor\NodeVisitorInterface[]
*/
function getNodeVisitors();
/**
* Returns a list of filters to add to the existing list.
*
* @return \Twig\TwigFilter[]
*/
function getFilters();
/**
* Returns a list of tests to add to the existing list.
*
* @return \Twig\TwigTest[]
*/
function getTests();
/**
* Returns a list of functions to add to the existing list.
*
* @return \Twig\TwigFunction[]
*/
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
*/
function getOperators();
/**
* Returns a list of global variables to add to the existing list.
*
* @return array An array of global variables
*
* @deprecated since 1.23 (to be removed in 2.0), implement \Twig\Extension\GlobalsInterface instead
*/
function getGlobals();
/**
* Returns the name of the extension.
*
* @return string The extension name
*
* @deprecated since 1.26 (to be removed in 2.0), not used anymore internally
*/
function getName();
}
Чтобы сохранить ваш класс расширения чистым и компактным, унаследуйте от встроенного класса \Twig\Extension\AbstractExtension вместо реализации интерфейса, так как он предоставляет пустые реализации для всех методов:
class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
}
Это расширение пока ничего не делает. Мы настраиваем его в следующих разделах.
Примечание
До Twig 1.26 необходимо реализовать метод getName(), который должен вернуть уникальный идентификатор для расширения.
Вы можете сохранить своё расширение где угодно в файловой системе, так как все расширения должны быть явно зарегистрированы, чтобы быть доступными в ваших шаблонах.
Вы можете зарегистрировать расширение, используя метод addExtension() на вашем основном объекте Environment:
$twig = new \Twig\Environment($loader);
$twig->addExtension(new Project_Twig_Extension());
Подсказка
Расширения ядра Twig — отличные примеры того, как работают расширения.
Глобальные переменные
Глобальные переменные могут быть зарегистрированы в расширении с помощью метода getGlobals():
class Project_Twig_Extension extends \Twig\Extension\AbstractExtension implements \Twig\Extension\GlobalsInterface
{
public function getGlobals()
{
return [
'text' => new Text(),
];
}
// ...
}
Функции
Функции могут быть зарегистрированы в расширении с помощью метода getFunctions():
class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
public function getFunctions()
{
return [
new \Twig\TwigFunction('lipsum', 'generate_lipsum'),
];
}
// ...
}
Фильтры
Чтобы добавить фильтр в расширение, необходимо переопределить метод getFilters(). Этот метод должен вернуть массив фильтров для добавления в среду Twig:
class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
public function getFilters()
{
return [
new \Twig\TwigFilter('rot13', 'str_rot13'),
];
}
// ...
}
Теги
Добавление тега в расширение можно выполнить путём переопределения метода getTokenParsers(). Этот метод должен вернуть массив тегов для добавления в среду Twig:
class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
public function getTokenParsers()
{
return [new Project_Set_TokenParser()];
}
// ...
}
В приведенном выше коде мы добавили один новый тег, определённый классом Project_Set_TokenParser. Класс Project_Set_TokenParser отвечает за разбор тега и его компиляцию в PHP.
Операторы
Метод getOperators() позволяет добавлять новые операторы. Вот как добавить операторы !, ||, и &&:
class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
public function getOperators()
{
return [
[
'!' => ['precedence' => 50, 'class' => '\Twig\Node\Expression\Unary\NotUnary'],
],
[
'||' => ['precedence' => 10, 'class' => '\Twig\Node\Expression\Binary\OrBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT],
'&&' => ['precedence' => 15, 'class' => '\Twig\Node\Expression\Binary\AndBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT],
],
];
}
// ...
}
Тесты
Метод getTests() позволяет добавлять новые функции тестов:
class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
public function getTests()
{
return [
new \Twig\TwigTest('even', 'twig_test_even'),
];
}
// ...
}
Определение против выполнения
Реализации фильтров, функций и тестов Twig могут быть определены как любой допустимый вызываемый объект PHP:
- функции/статические методы: Просты в реализации и быстры (используются всеми расширениями ядра Twig); но сложно для среды выполнения зависеть от внешних объектов;
- замыкания: Просты в реализации;
- методы объектов: Более гибкие и необходимы, если ваш код среды выполнения зависит от внешних объектов.
Самый простой способ использования методов — определение их в самом расширении:
class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
private $rot13Provider;
public function __construct($rot13Provider)
{
$this->rot13Provider = $rot13Provider;
}
public function getFunctions()
{
return [
new \Twig\TwigFunction('rot13', [$this, 'rot13']),
];
}
public function rot13($value)
{
return $this->rot13Provider->rot13($value);
}
}
Это очень удобно, но не рекомендуется, так как это делает компиляцию шаблонов зависимой от зависимостей среды выполнения, даже если они не нужны (например, подумайте о зависимости, которая подключается к СУБД).
Начиная с Twig 1.26, вы можете отделить определения расширения от их реализаций среды выполнения, зарегистрировав экземпляр \Twig\RuntimeLoader\RuntimeLoaderInterface в среде, который знает, как создавать такие классы среды выполнения (классы среды выполнения должны быть загружаемыми через автозагрузчик):
class RuntimeLoader implements \Twig\RuntimeLoader\RuntimeLoaderInterface
{
public function load($class)
{
// implement the logic to create an instance of $class
// and inject its dependencies
// most of the time, it means using your dependency injection container
if ('Project_Twig_RuntimeExtension' === $class) {
return new $class(new Rot13Provider());
} else {
// ...
}
}
}
$twig->addRuntimeLoader(new RuntimeLoader());
Примечание
Начиная с Twig 1.32, Twig поставляется с совместимым с PSR-11 загрузчиком среды выполнения (\Twig\RuntimeLoader\ContainerRuntimeLoader).
Теперь можно перенести логику среды выполнения в новый класс Project_Twig_RuntimeExtension и использовать его непосредственно в расширении:
class Project_Twig_RuntimeExtension
{
private $rot13Provider;
public function __construct($rot13Provider)
{
$this->rot13Provider = $rot13Provider;
}
public function rot13($value)
{
return $this->rot13Provider->rot13($value);
}
}
class Project_Twig_Extension extends \Twig\Extension\AbstractExtension
{
public function getFunctions()
{
return [
new \Twig\TwigFunction('rot13', ['Project_Twig_RuntimeExtension', 'rot13']),
// or
new \Twig\TwigFunction('rot13', 'Project_Twig_RuntimeExtension::rot13'),
];
}
}
Тестирование расширения
Функциональные тесты
Вы можете создать функциональные тесты для расширений, создав следующую структуру файлов в каталоге тестов:
Fixtures/
filters/
foo.test
bar.test
functions/
foo.test
bar.test
tags/
foo.test
bar.test
IntegrationTest.php
Файл IntegrationTest.php должен выглядеть следующим образом:
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 можно найти в каталоге tests/Twig/Fixtures репозитория Twig.
Тесты узлов
Тестирование посетителей узлов может быть сложным, поэтому расширяйте ваши тестовые случаи из \Twig\Test\NodeTestCase. Примеры можно найти в каталоге tests/Twig/Node репозитория Twig.
© 2009–2018 by the Twig Team
Licensed under the three clause BSD license.
The Twig logo is © 2010–2020 Symfony
https://twig.symfony.com/doc/1.x/advanced.html