
21 Cze Paginacja w Symfony – Knp Paginator Bundle
Bardzo często pierwsza aplikacją, na której szlifujemy swoje umiejętności jest blog. Nawet samo Symfony dało możliwość jedną komendą postawienia bloga, który przedstawia rekomendowaną strukturę. Teraz nastały czasy, że wszyscy scrollują, Facebook, Instagram itd. więc paginacja odeszła do lamusa. Czyżby? Tak na prawdę przybrała inną postać. Nieustanne scrollowanie też jest swego rodzaju dostarczaniem danych paczkami, przecież wchodząc na Facebooka nie dostajesz od razu wczytanej całej swojej tablicy, a jedynie fragment. Dzisiaj pokaże Ci jedno wielu rozwiązań implementacji i czym jest sama paginacja w Symfony.
Dla tego posta postawiłam właśnie czystą aplikacje ze szkieletu Symfony. Wystarczyło tylko odpalić:
composer create-project symfony/skeleton blog
Oczywiście doinstalować jeszcze pare innych paczek jak doctrine czy twig.
Czym jest paginacja?
Paginacja to nic innego jak stronicowanie/porcjowanie treści. Bardzo dobrze wpływa na wydajność strony internetowej, ponieważ nie renderuje się od razu wszystkich rekordów, a tylko część przez co czas oczekiwania jest znacznie krótszy. Jest także dobrym rozwiązaniem pod kątem SEO, ponieważ każda ze stron ma osobny adres i pozycjonuje się oddzielnie. Jednak z meta danymi trzeba uważać żeby nie wygenerować stron z takim samy opisem meta i innymi parametrami.
KNP Paginator Bundle
Po co utrudniać sobie życie i wymyślać koło na nowo. Moim zdaniem ważne jest aby umieć sobie ułatwiać życie gotowymi paczkami jednocześnie nie podchodząc do nich bezkrytycznie.
Do paginacji przyda się nam bundle od Knp Labs, instalacja jak zwykle bardzo prosta. Co ważne ten bundle wspiera SEO więc nie musimy się matrwić o to co pisałam powyżej.
composer require knplabs/knp-paginator-bundle
Następnie musimy do skonfigurować, w tym celu należy stworzyć plik config/packages/knp_paginator.yml z treścią
knp_paginator: page_range: 3 # number of links showed in the pagination menu (e.g: you have 10 pages, a page_range of 3, on the 5th page you'll see links to page 4, 5, 6) default_options: page_name: page # page query parameter name sort_field_name: sort # sort field query parameter name sort_direction_name: direction # sort direction query parameter name distinct: true # ensure distinct results, useful when ORM queries are using GROUP BY statements filter_field_name: filterField # filter field query parameter name filter_value_name: filterValue # filter value query parameter name template: pagination: '@KnpPaginator/Pagination/twitter_bootstrap_v4_pagination.html.twig' # sliding pagination controls template sortable: '@KnpPaginator/Pagination/sortable_link.html.twig' # sort link template filtration: '@KnpPaginator/Pagination/filtration.html.twig' # filters template
Zastosowanie
Skoro już mamy zainstalowaną i skonfigurowaną paczkę przyszedł czas aby ją użyć i sprawdzić jej możliwości. Zacznijmy od Controllera.
<?php declare(strict_types=1); namespace App\Controller\Controller; use App\Repository\ArticleRepository; use Knp\Component\Pager\PaginatorInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class ArticleController extends AbstractController { /** * @var ArticleRepository */ private $articleRepository; /** * @var PaginatorInterface */ private $paginator; /** * @param ArticleRepository $articleRepository * @param PaginatorInterface $paginator */ public function __construct( ArticleRepository $articleRepository, PaginatorInterface $paginator ) { $this->articleRepository = $articleRepository; $this->paginator = $paginator; } /** * @Route("/article/list/{page}", methods={"GET"}) */ public function list(string $page): Response { $articles = $this->articleRepository->findAll(); $articles = $this->paginator->paginate($articles, $page, ArticleRepository::PAGE_LIMIT); return $this->render( 'articles/list.html.twig', ['articles' => $articles] ); } }
Controller jest klasyczny, dziedziczy z AbstractControllera, w adnotacji określamy ścieżkę do akcji. W niej pierwsza linia to wywołanie metody z repozytorium, gdzie pobieramy wszystkie artykuły. Potem te rekordy wrzucamy do metody, którą dostarcza nam właśnie KnpPaginatrBundle. Jest on dostępny w tym kontrolerze dzięki DI. Pierwszy parametr to rekordy do paginacji, drugi parametr metody paginate oznacza, którą stronę chcemy wczytać dlatego pobieramy ją z requestu(podajemy ją w ścieżce). Druga liczba to limit elementów na stronę. Umieściłam ją w public const w repozytorium. Polecam takie rozwiązanie, ponieważ paginacja jest trochę jak limit w zapytaniu, więc najodpowiedniejszym miejscem na jej określenie jest właśnie repozytorium.
Szablon w Twigu jest również bardzo prosty, pętla for i wyświetlamy elementy. Dodatkowo musimy wyrenderować nawigację dla tej paginacji. Oprócz nawigacji mamy od razu sortowanie, cudo!
{% extends 'base.html.twig' %} {% block body %} {% if articles is defined and articles|length %} <div class="nav text-center"> {{ knp_pagination_render(articles) }} </div> <table class="table table-striped"> <thead> <tr> <th>{{ knp_pagination_sortable(articles, 'article.id'|trans, 't.id') }}</th> <th>{{ knp_pagination_sortable(articles, 'article.title'|trans, 't.title') }}</th> </tr> </thead> <tbody> {% for article in articles %} <tr> <td>{{ article.id }}</td> <td>{{ article.title }}</td> </tr> {% endfor %} </tbody> </table> <div class="nav text-center"> {{ knp_pagination_render(articles) }} </div> {% else %} <p> {{ 'empty_list'|trans }} </p> {% endif %} {% endblock %}
Tym sposobem bardzo szybko i sprawnie mamy zrobioną paginacje i co jeszcze fajniejsze, jej wykorzystanie w następnych Controllerach jest już mega proste.
Mam nadzieję, że pomogłam i następnym razem będzie Wam prościej. Jeśli macie jeszcze jakieś pytania to piszcie w komentarzach. Chętnie odpowiem i poszerzę artykuł jeśli będziecie tego potrzebować, w końcu dla Was to robię.