Search
Write a publication
Pull to refresh

Создание Twig Extension для Symfony2 на примере пейджера

Решил написать свою первую статью, ориентирована она в основном на новичков, так что «старожилы» сильно не пинайте. Речь пойдет о создании Twig Extension для Symfony2. В качестве примера я решил взять создание «пейджера», не лучший вариант реализации для «пейджера», но довольно неплохой для понимания того, как устроены и зачем нужны Twig Extension в Symfony2.

Для чего можно их использовать? Например, вывод 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);
    }

}

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.