symfony4 Хелпер для пейджинации, шаблон переключения страниц (Pagination Helper)

Задача

Требуется разделить длинную ленту списка каких-либо строк на страницы.

Решение

Вот все файлы, которые нам потребуются:

  1. Универсальный twig-шаблон для отображения переключателя страниц. Можно инклудить в Ваш шаблон. Принимает переменные pageNumber (выбранная страница) и pageCount (общее количество страниц).
    {% set currentPage = pageNumber %}
    {% set previousPage = currentPage - 1 %}
    {% set nextPage = currentPage + 1 %}
    {% set pageCount = pageCount %}
    {% set route = app.request.attributes.get('_route') %}
    {% set firstPagePath = path(route, {'pageNumber': 1}) %}
    {% set previousPagePath = path(route, {'pageNumber': currentPage - 1}) %}
    {% set nextPagePath = path(route, {'pageNumber': currentPage + 1}) %}
    {% set lastPagePath = path(route, {'pageNumber': pageCount}) %}
    
    {% if 1 != currentPage %}
        <a href="{{ previousPagePath }}">
            предыдущая
        </a>
        {% if 1 != previousPage %}    
            <a href="{{ firstPagePath }}">
                1
            </a>
        {% endif %}
        {% if previousPage > 2 %}
            ...
        {% endif %}
        <a href="{{ previousPagePath }}">
            {{ previousPage }}
        </a>
    {% endif %}
            
    [{{ currentPage }}]
    
    {% if currentPage != pageCount %}
        <a href="{{ nextPagePath }}">
            {{ nextPage }}
        </a>
        {% if (pageCount - currentPage) > 2 %}
            ...
        {% endif %}
        {% if pageCount != nextPage %}
            <a href="{{ lastPagePath }}">
                {{ pageCount }}
            </a>
        {% endif %}
        <a href="{{ nextPagePath }}">
            следующая
        </a>
    {% endif %}
  2. Дата-объект, хранящий в себе информацию, необходимую для рендеринга отдельной страницы, а именно, pageCount (общее количество страниц) и currentLines (данные по строкам на выбранной странице). Номер выбранной страницы сюда не добавляем, т.к. его рассчитывать не надо, он и так известен. Количество строк на одной странице подгрузим автоматически из параметров.
    <?php
    
    namespace App\DTO;
    
    class PageData
    {
        /**
         * @var array
         */
        private $currentLines;
    
        /**
         * @var int
         */
        private $pageCount;
    
        /**
         * @param array $currentLines
         * @param int   $pageCount
         */
        public function __construct(
            array $currentLines,
            int $pageCount
        ) {
            $this->currentLines = $currentLines;
            $this->pageCount = $pageCount;
        }
    
        /**
         * @return array
         */
        public function getCurrentLines(): array
        {
            return $this->currentLines;
        }
    
        /**
         * @return int
         */
        public function getPageCount(): int
        {
            return $this->pageCount;
        }
    }
  3. И непосредственно php-класс для формирования информации, которую нужно передать в шаблон. Создадим универсальный хелпер, который можно будет использовать для любых массивов двнных:
    <?php
    
    namespace App\Helpers;
    
    use App\DTO\PageData;
    
    class PaginationHelper
    {
        /**
         * Переменная, содержащая количество строк на странице автозагружается из параметров
         * 
         * @var int
         */
        private $numberOfLinesPerPage;
    
        /**
         * @param int $numberOfLinesPerPage
         */
        public function __construct(int $numberOfLinesPerPage)
        {
            $this->numberOfLinesPerPage = $numberOfLinesPerPage;
        }
        
        /**
         * @param int   $currentPage
         * @param array $lines
         * 
         * @return PageData
         */
        public function getPageData(int $currentPage, array $lines): PageData
        {
            return new PageData(
                // выбираем только объекты, отображаемые на <em>currentPage</em>
                array_slice(
                    $lines,
                    $this->numberOfLinesPerPage * ($currentPage - 1),
                    $this->numberOfLinesPerPage
                ),
                // столько страниц у нас будет всего
                ceil(count($lines) / $this->numberOfLinesPerPage)
            );
        }
    }

В контроллере передаём формируемые данные в шаблон так:

        // ...
        // Данные с учётом пейджинации на данной странице
        $pageData = $this->paginationHelper->getPageData($page, $objects);
        
        return $this->render('objects.html.twig', [
            'objects' => $pageData->getCurrentLines(),
            'pageNumber' => $page,
            'pageCount' => $pageData->getPageCount(),
        ]);
}

Шаблон подключаем в нужном Вам месте:

{% include 'pagination.html.twig' %}

Приятной разработки! ♥

Источники