La pagination avec Symfony et Doctrine
Créer une liste de résultats avec une pagination est très simple avec Symfony. Pour suivre ce petit tuto, je pars du principe que vous avez déjà créé votre modèle et le module qui lui est associé, tout ce qu’il reste à faire est d’afficher les résultats sur la page d’index du module en intégrant un système de pagination.
Création d’une méthode dans le modèle
Bon plutôt que d’utiliser des noms factices, j’ai pris un exemple banal: on veux afficher une liste de news avec les informations sur la news ainsi que le nom de la catégorie et de l’auteur qui sont stockés dans des tables liées. La première chose à faire est donc de créer la fonction chargée de récupérer les données dans la base.
public function getActiveNews()
{
$q = $this->createQuery('n')
->select('n.*, c.*, a.id, a.username')
->from('News n')
->innerJoin('n.Category c')
->innerJoin('n.Author a')
->where('n.is_activated = ?', true)
->orderBy('n.created_at DESC');
return $q;
}
Que fait cette requête ? Elle sélectionne toutes les news actives (on considère qu’une news est active si le champ is_activated est égal à 1), les trie en ordre décroissant par date de création et récupère les données liées dans d’autres tables (la catégorie et le membre qui a posté la news) avec les jointures.
J’utilise innerJoin car dans mon modèle une news a forcément une catégorie et un auteur, si ce n’est pas le cas utilisez leftJoin. En faisant les jointures dans cette fonction on diminue de manière drastique le nombre de requêtes pour l’affichage de la liste.
Notez aussi qu’avec le Doctrine pager, la fonction doit renvoyer $q et pas $q->execute()
Création de l’action dans le contrôleur
Lorsque l’on créer un module en utilisant les lignes de commandes, Symfony génère déjà une requête par défaut pour l’action « index », mais on ne va pas l’utiliser puisque l’on vient de créer une fonction exprès pour ça ! De toute façon en principe il faut écrire les requêtes dans le modèle et pas dans le contrôleur. En plus, cela permet de réutiliser la requête dans un autre module sans avoir à la réécrire.
Avant on va juste faire un petit ajout dans le fichier app.yml de votre application :
news_per_page: 10
Bien on peut maintenant créer notre action dans le contrôleur du module (actions.php)
{
$this->pager = new sfDoctrinePager('News', sfConfig::get('app_news_per_page'));
$this->pager->setQuery(Doctrine_Core::getTable('News')->getActiveNews());
$this->pager->setPage($request->getParameter('page', 1));
$this->pager->init();
}
Simple non? Il ne reste plus qu’à gérer l’affichage dans la vue indexSuccess.php. On va d’abord afficher les résultats (via un pauvre tableau mais bon c’est pour l’exemple)
<thead>
<tr>
<th>Title</th>
<th>Content</th>
<th>Category</th>
<th>Author</th>
<th>Created at</th>
</tr>
</thead>
<tbody>
<?php foreach ($pager->getResults() as $news): ?>
<tr>
<td><a href="<?php echo url_for('news/show?id='.$news->getId()) ?>"><?php echo $news->getTitle() ?></a></td>
<td><?php echo $news->getContent() ?></td>
<td><?php echo $news->getCategory()->getName() ?></td>
<td><?php echo $news->getAuthor()->getUsername() ?></td>
<td><?php echo $news->getCreatedAt() ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
Et maintenant, toujours dans le même fichier, la pagination en bas du tableau :
<div class="pagination">
<a href="<?php echo url_for('news', $news) ?>?page=<?php echo $pager->getFirstPage() ?>">Premier</a>
<a href="<?php echo url_for('news', $news) ?>?page=<?php echo $pager->getPreviousPage() ?>">Précédent</a>
<?php foreach ($pager->getLinks() as $page): ?>
<?php if ($page == $pager->getPage()): ?>
<?php echo $page ?>
<?php else: ?>
<a href="<?php echo url_for('news', $news) ?>?page=<?php echo $page ?>"><?php echo $page ?></a>
<?php endif; ?>
<?php endforeach; ?>
<a href="<?php echo url_for('news', $news) ?>?page=<?php echo $pager->getNextPage() ?>">Suivant</a>
<a href="<?php echo url_for('news', $news) ?>?page=<?php echo $pager->getLastPage() ?>">Dernier</a>
</div>
<?php endif; ?>
Vous êtes libres de styliser comme bon vous semble les liens en mettant des images, des effets…
Optimisations
On a un système qui fonctionne mais on peut encore un peu l’améliorer. Si on a plusieurs modules avec des listes paginées il peut être intéressant de créer un template unique pour l’affichage des liens vers les autres pages.
Pour ce faire, vous pouvez créer un fichier _paginate.php dans le dossier /templates de votre application. Par exemple, si votre application s’appelle « frontend » cela donne /frontend/templates, il doit déjà y avoir un fichier layout.php à cet endroit normalement. Une fois le fichier crée, copiez-y le code suivant :
<div class="pagination">
<?php echo link_to('Premier', $route.'?page=' . $pager->getFirstPage()) ?>
<?php echo link_to('Précédent', $route.'?page=' . $pager->getPreviousPage()) ?>
<?php foreach ($pager->getLinks() as $page): ?>
<?php if ($page == $pager->getPage()): ?>
<?php echo $page ?>
<?php else: ?>
<?php echo link_to($page, $route.'?page=' . $page) ?>
<?php endif; ?>
<?php endforeach; ?>
<?php echo link_to('Suivant', $route.'?page=' . $pager->getNextPage()) ?>
<?php echo link_to('Dernier', $route.'?page=' . $pager->getLastPage()) ?>
</div>
<?php endif; ?>
Vous pouvez désormais appeler le partial _paginate.php depuis n’importe quelle vue en ajoutant le code suivant dans votre vue :
Seule la route est variable dans le code ci-dessus. Pour que cela marche, il faut éditer le fichier routing.yml de votre application et rajouter autant de routes que nécessaires pour l’affichage des listes. Dans cet exemple cela donne :
url: /news/page/:page
class: sfDoctrineRoute
options: { model: News, type: list }
param: { module: news, action: index }
requirements:
page: \d+
sf_method: [get]
L’ajout de cette route permet de créer de « joli » liens sans le point d’interrogation et également de s’assurer que le le paramètre get fourni dans l’url est bien un entier positif (sinon erreur 404). Pour s’assurer également qu’un utilisateur ne va pas s’amuser à mettre le numéro d’une page qui n’existe pas, on peut rajouter le code suivant dans l’action index :
Voilà, la prochaine étape sera de gérer la pagination de la liste en prenant en compte les paramètres de recherche d’un utilisateur
3 Commentaires sur “La pagination avec Symfony et Doctrine”
Laisser un commentaire
Articles au hasard
-
Créer un RAID avec l'Intel Matrix Storage Man...
-
L'autocomplétion dans Symfony (suite et fin)
-
Quelques fonctions pratiques en PHP
-
Configurer les VirtualHosts pour Symfony
-
Installation de Webmin sous Debian ETCH
Articles par catégorie
- Administration réseau (6)
- Base de données (1)
- MySQL (1)
- Développement Web (7)
- HTML et CSS (1)
- Javascript (3)
- PHP (6)
Sondage

# Le 3 décembre 2011 à 11 h 03 min
Chez Free,la dernière version de WordPress que l’on peut installer est WP 3.1.4 !
# Le 4 décembre 2011 à 14 h 58 min
@zip: ok merci pour l’info, mais quel rapport avec le sujet ?
# Le 9 février 2012 à 19 h 43 min
Merci pour ce post qui va m’ être très utile.
Et @Zip et @Mika merci pour cette conversation qui m’ a fait beaucoup rire !