Решил написать свою первую статью, ориентирована она в основном на новичков, так что «старожилы» сильно не пинайте. Речь пойдет о создании Twig Extension для Symfony2. В качестве примера я решил взять создание «пейджера», не лучший вариант реализации для «пейджера», но довольно неплохой для понимания того, как устроены и зачем нужны Twig Extension в Symfony2.
Для чего можно их использовать? Например, вывод html блоков, которые используются в различных частях приложения, тот же «пейджер» или какой-нибудь индикатор. Второй вариант для модификации каких-нибудь данных, например, какой-нибудь специфичный формат цены, который используется по всему приложению, использование Twig Extension позволит его легко менять из одного места и не смотреть постоянно как он выводится в определенном месте приложения.
Итак, начнем!
Первый делом в директории «Twig» нашего Bundle создаем класс и наследуем его от класса «Twig_Extension» (в конце статьи будет приведен полный код класса). Получаем файл по следующему пути «AppBundle\Twig\AppPagerExtension.php». В классе объявляем публичный метод «getName()» в котором возвращаем строку с именем нашего Twig Extension.
Далее создаем публичный метод, который будет возвращать функции доступные в Twig шаблонизаторе и методы, которые эти функции вызывают. У нас будет одна функция, отображение «пейджера».
Я думаю, тут все понятно, «show_pager» — функция, которая будет вызываться в Twig'e, «ShowPagerFunction» — метод, который мы создадим далее в классе и который будет обрабатывать данные и выводить «пейджер».
Вот и сам метод, в него мы передаем "\Twig_Environment $environment" в том случае, если для вывода данных мы будем использовать шаблон. В данном случае мы его используем «AppBundle:TwigExtension:pager.html.twig» (где ее создать и его код опишу ниже), $current_page — текущая страница, сделано отчасти для наглядности, т. к. текущую страницу мы могли бы определять в шаблоне, $page_count — количество страниц, $route — текущий route для создания ссылок «пейджера», опять же создан для наглядность, т к его мы тоже можем определить в шаблоне, нижу покажу как.
Теперь нам осталось создать файл шаблона, в нашем Bundle в директории «views», создаем директорию «TwigExtension» а в ней файл «pager.html.twig» со следующим кодом:
Этот шаблон выводит «пейджер» с ссылками «первая, последняя, предыдущая, следующая». Опять же шаблон создан исключительно в обучающих целях, т.к., например, если у вас будет 100 страниц, он и выведет всю нумерацию, что является неверным решением.
Как я писал выше, переменные «route» и «current_page» мы могли бы определить в конфиге следующим образом:
Почти все готово, осталось только описать наш Twig Extension в конфиге, чтобы мы могли его использовать. Открываем файл «services.yml» и описываем наш класс:
Все, теперь в шаблоне мы можем его вызвать следующим образом:
Хотелось бы еще добавить, что в одном классе можно описать множество функций, а также что шаблоны можно не использовать а возвращать просто значения, пример можно посмотреть в документации Symfony2, реализация вывода цены .
P. S. Данный пример не претендует на использование и создан лишь в учебных целях и в любом случае требует доработок.
Для чего можно их использовать? Например, вывод html блоков, которые используются в различных частях приложения, тот же «пейджер» или какой-нибудь индикатор. Второй вариант для модификации каких-нибудь данных, например, какой-нибудь специфичный формат цены, который используется по всему приложению, использование Twig Extension позволит его легко менять из одного места и не смотреть постоянно как он выводится в определенном месте приложения.
Итак, начнем!
Первый делом в директории «Twig» нашего Bundle создаем класс и наследуем его от класса «Twig_Extension» (в конце статьи будет приведен полный код класса). Получаем файл по следующему пути «AppBundle\Twig\AppPagerExtension.php». В классе объявляем публичный метод «getName()» в котором возвращаем строку с именем нашего Twig Extension.
public function getName()
{
return 'app_pager_extension';
}
Далее создаем публичный метод, который будет возвращать функции доступные в Twig шаблонизаторе и методы, которые эти функции вызывают. У нас будет одна функция, отображение «пейджера».
public function getFunctions()
{
return array(
new \Twig_SimpleFunction(
'show_pager',
array($this, 'ShowPagerFunction'),
array(
'is_safe' => array('html'),
'needs_environment' => true,
)
),
);
}
Я думаю, тут все понятно, «show_pager» — функция, которая будет вызываться в Twig'e, «ShowPagerFunction» — метод, который мы создадим далее в классе и который будет обрабатывать данные и выводить «пейджер».
public function ShowPagerFunction(\Twig_Environment $environment, $current_page, $page_count, $route)
{
$renderArray = array(
'current_page' => $current_page,
'page_count' => $page_count,
'route' => $route,
);
return $environment->render('AppBundle:TwigExtension:pager.html.twig', $renderArray);
}
Вот и сам метод, в него мы передаем "\Twig_Environment $environment" в том случае, если для вывода данных мы будем использовать шаблон. В данном случае мы его используем «AppBundle:TwigExtension:pager.html.twig» (где ее создать и его код опишу ниже), $current_page — текущая страница, сделано отчасти для наглядности, т. к. текущую страницу мы могли бы определять в шаблоне, $page_count — количество страниц, $route — текущий route для создания ссылок «пейджера», опять же создан для наглядность, т к его мы тоже можем определить в шаблоне, нижу покажу как.
Теперь нам осталось создать файл шаблона, в нашем Bundle в директории «views», создаем директорию «TwigExtension» а в ней файл «pager.html.twig» со следующим кодом:
{% if page_count > 1 %}
<div class="item-list">
<ul class="pager">
{% if current_page != 1 %}
<li class="pager-first first"><a title="На первую страницу" href="{{ path(route, {'page': 1}) }}">« первая</a></li>
<li class="pager-first first"><a title="На предыдущую страницу" href="{{ path(route, {'page': current_page - 1}) }}">« предыдущая</a></li>
{% endif %}
{% for page in 1..page_count %}
{% if (page == current_page) %}
<li class="pager-item pager-current">{{ page }}</li>
{% else %}
<li class="pager-item">
<a title="На страницу номер {{ page }}" href="{{ path(route, {'page': page}) }}">{{ page }}</a>
</li>
{% endif %}
{% endfor %}
{% if current_page != page_count %}
<li class="pager-first first"><a title="На следующую страницу" href="{{ path(route, {'page': current_page + 1}) }}">следующая ›</a></li>
<li class="pager-first first"><a title="На последнюю страницу" href="{{ path(route, {'page': page_count}) }}">последняя »</a></li>
{% endif %}
</ul>
</div>
{% endif %}
Этот шаблон выводит «пейджер» с ссылками «первая, последняя, предыдущая, следующая». Опять же шаблон создан исключительно в обучающих целях, т.к., например, если у вас будет 100 страниц, он и выведет всю нумерацию, что является неверным решением.
Как я писал выше, переменные «route» и «current_page» мы могли бы определить в конфиге следующим образом:
{% set route = app.request.attributes.get('_route') %}
{% set current_page = app.request.query.get("page") %}
Почти все готово, осталось только описать наш Twig Extension в конфиге, чтобы мы могли его использовать. Открываем файл «services.yml» и описываем наш класс:
services:
#twig extensions
app.twig.undercity_pager_extension:
class: AppBundle\Twig\AppPagerExtension
tags:
- { name: twig.extension }
Все, теперь в шаблоне мы можем его вызвать следующим образом:
{{ show_pager(page, pages, 'article-list') }}
Хотелось бы еще добавить, что в одном классе можно описать множество функций, а также что шаблоны можно не использовать а возвращать просто значения, пример можно посмотреть в документации Symfony2, реализация вывода цены .
P. S. Данный пример не претендует на использование и создан лишь в учебных целях и в любом случае требует доработок.
P.P.S Полный код нашего класса
<?php
namespace AppBundle\Twig;
class AppPagerExtension extends \Twig_Extension {
public function getName()
{
return 'app_pager_extension';
}
public function getFunctions()
{
return array(
new \Twig_SimpleFunction(
'show_pager',
array($this, 'ShowPagerFunction'),
array(
'is_safe' => array('html'),
'needs_environment' => true,
)
),
);
}
/**
*
* @param \Twig_Environment $environment
* @param int $current_page
* @param int $per_page
* @param int $page_count
* @return string
*/
public function ShowPagerFunction(\Twig_Environment $environment, $current_page, $page_count, $route)
{
$renderArray = array(
'current_page' => $current_page,
'page_count' => $page_count,
'route' => $route,
);
return $environment->render('AppBundle:TwigExtension:pager.html.twig', $renderArray);
}
}