Aller au contenu
captain_torche

Gestion de la pagination

Noter ce sujet :

Recommended Posts

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.

Partager ce message


Lien à poster
Partager sur d’autres sites

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é par sebyoga

Partager ce message


Lien à poster
Partager sur d’autres sites

Bien vu, pour ma part j'avais complètement oublié l'existence de SQL_CALC_FOUND_ROWS. Merci ;)

Partager ce message


Lien à poster
Partager sur d’autres sites

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 :) .

Partager ce message


Lien à poster
Partager sur d’autres sites

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.

Partager ce message


Lien à poster
Partager sur d’autres sites

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.

Partager ce message


Lien à poster
Partager sur d’autres sites

Merci captain_torche !

Très intéressant !

b0b0

Partager ce message


Lien à poster
Partager sur d’autres sites

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

Partager ce message


Lien à poster
Partager sur d’autres sites

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é par Ernestine

Partager ce message


Lien à poster
Partager sur d’autres sites

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.

Partager ce message


Lien à poster
Partager sur d’autres sites

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 total

foreach ($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é par pacci

Partager ce message


Lien à poster
Partager sur d’autres sites

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é par Nicolas

Partager ce message


Lien à poster
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant

×