Pagination avec Symfony2 et PagerFanta !

Symfony2 Beta1 est sorti depuis quelques semaines, tout va bien !

Alors que je me demandais comment fonctionnait un Bundle je constate qu’il utilise un Pager! Oh, de la pagination! Voilà un sujet intéressant !

Alors le but n’est pas de vous expliquer en profondeur comment va fonctionner le pager, la classe est tellement simple que je vous laisse la découvrir !

Installation

On va installer un Bundle et PagerFanta! PagerFanta est le système de pagination en lui-même, et le Bundle ne fera que gérer la vue et la personnalisation de PagerFanta.

git submodule add http://github.com/whiteoctober/Pagerfanta.git vendor/pagerfanta
git submodule add http://github.com/whiteoctober/WhiteOctoberPagerfantaBundle.git vendor/bundles/WhiteOctober/PagerfantaBundle

On enregistre les namespaces:

// app/autoload.php
$loader->registerNamespaces(array(
// ...
'WhiteOctober\PagerfantaBundle' => __DIR__.'/../vendor/bundles',
'Pagerfanta' => __DIR__.'/../vendor/pagerfanta/src',
// ... ));

Puis on enregistre le Bundle

// app/AppKernel.php
public function registerBundles()
{
return array(
// ...
new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(),
// ...
);
}

Utilisation

Je pars du principe que vous avez un Bundle, un Controller et une Vue ! Et une base de données ! Dans mon cas ça sera Mysql.

PagerFanta fonctionne en utilisant le Pattern Adaptateur, c’est-à-dire qu’on peut utiliser n’importe quelles classes implémentant l’interface AdapterInterface. On pourra ainsi utiliser Doctrine ORM ou ODM ou d’autres, tant qu’on se débrouille pour renvoyer le résultat.

Premièrement on instancie un nouvel objet Adaptateur: DoctrineORMAdapter dans lequel on passe une instance de queryBuilder. C’est la requête que l’on effectuera pour récupérer notre contenu.

On passe ensuite l’objet DoctrineORMAdapter au constructeur de PagerFanta.
A partir de là, on peut commencer à personnaliser notre objet de pagination:

$pagerfanta->setMaxPerPage($maxPerPage); // 10 par défaut
$maxPerPage = $pagerfanta->getMaxPerPage();

$pagerfanta->setCurrentPage($currentPage); // 1 par défaut
$currentPage = $pagerfanta->getCurrentPage();

$nbResults = $pagerfanta->getNbResults();
$currentPageResults = $pagerfanta->getCurrentPageResults();
$pagerfanta->getNbPages();

$pagerfanta->haveToPaginate();
$pagerfanta->hasPreviousPage();
$pagerfanta->getPreviousPage();
$pagerfanta->hasNextPage();
$pagerfanta->getNextPage();

Grâce à ses méthodes on dispose de toutes les informations qu’il nous faut pour effectuer nos paginations.

Dans la vue

Pour générer la pagination, c’est-à-dire les liens entre chaque page, le Bundle PagerFantaBundle propose une méthode pour twig:

{{ pagerfanta(pagerfanta, 'default') }}

On lui passe notre objet pagerfanta, et on lui applique une vue par défaut.

Pour afficher la liste du contenu, on va appeler une boucle sur l’objet pagerfanta que l’on passera dans le Controller:

{% for data in pagerfanta.currentPageResults %}
<li>{{ data }}</li>
{% endfor %}

On va ainsi afficher les résultats de la page courante, par page je parle toujours des données découpées par la pagination.

Le Controller

Dans la vue, chaque lien généré aura une URL de la sorte : ma-route/?page=x, où x est le numéro de la page.

Lorsqu’on clic sur le lien, il faut récupérer cette valeur dans notre controller. Pour cela on utilise le service request:

$request = $this->get('request');
$page = $request->query->get('page',1);
try {
$pagerfanta->setCurrentPage($page);

} catch (NotValidCurrentPageException $e) {
throw new NotFoundHttpException();
}

$request->query->get(‘page’,1) nous permet de récupérer la valeur de page, et le second argument est la valeur par défaut.

Voici le code de mon Controller:

// pagination
$queryBuilder = $em->createQueryBuilder()
->select('u')
->from('NaN\ArticlesBundle\Entity\Articles', 'u');


$adapter = new DoctrineORMAdapter($queryBuilder);
$pagerfanta = new Pagerfanta($adapter);
$pagerfanta->setMaxPerPage(8); // 8 résultats par page

$request = $this->get('request');
$page = $request->query->get('page',1);
try {
$pagerfanta->setCurrentPage($page);
} catch (NotValidCurrentPageException $e) {
throw new NotFoundHttpException();
}

return array('pagerfanta' => $pagerfanta);

Ainsi on vient de voir comment utiliser simplement et rapidement un système de pagination pour Symfony2 !

Les sources des projets comportent des détails pour personnaliser les paginations, à lire ;) !

PagerFante

PagerFantaBundle

10 Réponses à Pagination avec Symfony2 et PagerFanta !

  1. Manu dit :

    Hello,

    Dans mon projet en cours, j’ai une relation one-to-many entre mon entité “Product” et mon entité “Picture”. J’utilise le paginator de KnpLabs qui me permet de mettre une limite sur le nombre de produits retournés, et non pas le nombre de lignes de résultats (sans ce paginator, si chaque produit a par exemple 5 images, un “limit 10″ ne me retournera que 2 produits…)

    Est-ce que tu sais si PagerFanta gère également correctement les limit lors qu’il y a des relation one-to-many ?

    Merci pour l’article en tout cas !

  2. spike31 dit :

    Je suis pas sûr d’avoir suivis ce que tu essaies d’expliquer, montres ta requête de base si tu veux ^^

  3. sadlig dit :

    il n’y aurai pas quelque chose à faire pour définir la méthode dans twig, car j’ai cette erreur “The function “pagerfanta” does not exist in ….html.twig at line 40 “?

    Sinon les datas s’affichent bien ça me semble facile à utiliser, j’ai juste ce petit problème qui m’empêche de générer les liens de pagination :-/

  4. spike31 dit :

    Tu es sûr d’avoir installé correctement le bundle ? Parce que s’il ne trouve pas la fonction pagerfanta dans ton template, c’est qu’il ne trouve pas l’extension proposée par le bundle…Essaies de bien relire l’installation et mettre tes sources à jour. Autant pour le pager, que symfony et twig.

  5. Sadlig dit :

    Ok je vois
    J’ai essayer d’inclure l’extension dans la config config.yml de mon projet et là j’ai eu un MSG m’indiquant que l’extension était introuvable. Ça concorde avec ce que tu me dis

  6. sadlig dit :

    Ok en fait le problème était situé entre le clavier et le fauteuil :/

  7. Matthieu dit :

    Bonjour,
    Ce pager est-il toujours utilisable avec Symfony 2 RC4 ?

    Car j’ai l’impression d’avoir fait exactement ce que tu indiques mais ça ne marche pas …

    Y a t-il des “use” à mettre dans le contrôleur ? car le message d’erreur m’indique qu’il ne trouve pas la classe pour DoctrineORMAdapter.

    D’avance merci

  8. Matthieu dit :

    Vous pouvez oublier le message précédent le problème se situait également entre le clavier et le fauteuil TT

    Par contre comment peut on changer les mots “Previous” et “Next”, ajouter un peu d’espace entre les chiffres, etc. ?

    • spike31 dit :

      D’après la page sur github lien, tout en bas il explique la marche à suivre. Il faut modifier le css pour gérer l’espacement, et pour changer les noms utiliser la classe OptionablView:
      $myView2 = new OptionableView($defaultView, array('previous_message' => 'Anterior', 'next_message' => 'Siguiente'));

  9. Thibault dit :

    Bonjour,

    Merci pour cet article très intéressant. J’ai repris exactement ce que tu as dit et tout fonctionne parfaitement.

    Cependant, j’ai voulu paginer les résultats d’une recherche. J’ai la première page qui s’affiche parfaitement, mais lorsque je clic sur la page 2 ou 3, je perds la valeur de recherche et donc il n’y a plus aucun résultats, et je perds la valeur requête.

    Est-ce que le bundle contient un truc pour faire passer en plus du numéro de la page la requête pour pouvoir la récupérer ? Ou as-tu déjà eu un truc semblable à réaliser ?

    Bien à toi,
    Thibault

Répondre

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Twitter picture

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Connexion à %s

Suivre

Get every new post delivered to your Inbox.