Раньше я был ярым поклонником Smarty. У Smarty достаточно много достоинств, он распространен, с ним просто, он привычен и так далее. Но так вышло, что для одного из проектов Smarty оказался слишком уж тяжелым и слегка тормозным. Я не говорю, что Smarty плох или что он негодный, нет. Просто в некоторых условиях его производительность оказалась недостаточной, и надо было искать альтернативу. Альтернатива нашлась и я очень рад, что мне выпала возможность работать с Twig.
Smarty был второй версии, в комментариях верно замечают, что третья версия имеет отличия и часто значительные.
В первую очередь я попытался подстроить Twig под синтаксис Smarty, так как тот мне был привычен, понятен и приятен. Сделать это можно, пускай и не в полной мере. Вот так:
При инициализации объявляем в массиве tag_comment, tag_block и tag_valiable. Теперь можно как в Smarty выводить переменные. При переходе достаточно удобно, но сейчас я понимаю, что лучше было бы этого не делать. Синтаксис становится неоднородным.
К некоторым вещам все же пришлось привыкать и некоторое время заглядывать в документацию, чтобы ничего не напутать. Например обход массивов
Вместо
Обратите внимание, что в Twig не смотря на переопределение тэга переменной знак доллара перед именем переменной не ставится. Если бы не переход со Smarty — было бы удобнее.
Блоки закрываются не {/if} а {endif}. Тоже по началу путаешься.
Или, например, блоки которые не надо обрабатывать шаблонизатором.
{raw} {endraw} вместо {literal}{/literal}.
Все это мелкие подстройки и связанная с переходом адаптация. Скорее всего это даже усложнено тем, что синтаксис похож.
К чему я привык работая со Smarty?
Во-первых это структура шаблонов. Шаблоны дробились на шапку, основное тело и подвал. Также боковые блоки и другие блоки тоже иногда выделялись. Дальше все это дело подключалось в основном шаблоне в порядке следования. Теперь я понимаю, что это совсем не круто. Наследование – вот это круто! Страницы сайта зачастую построены по одному принципу, либо есть несколько типов страниц со своей организацией. Шапка/подвал везде одинаковая зачастую, а вот левое/правое меню может скакать то влево, то вправо, либо на части страниц его может не быть вовсе. В Smarty я бы стал городить условия и подключать нужный шаблон, в нем подключать еще один шаблон и так далее. В Twig все иначе. Здесь, как и в ООП шаблоны наследуются друг от друга, можно переопределять части шаблонов. Это просто здорово. Движение фактически в другую сторону – не от главного шаблона к дочерним, а отображая конечный шаблон он собирается из родителей их родителей и так до корня.
Строим основной шаблон с шапкой/подвалом, можно даже боковыми блоками, а потом наследуем от него другие шаблоны, более низкого уровня. В них запросто переопределяем боковой блок. Например, можно от основного шаблона унаследовать шаблон с левым меню и шаблон с правым меню. Что там выше, кто от кого наследуется — дело только тех, кто выше. А потом в зависимости оттого, что нам требуется – наследовать конечный шаблон либо от шаблона с правым меню, либо от шаблона с левым меню. А потом можем передумать и унаследовать шаблон не от шаблона левого меню, а от шаблона правого меню. Такая простота, прозрачность и гибкость меня очень радует. Даже кардинальные изменения даются легко. Немного кода.
Основной родительский шаблон.
main.tpl
Теперь напишем страницу просто без меню.
left_menu.tpl
А теперь шаблон меню с левой стороны.
left_menu.tpl
И конечную страницу
В итоге конечные шаблоны не загромождаются подключениями, условиями и всем остальным. Просто говорим от чего наследуем шаблон, а дальше только по сути.
Работая со Smarty, я привык к тому, что надо передавать все переменные в шаблон и уже там их выводить, вся обработка была в коде. Часто даже форматирование приходилось делать до шаблонизатора, в итоге выходила мешанина. В Twig можно вообще управлять логикой исполнения из шаблона, без каких либо телодвижений. Если в выводе будет не название поля, а название метода, то в этом месте будет выведено возвращаемое методом значение. Т.е. если нам надо вывести какое-то подсчитываемое значение, то его не нужно подсчитывать заранее, это будет произведено непосредственно при выводе.
И все. Не надо об этом заранее думать – все отработает и отработает быстро. Неприятным моментом было то, что если поле класса приватное, то выводить twig его не станет, даже если в классе описан геттер.
И третье это написание собственных расширений. Часто бывают нужны какие-то функции, не реализованные в шаблонизаторе. Расширяется twig крайне просто. Например нам нужно типографить вывод. Выборочно.
И подключаем его на этапе инициализации.
Теперь шаблоне для тех переменных которые нам надо обработать – просто дописываем модификатор – {$page.content|typograph} и все, значение будет обработано. Не нужно сначала перебирать все значения до передачи их шаблонизатору и обрабатывать. Шаблонизатор все равно будет обходить массив для выхода — так это делается один раз, а не два. Расширение можно написать одно и потом дополнять его нужными функциями.
После Twig-a в сторону Smarty смотреть не очень хочется. Как то уж слишком легко и логично все получается вместе с ним.
Smarty был второй версии, в комментариях верно замечают, что третья версия имеет отличия и часто значительные.
В первую очередь я попытался подстроить Twig под синтаксис Smarty, так как тот мне был привычен, понятен и приятен. Сделать это можно, пускай и не в полной мере. Вот так:
$loader = new Twig_Loader_Filesystem('/templates');
$twig = new Twig_Environment($loader,array('charset'=>' utf -8','cache'=>'/templ_c','auto_reload'=>true));
$escaper = new Twig_Extension_Escaper(true);
$twig->addExtension($escaper);
$lexer = new Twig_Lexer($twig, array(
'tag_comment' => array('{*', '*}'),
'tag_block' => array('{', '}'),
'tag_variable' => array('{$', '}'),
));
$twig->setLexer($lexer);
При инициализации объявляем в массиве tag_comment, tag_block и tag_valiable. Теперь можно как в Smarty выводить переменные. При переходе достаточно удобно, но сейчас я понимаю, что лучше было бы этого не делать. Синтаксис становится неоднородным.
К некоторым вещам все же пришлось привыкать и некоторое время заглядывать в документацию, чтобы ничего не напутать. Например обход массивов
{for category in category_tree}
{$category.name}
{endfor}
Вместо
{foreach from=$category_tree item=category}
{$category.name}
{/foreach}
Обратите внимание, что в Twig не смотря на переопределение тэга переменной знак доллара перед именем переменной не ставится. Если бы не переход со Smarty — было бы удобнее.
Блоки закрываются не {/if} а {endif}. Тоже по началу путаешься.
Или, например, блоки которые не надо обрабатывать шаблонизатором.
{raw} {endraw} вместо {literal}{/literal}.
Все это мелкие подстройки и связанная с переходом адаптация. Скорее всего это даже усложнено тем, что синтаксис похож.
К чему я привык работая со Smarty?
Во-первых это структура шаблонов. Шаблоны дробились на шапку, основное тело и подвал. Также боковые блоки и другие блоки тоже иногда выделялись. Дальше все это дело подключалось в основном шаблоне в порядке следования. Теперь я понимаю, что это совсем не круто. Наследование – вот это круто! Страницы сайта зачастую построены по одному принципу, либо есть несколько типов страниц со своей организацией. Шапка/подвал везде одинаковая зачастую, а вот левое/правое меню может скакать то влево, то вправо, либо на части страниц его может не быть вовсе. В Smarty я бы стал городить условия и подключать нужный шаблон, в нем подключать еще один шаблон и так далее. В Twig все иначе. Здесь, как и в ООП шаблоны наследуются друг от друга, можно переопределять части шаблонов. Это просто здорово. Движение фактически в другую сторону – не от главного шаблона к дочерним, а отображая конечный шаблон он собирается из родителей их родителей и так до корня.
Строим основной шаблон с шапкой/подвалом, можно даже боковыми блоками, а потом наследуем от него другие шаблоны, более низкого уровня. В них запросто переопределяем боковой блок. Например, можно от основного шаблона унаследовать шаблон с левым меню и шаблон с правым меню. Что там выше, кто от кого наследуется — дело только тех, кто выше. А потом в зависимости оттого, что нам требуется – наследовать конечный шаблон либо от шаблона с правым меню, либо от шаблона с левым меню. А потом можем передумать и унаследовать шаблон не от шаблона левого меню, а от шаблона правого меню. Такая простота, прозрачность и гибкость меня очень радует. Даже кардинальные изменения даются легко. Немного кода.
Основной родительский шаблон.
main.tpl
<!doctype html>
<head>
<title>{block html_title}Заголовок по умолчанию{endblock}</title>
</head>
<html>
<div class=”header”>Содержимое шапки</div>
<div class=”body”>
{block content}
Здесь ничего нет. {*Если мы не переопределим содержимое блока, то страница все равно не будет пустой.*}
{endblock}
</div>
<div class=”footer”></div>
</html>
Теперь напишем страницу просто без меню.
left_menu.tpl
{extends "main.tpl "}
{block html_title}Главная страница{endblock} {*Переопределяем заголовок страницы*}
{block content}
Тут содержимое главной страницы. Это содержимое заменит определенный в родительском шаблоне текст.
{endblock}
А теперь шаблон меню с левой стороны.
left_menu.tpl
{extends "main.tpl "}
{block content}
<div class=”left_menu”>
{*Выводим список каких-то категорий*}
{for category in category_tree}
<a href=”?{$category.id}”>{$category.name}</a>
{endfor}
</div>
<div class=”content”>
{block page_content} {* Обратите внимание, блок не может называеться content, так как такой блок уже есть. *}
Здесь ничего нет.
{endblock}
</div>
{endblock}
И конечную страницу
{extends "left_menu.tpl "}
{block html_title}Конечная страница{endblock}
{endblock}
{block page_content}
Содержимое страницы с меню. На этой странице переопределен заголовок страницы, заданный в самом первом, основном шаблоне.
{endblock}
В итоге конечные шаблоны не загромождаются подключениями, условиями и всем остальным. Просто говорим от чего наследуем шаблон, а дальше только по сути.
Работая со Smarty, я привык к тому, что надо передавать все переменные в шаблон и уже там их выводить, вся обработка была в коде. Часто даже форматирование приходилось делать до шаблонизатора, в итоге выходила мешанина. В Twig можно вообще управлять логикой исполнения из шаблона, без каких либо телодвижений. Если в выводе будет не название поля, а название метода, то в этом месте будет выведено возвращаемое методом значение. Т.е. если нам надо вывести какое-то подсчитываемое значение, то его не нужно подсчитывать заранее, это будет произведено непосредственно при выводе.
// Класс пользователя
class User
{
public function free_space()
{
// Что-то вычисляем, проверяем наличие свободного места.
Return $result;
}
}
В шаблоне вызываем:
{$user.free_space}
И все. Не надо об этом заранее думать – все отработает и отработает быстро. Неприятным моментом было то, что если поле класса приватное, то выводить twig его не станет, даже если в классе описан геттер.
И третье это написание собственных расширений. Часто бывают нужны какие-то функции, не реализованные в шаблонизаторе. Расширяется twig крайне просто. Например нам нужно типографить вывод. Выборочно.
class My_Twig_Extension extends Twig_Extension
{
// Этот метод должен быть объявлен обязательно.
public function getFilters()
{
return array(
'typograph => new Twig_Filter_Method($this, 'typograph')
);
}
public function typograph($text)
{
return $typograph->parse($text); // тут собственно типограф работает с передаваемым ему текстом.
}
}
И подключаем его на этапе инициализации.
$twig->addExtension(new My_Twig_Extension());
Теперь шаблоне для тех переменных которые нам надо обработать – просто дописываем модификатор – {$page.content|typograph} и все, значение будет обработано. Не нужно сначала перебирать все значения до передачи их шаблонизатору и обрабатывать. Шаблонизатор все равно будет обходить массив для выхода — так это делается один раз, а не два. Расширение можно написать одно и потом дополнять его нужными функциями.
После Twig-a в сторону Smarty смотреть не очень хочется. Как то уж слишком легко и логично все получается вместе с ним.