captain_torche Posté 3 Octobre 2008 Posté 3 Octobre 2008 Il arrive fréquemment d'avoir à gérer un système de pagination, par exemple dans une page de résultats de recherche. Les solutions les plus simples consistent à effectuer une boucle, et afficher toutes les pages disponibles, mais on en trouve vite les limites dans le cas où on aurait un nombre important de pages. J'ai rédigé cet article, que j'espère suffisamment pédagogique pour vous aider à le comprendre, à cette adresse : Gestion de la pagination. J'espère y avoir été suffisamment clair ! Dans le cas contraire, n'hésitez pas à me faire part de vos suggestions.
sebyoga Posté 3 Octobre 2008 Posté 3 Octobre 2008 (modifié) Très bon article, simple, rapide à comprendre et surtout éfficace ! Ca va me servir grandement ! Je galère souvent sur ce genre de développement (j'ai pas de logique... lol) A quand le prochain article ? Sébastien Modifié 3 Octobre 2008 par sebyoga
Kioob Posté 3 Octobre 2008 Posté 3 Octobre 2008 Bien vu, pour ma part j'avais complètement oublié l'existence de SQL_CALC_FOUND_ROWS. Merci
cyberlaura Posté 3 Octobre 2008 Posté 3 Octobre 2008 Idem pour moi, je ne connaissais pas du tout SQL_CALC_FOUND_ROWS, cela va un tout petit peu réduire la charge de Mysql. Merci pour l'info et bravo pour l'article .
Kioob Posté 3 Octobre 2008 Posté 3 Octobre 2008 cyberlaura : attention toutefois, le SQL_CALC_FOUND_ROWS est à manier avec précaution, cf cet article (en anglais désolé) : http://www.mysqlperformanceblog.com/2007/0...alc_found_rows/ Grosso modo je le réserve pour les SELECT sans clause where sur un champ indexé, sur des tables InnoDB. Sinon, il y a des chances pour que le COUNT(*) soit préférable.
captain_torche Posté 3 Octobre 2008 Auteur Posté 3 Octobre 2008 Merci pour vos retours, ça fait plaisir Kioob, je vais consulter ton lien à tête reposée, pour voir si je fais un addendum à l'article ou pas.
Boulbi1 Posté 19 Juillet 2009 Posté 19 Juillet 2009 Au final, après avoir lu l'article en anglais et tous ses commentaires, on ne sait plus trop si le sql calc found rows est vraiment une bonne idée dans tous les cas... Mais j'ai une autre question : dans votre système de pagination, vous faites appel à un SELECT à chaque page en faisant varier simplement le LIMIT mais le prestataire qui a développé mon site a eu une idée qui me paraît saugrenue : il a fait un seul SELECT LIMIT 0,400 puis il a mis tous les résultats dans un tableau en session - ensuite il pagine sans plus jamais faire de SELECT mais en allant chercher dans le tableau. Perso, Cela me paraît gênant de mettre autant de valeur en session (qui sont chargées en mémoire). qu'en pensez-vous ? Je suis très sceptique et je soupçonne même cette méthode de générer de temps en temps des pertes de mémoire dans mes variables de session Remarque : Bien sûr dans notre cas, on ne cherche pas à connaître le nombre de pages de résultats à l'avance, on se limite à 400 pour ne pas surcharger la mémoire. Les autres résultats pouvant être retrouvés par une recherche mullti-critères. Merci
Ernestine Posté 19 Juillet 2009 Posté 19 Juillet 2009 (modifié) Salut, Captain Torche, qui a écrit l'article, te répondra certainement Mais c'est sûr qu'une règle importante est de toujours déléguer au maximum au moteur de base de données, donc l'idéal, pour une pagination, c'est bel et bien de faire des requêtes MySql qui vont retourner uniquement les éléments correspondant à une page P. C'est beaucoup plus efficace niveau économie de ressources, que de faire le tri après coup en php. Mais peut-être qu'il y a d'autres aspects dans ton site, ou dans ta base, qui font que cette méthode n'était pas possible dans ton cas précis. Modifié 19 Juillet 2009 par Ernestine
captain_torche Posté 20 Juillet 2009 Auteur Posté 20 Juillet 2009 Effectivement, ça me paraît tout de même bien complexe, pour une simple pagination. Et cette requête est exécutée à chaque fois qu'on change les critères ? Je ne suis pas expert en performance, mais ça ne me semble pas génial. Ca empêche en premier lieu de mettre quoi que ce soit en cache, par exemple.
Nouipoz Posté 23 Novembre 2009 Posté 23 Novembre 2009 Bonjour , très bonne article ! Merci beaucoup !
pacci Posté 5 Juin 2011 Posté 5 Juin 2011 (modifié) Bonjour à tous. La pagination peut devenir un vrai casse tête en terme d'implémentation. On ne se souvient pas souvent du code, c'est récurent etc... Bon je vous propose ma solution. J'ai développé une classe de traitement pour le SQL. <?php /* * Class d'utilisation du SQL | CURSEUR * Auteur : Maxime Di Meglio * Date : Fevrier 2011 * Commentaire : - Cette classe est écrite pour le SGBDR MySql ; * - La classe Exception (Class système) est utilisé dans le script * * Liste des méthodes : * fonction Sql($host, $user, $password, $bdd) | CONSTRUCTEUR * fonction Connect() | méthode de connexion * fonction GetHost() | Renvoi l'host * fonction GetUser() | Renvoi l'utilisateur en cours * fonction GetBdd() | Renvoi la bdd utilisé * fonction GetPassword() | Renvoi le mot de passe de connexion * fonction GetNb() | Renvoi le nombre d'occurence d'une requête * fonction Query($requete:ch de char) | Execute la requete * fonction Select($requete:ch de char | Méthode pour traiter les requêtes select * fonction Call($flag:booléen) | Affiche la liste des méthodes et attribut */ class Sql{ private $date; private $host; private $user; private $bdd; private $password; private $connect; // Prend la valeur true si la connexion est établie sinon false private $select_bdd; // Prend la valeur de .true. si la BDD existe et que l'on arrive à se connecter sinon .false. protected $nb; // Retourne le nombre de résultat de la dernière requete requete // Tableau contenant les messages d'erreur protected $exception=array( 0=>'La connexion au serveur est impossible', 1=>'La connexion à la base de données est impossible', 2=>'La requête doit contenir une chaine de charactère non vide', 3=>'L\'intérogation a échoué, vérifiez la requête en paramètre', 4=>'L\'adresse e-mail n\'est pas valide' ); // Constructeur : initialise les attributs public function Sql ($host, $user, $password, $bdd){ $this->host = $host; $this->user = $user; $this->password = $password; $this->bdd = $bdd; $this->connect = false; $this->select_bdd = false; $this->date = date('Y-m-d-G-i'); } // Méthode de connexion au serveur et à la BDD public function Connect(){ $this->connect = mysql_connect($this->host, $this->user, $this->password) or die('N\'a pas pu se connecter au serveur mysql'); if(!$this->connect){throw new Exception ($this->exception[0],0);return false;} else{ $this->select_db = mysql_select_db($this->bdd, $this->connect) or die('N\'a pas pu se connecter à la base de données'); if(!$this->select_db){ $this->connect=false; throw new Exception ($this->exception[1],1); return false; } else{ return true; } } } public function SetDate($timestamp, $flag){ if($flag){$this->date = date('Y-m-d-G-i', $timestamp);} else{$this->date = date('Y-m-d-G-i', time());} } public function GetDate(){ return $this->date; } // Récupérer le nom du serveur public function GetHost(){ return $this->host; } // Récupérer l'utilisateur public function GetUser(){ return $this->user; } // Récupérer la bdd public function GetBdd(){ return $this->bdd; } // Récupérer le mot de passe public function GetPassword(){ return $this->password; } // Récupère le nombre d'occurences renvoyé par une requete public function GetNb(){ return $this->nb; } /**********************************************************/ // Modifier le nom du serveur public function SetHost($host){ $this->host = $host; } // Modifier l'utilisateur public function SetUser(){ $this->user = $user; } // Modifier la bdd public function SetBdd(){ $this->bdd = $bdd; } // Modifier le mot de passe public function SetPassword(){ $this->password = $password; } // Methode d'intérogation de la bdd public function Query($requete){ if(empty($requete) || $requete == '' || !is_string($requete)){ throw new Exception ($this->exception[2],2); } $query = mysql_query($requete); if(!$query){ throw new Exception ($this->exception[3],3); return false; } else{ return $query; } } // Méthode pour traiter les requêtes select public function Select($requete){ $d = array(); $query = $this->Query($requete); $this->nb = mysql_num_rows($query); if($query){ if($this->nb == 1){ $r = mysql_fetch_assoc($query); $d[] = $r; } else{ while($r = mysql_fetch_assoc($query)){ $d[] = $r; } } return $d; } else{ return false; } } //Retourne le nombre d'enregistrement total d'une table public function Count($table){ $query = mysql_query('SELECT COUNT(*) AS total FROM '.$table.';'); $result = mysql_fetch_assoc($query); return $result['total']; } //retourne le nombre de page (à utiliser avec la methode pagination) public function Nbpage($table, $nb){ $count = $this->Count($table); $nombreDePages=ceil($count/$nb); return $nombreDePages; } //fonction de pagination public function Pagination($table, $nb, $getpage, $requete){ $count = $this->Count($table); $nombreDePages=ceil($count/$nb); if(isset($getpage)){ $pageActuelle=intval($getpage); if($pageActuelle>$nombreDePages){ $pageActuelle=$nombreDePages; } } else{ $pageActuelle=1; } $premiereEntree=($pageActuelle-1)*$nb; $requete .= ' LIMIT '.$premiereEntree.', '.$nb.';'; $result = $this->Select($requete); return $result; } // Affichage des methodes et attributs de la class Sql public function Call($flag=true){ $resultat = '------ Liste des méthodes et des attributs de la class Sql ------\n'; $resultat .= '\n **Liste des attributs de la class Sql** \n'; $resultat .= ' protected $host:ch de char | Nom du serveur \n protected $user:ch de char | Utilisateur de la bdd \n protected $bdd:ch de char | Nom de la bdd \n protected $password:ch de char | Mot de passe de connexion \n protected $connect:booléen | Renvoie .vrai. si la connexion au serveur marche sinon .faux. \n protected $select_bdd | Renvoie .vrai. si on accède à la BDD sinon faux \n protected $nb; | Nombre d\'occurence de la dernière requete executé \n protected $exception:tbl de ch | Tableau dans lequel les messages d\'exceptions sont enregistrés \n'; $resultat .= '\n **Liste des méthodes de la class Sql** \n'; $resultat .= 'public function Sql ($host:ch de char, $user:ch de char, $password:ch de char, $bdd:ch de char) | CONSTRUCTEUR \n'; $resultat .= 'public function Connect() | Connexion au SGBDR \n'; $resultat .= 'public function GetHost() | Retourne le nom du serveur \n'; $resultat .= 'public function GetUser() | Retourne le nom de l\'utilisateur \n'; $resultat .= 'public function GetBdd() | Retourne le nom de la BDD \n'; $resultat .= 'public function GetPassword() | Retourne le mot de passe de la BDD \n'; $resultat .= 'public function GetNb() | Retourne le nombre d\'occurence de la dernière requête \n'; $resultat .= 'public function SetHost($host) | Modifier l\'host \n'; $resultat .= 'public function SetUser($user) | Modifier l\'utilisateur \n'; $resultat .= 'public function SetBdd($bdd) | Modifier la bdd \n'; $resultat .= 'public function SetPassword($password) | Modifier le mot de passe de la BDD \n'; $resultat .= 'public function Query($requete:ch de char) | Execute la requête \n'; $resultat .= 'public function Select($requete:ch de char) | Retourne un tableau pour les requete de type select \n'; $resultat .= 'public function Pagination($table:chaine de char, $nb:entier, $getpage:entier, $requete:chaine de char) | retourne un tableau pour la pagination'; $resultat .= 'public function Call($flag:booléen) | Retourne la liste et les méthodes de la class, flag = .vrai.=> saut de ligne en html \n'; if($flag){return nl2br($resultat);}else{return $resultat;} } }?> Comme vous pouvez voir on a la méthode publique Pagination($table:chaine de char, $nb:entier, $getpage:entier, $requete:chaine de char) : tableau et la méthode publique Nbpage($table : chaine de char, $nb : entier) : entier Utilisation : $db = new Sql($host, $user, $password, $bdd);$requete = 'SELECT mes_champs FROM mes_tables WHERE criteres_de_restriction';$page = 1; // Pour la premiere page sinon récupérer un POST ou un GET$nb_occurences = 12;$result = $db->Pagination('matable',$nb_occurences , $page, $requete); // Pagination des résultat retourne un tableau$nb_page = $db->Nbpage('contact', 12); // Nombre de page totalforeach ($result as $key => $value) { //Parcoure du tableau....} Si vous voyez des améliorations/erreurs de la class (peut être la passer en static ?), n'hésitez pas à me contacter par MP. Modifié 5 Juin 2011 par pacci
bug01300 Posté 20 Août 2012 Posté 20 Août 2012 Salut, Cela fait 4 jours que j'essaie de réaliser une pagination d'une recherche. Pouvez vous m'aider? Merci Bug
Nicolas Posté 20 Août 2012 Posté 20 Août 2012 (modifié) Bonjour Bug01300, Pour cela il faut que tu gardes les valeurs des champs de la recherche en session (il existe d'autres moyens). La valeur de l'id de la page demandée peut être recupérée via l'url (exemple : -http://monsite.com/recherche-page-3.html dans ce cas on recupère la numéro de la page : 3). Cela permettra de filtrer les résultats avec un LIMIT dans la requête SQL. Il faut bien sur connaitre le nombre de résultats de page qui peut être mis en variable dans un fichier de config ou dans une table config. J'espère que cela t'aidera un peu. Modifié 20 Août 2012 par Nicolas
khalid-ref Posté 28 Juillet 2014 Posté 28 Juillet 2014 toto sympa et facile à retenir merci pour le partage
captain_torche Posté 29 Juillet 2014 Auteur Posté 29 Juillet 2014 Pas de quoi, ça fait plaisir de savoir qu'il est toujours lu !
Sujets conseillés
Veuillez vous connecter pour commenter
Vous pourrez laisser un commentaire après vous êtes connecté.
Connectez-vous maintenant