Наконец-то сделан репозитарий расширений Twig. В нем уже хранятся такие полезные расширения, как text фильтры, i18n и тэг debug.
Установить расширения очень просто, достаточно обеспечить их автозагрузку.
Запустить тест-кейсы тоже очень просто, так как надо настроить только путь до библиотеки Twig.
С релиза 0.9.8 прошло 5 месяцев, и вот готов Twig 0.9.9, было исправлено много ошибок, сделано много улучшений. К тому же, возможно, это последний релиз перед выходом Twig 1.0.
Как всегда, исправлено много ошибок и сделано много фишек для упрощения отладки. Полный список можно посмотреть в списке изменений.
Документация тоже обновлена, в соответствии с изменениями в коде.
В этом топике сообщается только о самых важных изменениях.
Основные изменения затронули интерфейс Node. Введен единый способ описания узлов и атрибутов. Дочерние узлы теперь доступны с помощью getNode() (вместо обращения к свойству) и атрибуты с помощью getAttribute() (вместо обращения к массиву). Переход на новую систему должен быть довольно легким.
Некоторые вещи были переименованы для большей ясности и согласованности:
Переменная self переименована в _self;
Фильтр safe переименован в raw;
Фильтр urlencode переименован в url_encode;
переименован в Twig_Error_Syntax;
Twig_RuntimeError переименован в Twig_Error_Runtime.
Так же сделаны несколько мелких изменений:
Фильтры odd и even теперь можно использовать по другому (смотрите новый функционал): вместо {{ foo|odd }} писать {{ foo is odd }};
Тэг include теперь объединяет переданные переменные с текущими по умолчанию (раньше надо было добавлять ключевое слово only в конец тэга);
Удаленна поддержка {{ 1 < i < 3 }} (используйте {{ i > 1 and i < 3 }});
Фильтр “in” был удален ({{ a|in(b) }} теперь надо писать {{ a in b }})
Все исключения в Twig наследуются от Twig_Error.
Один из лучших аспектов Twig - система автоматического экранирования. Увы, раньше реализация была не самая хорошая. После продолжительных споров, Arnaud Le Blanc предложил разработать более эффективное решение. В настоящий момент код основан на его работе и работе помогавших ему людей. Большое им спасибо за их превосходную работу. Дискуссия еще не окончена, если вы хотите в ней поучаствовать.
Добавлен новый оператор is. Интересно, лучше ли он обычных выражений? Пример использования:
{% if name is odd %}
{# проверка существует ли переменная (полезно, когда используется режим strict_variables) #}
{% if article is defined %}
{% if loop.index is divisibleby(3) %}
{% if loop.index is not divisibleby(3) %}
В документации есть полный список новинок.
Как и в любом другом новом релизе Twig, добавлены новые теги, фильтры и операторы:
** (возведение в степень);spaceless;{{ 1 not in [2, 3] }} (это проще воспринимать чем {{ not (1 in [2, 3]) }});constant, trans, replace, json_encode;_charset содержащая текущую кодировку;_context содержащая текущий контент.В течении последних месяцев, была сильно оптимизирована работа Twig.
Наследование шаблонов было переписано с целью лучшей имитации "реальных" классов (блоки теперь можно вызывать напрямую)
Алгоритм разбора выражений был изменен для обеспечения большей гибкости. Теперь вы можете добавлять собственные операторы из расширений. На самом деле, все встроенные операторы теперь являются частью расширений ядра.
Twig 0.9.8 это технический релиз, исправляющий несколько не очень существенных багов.
Этот релиз обратно не совместим для тэга trans:
[twig]
{# старый синтаксис #}
{% trans count %}...{% plural %}...{% endtrans %}
{# новый синтаксис #}
{% trans %}...{% plural count %}...{% endtrans %}
Полный список исправленных багов:
{% trans var %})trans при включеном расширении EscaperTwig_Template из вывода тэга debug__isset()setTwig_Environment::addFilter()Всего месяц назад вышел Twig 0.9.6, а сегодня уже доступен Twig 0.9.7
Как всегда документация обновлена и лог правок содержит все сделанные изменения. В этом посте упомянуты только основные изменения.
setСинтаксис тэга set изменен для улучшения читабельности
{# до 0.9.7 #}
{% set title as "Title" %}
{# начиная с 0.9.7 #}
{% set title = "Title" %}
includeУдален атрибут sandboxed тэга include, так как введен новый тэг – sandbox:
{# до 0.9.7 #}
{% include "foo.twig" sandboxed %}
{# начиная с 0.9.7 #}
{% sandbox %}
{% include "foo.twig" %}
{% endsandbox %}
Тэг include также принимает в качестве аргумента объект класса Twig_Template.
Подсистема узлов была подвергнута рефакторингу. Если у вас есть свои собственные тэги, вам необходимо обновить их, используя новый API:
Класс Twig_NodeList удален. Если ваш тэг наследует его, просто заменить базовый класс на Twig_Node и удалить методы getNodes() и setNodes().
Метод __toString() теперь генерируется автоматически базовым классом Twig_Node. Т.е. вы можете безбоязненно удалить свою реализацию этого метода.
Основные изменения касаются конструктора (подробнее можно почитать в описании Twig_Node)
Уже описано здесь
sandboxКак уже упоминалось, доступен новый тэг sandbox:
{% sandbox %}
{% include "foo.twig" %}
{% include "bar.twig" %}
{% endsandbox %}
strict_variablesПо умолчанию Twig просто игнорирует неопределенные переменные. Это хорошо для рабочего проекта, но вызывает сложности при отладке. Параметр strict_variables управляет этим поведением Twig, и по умолчанию он отключен. Если же присвоить ему true, неопределенные переменные будут вызывать исключения.
Когда разработчику надо создать новый тэг, ему приходиться разобраться со многими понятиями: токены, потоки токенов, парсеры, компиляторы. Конечно, он может просто скопировать существующий код, но это не очень хорошо. В Twig 0.9.7 добавлен новый высокоуровневый API, облегчающий создание новых тэгов. Это API экспериментальное и может в будущем измениться, кроме того, документация пока не готова.
До обновления внимательно прочитайте топик, так как этот релиз может сломать ваш код. Затем действуйте как обычно:
Установите новую версию (через PEAR, SVN, Git или скачав новый архив);
Удалите закэшированные шаблоны;
Проверьте.
Сегодня мы поговорим о наследовании шаблонов. С тех пор как был создан Twig, очень многие интересуются – как делать динамические и/или условные шаблоны.
До версии Twig 0.9.6 включительно, тэг extends мог использоваться используется только со статическим именем шаблона.
{% extends "layout.twig" %}
...
Но что если вы хотите изменять имя макета? Скажем в зависимости от того является запрос AJAX или нет? Это стало возможным в Twig 0.9.7.
Во-первых, можно хранить название макета в переменной и передавать ее в шаблон.
{% extends layout %}
Здесь layout – это строковая переменная, которая содержит название шаблона и ее значение задается в контроллере, в зависимости от заголовка запроса.
Но есть и другой способ. Если вы хотите принять решение о подключаемом макете непосредственно в самом шаблоне, можно сделать следующее:
{% extends is_ajax ? 'layout_ajax.twig' : 'layout.twig' %}
Фактически, именем шаблона может быть любое валидное выражение (как это уже сделано с тэгом include); итак, теперь разрешено такое использование тэга extends:
{% extends 'layout' ~ extension %}
Вместо того, чтобы передавать шаблон как строку, вы можете передать непосредственно сам шаблон Twig_Template:
// {% extends layout %}
$layout = $twig->loadTemplate('some_layout_template.twig');
$twig->display('template.twig', array('layout' => $layout));
Заметьте, что аналогичная возможность добавлена и в тэг include:
// {% include template %}
// {% include template %}
$template = $twig->loadTemplate('some_template.twig');
$twig->display('template.twig', array('template' => $template));
Поддержка динамического наследования шаблонов была не простой задачей, так как Twig основывался на наследование классов в PHP. И, конечно, невозможно динамически менять родительский класс в PHP:
$bar = 'SomeBaseClass';
class Foo extends $bar
{
// ...
}
Итак, Twig не использует больше PHP наследование, а просто имитирует его. Тесты производительности показывают, что скорость работы понижается незначительно. Уверен, что этот дает много возможностей и повышает гибкость приложения.
Если вам интересны подробности в коде – взгляните на лог изменений.
Я рад представить вам Twig 0.9.6. Это технический релиз, где исправлены некоторые ошибки и добавлено несколько новых особенностей. До того как выйдет Twig 1.0 осталось два основных тикета.
Кроме исправления ошибок и новых особенностей, есть два примечательных изменения внутри Twig (однако мало важные для пользователей библиотеки): для юнит-тестов используется PHPUnit и код оформлен в соответствии в стандартами PEAR .
Документация обновлена в соответствии со сделанными изменениями новой версии.
Дальше будет рассказано об основных изменениях, но если вы хотите знать все подробности – загляните в лог правок.
Обратная совместимость соблюдена, обновление от 0.9.5 должно быть безопасным:
Мы исправили несколько ошибок, основные из них:
mbstring.func_overload использовалась вместе с mbstring.internal_encoding для кодировок отличных от ASCII;i18nБлагодаря расширению i18n вы можете использовать различные языки в шаблонах. Это расширение работает только если подключено расширение PHP gettext.
Используйте тэг trans для того, чтобы отметить какая часть шаблона должна быть переведена:
{% trans %}
Hello World!
{% endtrans %}
Вы можете использовать внутри переменные, если это необходимо:
{% trans %}
Hello {{ name }}!
{% endtrans %}
Используйте тэг plural для перевода множественных числительных:
{% trans apple_count %}
Hey {{ name }}, I have one apple.
{% plural %}
Hey {{ name }}, I have {{ count }} apples.
{% endtrans %}
__call()Twig теперь использует __call() для обращения к методам переменных.
Новый алгоритм обращения к методам объекта следующий:
$object (используя reflectionObject);$item в списке методов;get$item в списке методов;__call и передаем $item как имя метода.setТэг set теперь поддерживает расширенный синтаксис. Это весьма удобно, если вам надо сохранить в переменной кусок HTML:
{% set foo %}
<div id="pagination">
...
</div>
{% endset %}
cycleФильтр cycle может быть использован для перечисления между элементами массива:
{% for i in 0..10 %}
{{ ['odd', 'even']|cycle(i) }}
{% endfor %}
Массив может содержать любое число элементов:
{% set fruits as ['apple', 'orange', 'citrus'] %}
{% for i in 0..10 %}
{{ fruits|cycle(i) }}
{% endfor %}