Licence CC BY-NC-SA

Paginer avec PHP et SQL

Afin de ne plus submerger d'informations les utilisateurs, et accélérer le chargement de vos pages

Jusqu’à présent, toutes les données d’une table s’affichaient sur une seule page. Mais voilà, cela commence à faire beaucoup de données. On doit faire défiler pour trouver l’information, et ça met de plus en plus de temps pour charger une page. Il faut faire quelque chose.
Oui, mais quoi ?

La solution la plus répandue s’appelle la pagination, soit la séparation en plusieurs pages d’une liste de données.

Ce tutoriel, pensé pour ceux qui ne connaissent pas nécessairement tout de SQL ni de PHP, est là pour vous expliquer plus concrètement le principe, exposer la réflexion pour arriver à une bonne solution, et évidemment vous proposer une implémentation possible.

Si le tutoriel est rédigé avec MySQL, il est très facilement adaptable à d’autres langages SQL.

Malgré le fait que du code soit fourni, ce tutoriel nécessite tout de même quelques bases. Vous devriez être déjà capable d’écrire le code de base et de comprendre ce qu’il fait avant d’aller plus loin.

Cela implique donc de connaître :

  • la syntaxe de PHP ;
  • les structures de contrôle et les boucles (if, while et for présentes dans ce tutoriel) ;
  • la connexion aux bases de données (dans l’idéal avec PDO, utilisé ici, et que je vous recommande chaudement) ;
  • le principe et la syntaxe de base des requêtes SQL (un tutoriel pour MySQL est disponible sur ce site en cas de besoin)

N'afficher qu'un nombre défini d'éléments

Pour commencer, prenons un code simple qui affiche toutes ces données. Il nous servira aussi de base pour continuer le tutoriel, mais je n’en reprendrai que quelques parties au gré des points à observer.

<?php
$cnx = new PDO('mysql:host=localhost;dbname=my_database;charset=utf8', 'root', '');

// Partie "Requête"
$query = 'SELECT * FROM `my_table`';
$resultSet = $cnx->query($query);

// Partie "Boucle"
while ($element = $resultSet->fetch()) {
    // C'est là qu'on affiche les données  :)
}
Le code de base qui nous servira pour le tutoriel.

Des solutions peu optimales…

Maintenant que nous avons notre code de travail, mettons-nous à l’ouvrage !  :)
Il nous a été demandé de n’afficher que 10 éléments à la fois.

Le compteur d’itérations

En regardant la ligne 9, on voit de suite qu’on va avoir autant d’itérations qu’il y a de résultats.
Du coup, la première solution qui vient à l’esprit, c’est de placer une condition sur le nombre de résultats traités pour sortir de la boucle au bon moment, ce qui nous donnerait ceci :

<?php
// Partie "Boucle"
$limite = 10;
$compteur = 0;
while ($element = $resultSet->fetch()) {
    if ($compteur >= $limite) {
        break;
    }
    // C'est là qu'on affiche les données  :)
    $compteur++;
}
Mise en place d’une condition sur le nombre d’itérations

Cette méthode fonctionne, vous vous frottez les mains d’avoir trouvé une solution rapidement et qui plus est simple à mettre en place.
Malheureusement, elle reste consommatrice de mémoire de manière inutile : nous allons récupérer tous les résultats pour n’en utiliser au final que 10. Si ce n’est pas trop gênant quand il n’y a que 20 enregistrements, imaginez quand il y en a au-delà de 8000…

La requête dans la boucle

Si le souci est qu’on récupère trop de résultats, nous pouvons alors mettre la requête dans la boucle, ce qui nous donnerait quelque chose dans le genre de ce qui suit :

<?php
$cnx = new PDO('mysql:host=localhost;dbname=my_database;charset=utf8', 'root', '');

// Partie "Boucle"
$limite = 10;
for ($i = 0; $i < $limite; $i++) {
    // Partie "Requête"
    $query = 'SELECT * FROM `my_table`';
    $resultSet = $cnx->query($query);
    $element = $resultSet->fetch();
    // C'est là qu'on affiche les données  :)
}
Requête dans la boucle

Mais… mais… ça nous affiche toujours le même élément ⁈

Hé oui, ce qui semblait être une solution logique implique plus de changements que ce qu’on pourrait penser. Il faudrait savoir quel élément a déjà été affiché, et récupérer le premier qui ne l’a pas été. Nous pourrions simplifier, et ne garder que le dernier. Mais il faudrait…

STOP

Cette solution, outre la complexité qu’elle amène sans en avoir l’air, n’est toujours pas optimale. En plus de la mémoire nécessaire pour garder les résultats à portée de main, il faut aussi penser aux temps d’exécution des requêtes.

Un gestionnaire de bases de données est un serveur comme Apache, nginx ou IIS. On lui envoie une requête qu’il traite avant d’envoyer la réponse, que PHP stocke en mémoire. On voit donc qu’il y a au final plus d’un point à prendre en compte :

  1. Le temps d’accès au serveur
    On ne peut pas trop influer dessus, cela dépend de la machine (ou des machines) sur laquelle (ou lesquelles) sont installés PHP et MySQL.
  2. Le temps de traitement
    C’est très lié à la complexité de la requête et à la quantité de résultats, nous pouvons donc en tout cas essayer de demander juste ce qu’il nous faut. Mais ce n’est en général pas le plus gênant, les gestionnaires de bases de données sont suffisamment performants sur ce point.  ^^
  3. La mémoire pour enregistrer cette réponse
    Là aussi, essayer de demander uniquement ce que l’on va utiliser permet déjà de faire mieux.

Au final, c’est donc le temps d’accès qui pose problème. Ce temps d’accès va rester quasiment identique à chaque requête exécutée, donc il faut trouver un moyen pour le diminuer.
Si nous arrivions à mettre en place la seconde proposition, ce temps serait conséquent. La solution est donc de demander directement à MySQL uniquement 10 résultats à la fois. Une seule requête au lieu de 10, donc :

  • nous n’avons pas 10 fois le temps d’accès qui entre en compte
  • nous ne surchargeons pas la mémoire de résultats inutiles
  • nous ne nous cassons plus trop la tête pour savoir lequel est affiché, lequel ne l’est pas  :D

Néanmoins, il nous manque encore la manière de faire pour dire à MySQL de se limiter à 10 résultats.

Une solution optimale avec LIMIT

Pour ceux qui connaissent un peu le SQL ou qui sont allés chercher des solutions ailleurs, vous connaissez peut-être déjà la clause LIMIT. Et pour ceux qui la découvrent maintenant, on va expliquer ce qu’elle permet.  ;)

LIMIT : rien que le mot est évocateur. Et il se trouve que c’est bien l’anglais pour « limite ». Il sert donc à limiter le nombre de résultats retournés par une requête. Nous avons désormais de quoi n’avoir que les 10 enregistrements souhaités. Si nous reprenons la partie "Requête" de notre code de travail de départ et que nous l’adaptons, nous avons ceci :

<?php
$cnx = new PDO('mysql:host=localhost;dbname=my_database;charset=utf8', 'root', '');

$limite = 10;

// Partie "Requête"
/* On construit la requête, en remplaçant les valeurs par des marqueurs. Ici, on
 * n'a qu'une valeur, limite. On place donc un marqueur là où la valeur devrait se
 * trouver, sans oublier les deux points « : » */
$query = 'SELECT * FROM `my_table` LIMIT :limite';
/* On prépare la requête à son exécution. Les marqueurs seront identifiés */
$query = $cnx->prepare($query);
/* On lie ici une valeur à la requête, soit remplacer de manière sûre un marqueur par
 * sa valeur, nécessaire pour que la requête fonctionne. */
$query->bindValue(
    'limite',         // Le marqueur est nommé « limite »
     $limite,         // Il doit prendre la valeur de la variable $limite
     PDO::PARAM_INT   // Cette valeur est de type entier
);
/* Maintenant qu'on a lié la valeur à la requête, on peut l'exécuter */
$query->execute();

// Partie "Boucle"
/* Ce qui se trouvait avant dans $resultSet est désormais dans $query, donc on doit
 * modifier ici aussi */
while ($element = $query->fetch()) {
    // C'est là qu'on affiche les données  :)
}
La solution optimale, qui va nous servir de base pour la suite, avec quelques explications supplémentaires sur les modifications

Nous avons désormais un code qui nous affiche juste le nombre souhaité d’éléments, qui est rapide, et qui ne consomme pas trop de mémoire. C’est là un bon début.

Ce qu’il nous faut maintenant, c’est de quoi afficher les éléments suivants. Car si nous n’avons plus 10 fois le même, les autres que les 10 premiers doivent être accessibles aussi !  :p

Générer les liens vers les pages précédente et suivante

Maintenant que nous savons comment afficher quelques éléments à la fois, nous allons voir comment faire en sorte d’avoir la possibilité de voir toutes les pages, pas seulement la première.

Comme auparavant, reprenons une base de départ.

<?php
$cnx = new PDO('mysql:host=localhost;dbname=my_database;charset=utf8', 'root', '');

$limite = 10;

// Partie "Requête"
$query = 'SELECT * FROM `my_table` LIMIT :limite';
$query = $cnx->prepare($query);
$query->bindValue('limite', $limite, PDO::PARAM_INT);
$query->execute();

// Partie "Boucle"
while ($element = $query->fetch()) {
    // C'est là qu'on affiche les données  :)
}
Base pour la génération des liens vers les autres pages

Et, une fois n’est pas coutume, un peu de réflexion s’impose avant de foncer tête baissée dans le code.

Nous savons que l’on aimerait afficher 10 éléments à la fois. Seulement, il nous faut de quoi afficher les 10 suivants, et aussi les 10 précédents, bref, de pouvoir naviguer d’une page à la suivante ou la précédente.

Liens « Suivant » et « Précédent »

Dans un premier temps, nous allons nous contenter de deux simples liens pour passer d’une page à l’autre. Mais d’abord, réfléchissons.

Une page, ce sont 10 éléments d’affichés. La page suivante, ce sont les 10 éléments suivants, la page précédente, ce sont les 10 éléments précédents. Il nous faut donc adapter notre requête afin de pouvoir dire, d’une certaine manière, que nous n’avons pas besoin des éléments des pages précédentes.

Ce moyen est proposé par un autre mot-clé SQL : OFFSET. Celui-ci s’utilise très simplement de la manière OFFSET :debut. Comme vous pouvez l’avoir déjà compris, ce mot-clé permet de déterminer à partir de quel enregistrement l’on aimerait récupérer les données. D’une certaine manière, c’est donc aussi le nombre d’enregistrements que l’on souhaite "éviter" ou "ignorer". Je n’ai donc pas choisi les marqueurs sans y réfléchir ! ;)

Maintenant, le souci est de calculer cette valeur de début. Regardons de plus près quels sont les enregistrements que nous souhaitons récupérer pour chaque page. Afin de nous y retrouver, nous allons simplement les numéroter, mais pour des questions pratiques, je vais commencer à 0 comme pour les tableaux en PHP. Ce choix se justifie quand nous apprenons que pour SQL, le premier enregistrement est l’enregistrement 0 — comme dans beaucoup de langages de programmation.

Sur la première page, nous récupérons donc les enregistrements 0, 1, 2, 3, …, 9 (vous pouvez compter, ça fait bien 10 :p ).
Sur la seconde page, nous allons récupérer les enregistrements 10, 11, 12, …, 19.
Sur la troisième : 20, 21, … 29.
Vous voyez où je veux en venir ?

En fait, sur chaque page, on commence avec l’enregistrement dont la dizaine correspond au numéro de page moins un. Dit autrement, le numéro du premier enregistrement à récupérer pour une page correspond à l’expression ci-dessous :

debut=(numeroDePage1)10debut = (numeroDePage - 1) * 10

Il y a juste encore le 10 qui peut gêner, bien qu’on puisse rapidement se rendre compte que ce 10 correspond au nombre d’éléments par page. Ce serait donc intéressant de le remplacer par limitelimite.

debut=(numeroDePage1)limitedebut = (numeroDePage - 1) * limite

Nous pouvons désormais adapter la requête pour y ajouter ce que nous avons vu plus haut, du fait que nous savons maintenant comment calculer ce dont elle a besoin pour être utilisable comme on le souhaite.

<?php
// Partie "Requête"
/* On calcule le numéro du premier élément à récupérer */
$debut = ($page - 1) * $limite;
/* La requête contient désormais l'indication de l'élément de départ,
 * avec le nouveau marqueur … */
$query = 'SELECT * FROM `my_table` LIMIT :limite OFFSET :debut';
$query = $cnx->prepare($query);
$query->bindValue('limite', $limite, PDO::PARAM_INT);
/* … auquel il faut aussi lier la valeur, comme pour la limite */
$query->bindValue('debut', $debut, PDO::PARAM_INT);
/* Le reste se passe comme auparavant */
$query->execute();
Notre nouvelle partie "Requête", avec les commentaires

Nous sommes allés un peu trop vite, il nous manque quelque chose, là !
Maintenant que nous avons de quoi calculer le numéro du premier enregistrement pour la page, il nous faut encore savoir sur quelle page on se trouve. Pour ce faire, nous allons rester simple : nous allons passer le numéro de la page souhaitée dans l’URL en utilisant un paramètre de chaîne de requête page. Voilà, nous allons enfin pouvoir passer aux liens vers les pages précédentes et suivantes, en ajoutant simplement la partie "Liens".  ^^

<?php
$cnx = new PDO('mysql:host=localhost;dbname=my_database;charset=utf8', 'root', '');

$page = $_GET['page'];
$limite = 10;

// Partie "Requête"
/* On calcule donc le numéro du premier enregistrement */
$debut = ($page - 1) * $limite;
/* On ajoute le marqueur pour spécifier le premier enregistrement */
$query = 'SELECT * FROM `my_table` LIMIT :limite OFFSET :debut';
$query = $cnx->prepare($query);
$query->bindValue('limite', $limite, PDO::PARAM_INT);
/* On lie aussi la valeur */
$query->bindValue('debut', $debut, PDO::PARAM_INT);
$query->execute();

// Partie "Boucle"
while ($element = $query->fetch()) {
    // C'est là qu'on affiche les données  :)
}

// Partie "Liens"
/* Notez que les liens ainsi mis vont bien faire rester sur le même script en passant
 * le numéro de page en paramètre */
?>
<a href="?page=<?php echo $page - 1; ?>">Page précédente</a><a href="?page=<?php echo $page + 1; ?>">Page suivante</a>
Une pagination effective, mais…

Il reste un point à traiter avant que ce script ne soit utilisable.
Si l’on arrive dessus sans spécifier de numéro de page, on aura droit à un message comme quoi l’index page n’existe pas. Même si nous savons que l’on doit arriver sur la première page, notre script ne le sait pas !  ^^

Il ne manque pas grand-chose pour régler cela, il suffit de modifier un petit peu la récupération du numéro de page comme suit :

<?php
$page = (!empty($_GET['page']) ? $_GET['page'] : 1);
Définition d’un numéro de page par défaut

Le code ainsi fourni n’est pas totalement sécurisé.

Il vous appartient donc de faire les vérifications d’usage sur ce que contient $_GET['page'].

Voilà, nous avons maintenant quelque chose de fonctionnel, qu’on va pouvoir continuer d’améliorer.

Afficher des liens vers d'autres pages que les suivante et précédente

Maintenant que nous savons comment afficher quelques éléments à la fois, nous allons voir comment faire en sorte d’avoir la possibilité de savoir combien de pages il y a, et permettre de passer à d’autres pages que celles qui suivent ou précèdent immédiatement.

Comme auparavant, reprenons une base de départ.

<?php
$cnx = new PDO('mysql:host=localhost;dbname=my_database;charset=utf8', 'root', '');

$page = (!empty($_GET['page']) ? $_GET['page'] : 1);
$limite = 10;

// Partie "Requête"
$debut = ($page - 1) * $limite;
$query = 'SELECT * FROM `my_table` LIMIT :limite OFFSET :debut';
$query = $cnx->prepare($query);
$query->bindValue('debut', $debut, PDO::PARAM_INT);
$query->bindValue('limite', $limite, PDO::PARAM_INT);
$query->execute();

// Partie "Boucle"
while ($element = $query->fetch()) {
    // C'est là qu'on affiche les données  :)
}

// Partie "Liens"
?><a href="?page=<?php echo $page - 1; ?>">Page précédente</a><a href="?page=<?php echo $page + 1; ?>">Page suivante</a>
Base pour la génération des liens vers les autres pages

Comme toujours, un peu de réflexion s’impose avant de foncer tête baissée dans le code. Nous savons que nous aurons 10 éléments par page, mais nous ne savons pas combien de fois cela va faire. Il nous faut donc un moyen de récupérer ce nombre, qui correspondra au nombre de pages total.

Un peu de réflexion (ou de recherche ^^ ) nous permet de trouver que le nombre de pages total se calcule de la sorte :

nombreDePages=nombredElementstotallimitenombreDePages = \left \lceil{\dfrac{nombredElements_{total}}{limite}}\right \rceil

La notation quelqueChose\lceil{quelqueChose}\rceil se lit comme la fonction plafond de quelqueChosequelqueChose, et consiste à prendre l’entier supérieur ou égal à l’argument.
Du coup, pour une explication en français : le nombre de pages total est égal à la fonction plafond appliquée sur le résultat de la division du nombre total d’éléments à afficher par le nombre d’éléments par page.
Prenez le temps de relire si vous ne comprenez pas. :p

Parmi tout ce qu’il y a dans cette expression, il nous manque maintenant nombredElementstotalnombredElements_{total}.

Récupérer le nombre d’éléments total

Nous pourrions commencer par nous dire qu’il nous faut récupérer tous les résultats, puis les compter. Seulement, nous avons déjà vu que récupérer tous les résultats n’est pas une bonne solution quand on n’en affiche que quelques-uns : nous nous retrouvons dans la première situation de la première partie. Il nous faut donc éviter cela.

Pour compter un nombre d’enregistrements, il existe la fonction SQL count(). Elle s’utilise sur une colonne, et compte le nombre de valeurs non-nulles qui s’y trouvent. Seulement, si vous arrivez à la combiner avec la version courante de notre requête, vous ne récupérerez plus jamais qu’un seul enregistrement. :-°

Mais c’est cependant la solution standard que d’effectuer deux requêtes : une qui compte, et une autre qui ira récupérer les éléments voulus.

Une solution pratique avec MySQL consistait à utiliser un mot-clé SQL_CALC_FOUND_ROWS. Cependant, s’il peut encore être supporté par MySQL 8.0 tout en générant un avertissement de dépréciation, il n’est pas exclu que cette option qui ne respecte pas les standards SQL ne disparaisse aussi de MariaDB 11.

Pour l’instant, notre unique requête se présente ainsi :

SELECT * FROM `my_table` LIMIT :limite OFFSET :debut
Requête qui ne fait que récupérer limite enregistrements depuis debut

Avec celle-ci, nous récupérons toutes les colonnes des enregistrements. Pour compter, il ne nous faudra que le nombre de résultats, ce qui peut donc se faire tout simplement ainsi :

SELECT count(id) FROM `my_table`
Requête qui compte le nombre de valeurs non nulles dans la colonne id

Au final, notre partie "Requête" va se présenter ainsi :

<?php
// Partie "Requête"
/* On commence par récupérer le nombre d'éléments total. Comme c'est une requête,
 * il ne faut pas oublier qu'on ne récupère pas directement le nombre.
 * Ici, comme la requête ne contient aucune donnée client pour fonctionner,
 * on peut l'exécuter ainsi directement */
$resultFoundRows = $cnx->query('SELECT count(id) FROM `my_table`');
/* On doit extraire le nombre du jeu de résultat */
$nombredElementsTotal = $resultFoundRows->fetchColumn();

$debut = ($page - 1) * $limite;
/* Cette requête ne change pas */
$query = 'SELECT * FROM `my_table` LIMIT :limite OFFSET :debut';
$query = $cnx->prepare($query);
$query->bindValue('debut', $debut, PDO::PARAM_INT);
$query->bindValue('limite', $limite, PDO::PARAM_INT);
$query->execute();
La dernière version de la partie "Requête"

Si vous ajoutez des jointures, peut-être que vous devrez compter les valeurs distinctes d’une colonne sur l’entier du jeu de résultats, les jointures introduisant des "doublons". Pour pallier cela, utilisez count(DISTINCT laColonne)

Il ne nous reste maintenant plus qu’à afficher les liens vers les autres pages selon leur numéro.

Liste des pages

Nous avons vu une expression mathématique un peu plus haut. Dans un premier temps, nous allons l’adapter en PHP. Vous l’avez peut-être remarqué, les noms de fonctions en PHP sont en anglais. On parle de fonction plafond, est-ce que “ceiling” serait le nom de la fonction ? Presque, c’est la version abrégée ! La fonction PHP qui permet de récupérer l’entier supérieur ou égal le plus proche est la fonction ceil(). Du coup, nous aurons notre calcul qui se présentera ainsi :

<?php
$nombreDePages = ceil($nombredElementsTotal / $limite);
Adaptation de la formule mathématique dans PHP

Et maintenant que nous avons toutes les données, il nous faut les afficher. Rien de plus simple qu’une boucle pour ce faire. ;)

<?php
// Partie "Liens"
/* On calcule le nombre de pages */
$nombreDePages = ceil($nombredElementsTotal / $limite);

/* Si on est sur la première page, on n'a pas besoin d'afficher de lien
 * vers la précédente. On va donc ne l'afficher que si on est sur une autre
 * page que la première */
if ($page > 1):
    ?><a href="?page=<?php echo $page - 1; ?>">Page précédente</a><?php
endif;

/* On va effectuer une boucle autant de fois que l'on a de pages */
for ($i = 1; $i <= $nombreDePages; $i++):
    ?><a href="?page=<?php echo $i; ?>"><?php echo $i; ?></a> <?php
endfor;

/* Avec le nombre total de pages, on peut aussi masquer le lien
 * vers la page suivante quand on est sur la dernière */
if ($page < $nombreDePages):
    ?><a href="?page=<?php echo $page + 1; ?>">Page suivante</a><?php
endif;
?>
Génération des liens directs vers chaque page

Nous avons désormais notre pagination définitive : nous pouvons accéder à toutes les pages en un clic, nous pouvons passer d’une page à l’autre dans les deux "directions". Au niveau de l’expérience utilisateur nous avons :

  • organisé l’information en petites parties qu’il est plus simple pour l’utilisateur de parcourir ;
  • diminué le temps de chargement des pages ;
  • réparti un tant soit peu la charge en demandant le plus d’informations possible à MySQL plutôt que de tout faire en PHP ;
  • minimisé l’empreinte mémoire nécessaire

Le jeu en valait donc la chandelle, non ? :)


Comme vous pouvez le constater, cela ne coule pas nécessairement de source, et il y a pas mal de paramètres dont il faut tenir compte. Mais maintenant, vous avez des exemples et donc de bonnes bases pour réaliser vos propres paginations.

Dans un premier temps, vous pouvez vous soucier de l’avertissement donné plus haut : si l’on met dans le paramètre page de l’URL un nombre négatif, à virgule, plus grand que le nombre total de pages, ou même quelque chose qui n’est pas un nombre, ça peut poser problème. Ou alors malgré un nombre respectable d’éléments par page, vous avez trop de pages, et vous souhaitez n’afficher des liens que vers certaines d’entre-elles, comme la première et la dernière, ainsi que les trois précédentes et les trois suivantes…

Vous pouvez encore imaginer un système avec de l’AJAX pour charger les éléments suivants comme sur les réseaux sociaux, voire – soyons fous ! — paginer des résultats de recherche en utilisant la fonction http_build_query() à bon escient…

Bref, une fois de plus, ce tutoriel vous permet de comprendre la réflexion qu’il y a derrière la pagination afin de pouvoir mettre en place une version très simple, mais néanmoins utilisable et pratique. La suite n’appartient qu’à vous.

À vos claviers !

29 commentaires

Une petite question : sachant que je veux ordonner mes résultats par ordre alphabétique; si je fais quelque chose du genre :

1
SELECT * FROM table ORDER BY NameChamp  ASC LIMIT 0,10

Est ce que le ORDER BY s'applique sur l'ensemble de la table ou sur les résultats renvoyés? Dit autrement, est-ce que je récupère les 10 premiers éléments puis ils sont mis par ordre alphabétique, ou autre contre l'ordre alphabétique s'applique sur la table puis je récupère les 10 premiers éléments une fois le classement effectué?

Merci ;)

+0 -0

Merci pour ce tutoriel.

Une petite astuce qui peut éviter quelques problèmes :

1
2
3
4
5
6
<?php
$page = intval($_GET['page']); // Conversion forcée en entier
// Si le nombre est invalide, on demande la première page par défaut
if($page <= 0) {
    $page = 1;
}

J'ai survolé le reste et ça m'a l'air très bien construit et expliqué. :)

Peut-être préciser qu'il ne faut pas reproduire le comportement "connexion à MySQL avec root" en production (si si, ça arrive), mais comme c'est pour la beauté de l'exemple, c'est du pinaillage… ^^

Du beau boulot au final.

Merci. Je sais maintenant utiliser OFFSET et LIMIT efficacement. ;)

Et sinon tu n'aurais pas envie de faire un tuto sur << l'infinite scroll >> ? La technique en elle même me paraît pas si compliqué. Mais au niveau du référencement, je me demande comment on peut optimiser l'affichage du contenu ? J'avais pensé à des pré-liens cachés pour que le robot d'indexation contourne ce problème. Bonne ou mauvaise idée ? :)

Et sinon tu n’aurais pas envie de faire un tuto sur « l’infinite scroll » ?

Yarflam

C’est un des trucs listés dans la conclusion, quand je parle du chargement par AJAX  ;)
J’ai hésité à en parler ici, mais cela me paraissait être quelque chose de trop particulier qui n’entrait pas vraiment dans le champ du tutoriel tel que je le voyais.

Mais au niveau du référencement, je me demande comment on peut optimiser l’affichage du contenu ? J’avais pensé à des pré-liens cachés pour que le robot d’indexation contourne ce problème. Bonne ou mauvaise idée ? :)

Yarflam

Non, pas tellement, à mon avis. Moi je mettrais une pagination "normale" que je modifierais en JavaScript. Ça a l’avantage SEO et accessibilité.

Pour l’anecdote, un client a une fois vu qu’il y avait une pagination masquée, et m’a demandé à l’enlever, malgré mes conseils et protestations. Il est revenu vers moi quelques semaines plus tard pour me dire qu’il ne trouvait plus certains éléments avec un moteur de recherche. Quand je lui ai eu réexpliqué pourquoi je ne voulais pas qu’on enlève ça et que c’était une conséquence, il n’a étrangement plus rien dit… On a remis en place et dans les trois jours, les autres éléments étaient à nouveau accessibles.

+0 -0

Non, pas tellement, à mon avis. Moi je mettrais une pagination "normale" que je modifierais en JavaScript. Ça a l'avantage SEO et accessibilité.

Ymox

Pas bête. Ta solution est bien meilleure, merci. :)

En plus, c'est tout simple à réaliser. Si on se trouve sur http://monsite.fr/page-4, on affiche avec AJAX les pages 1/2/3/5 et on scroll jusqu'à la position 4. Voir même on cache les pages 1 & 2 pour ne pas surcharger le scroll (comme sur FB pour les années).

+0 -0

Ce mot-clé et la manière de l’utiliser sont propres à MySQL, de ce que j’ai pu constater. Il n’y a apparemment pas d’équivalent "simple et direct" en PostgreSQL ni Transact SQL.

En revanche, même si ce n’est plus exactement le même SGBDR, ça devrait fonctionner avec MariaDB.

+0 -0

Merci, content que ça t’ait aidé  :)

Pour te répondre honnêtement, ça dépend de ce que représentent ces checkboxes. Est-ce que je peux te demander de créer un sujet pour ta question dans le forum Site web, tout en y expliquant un peu plus ce que tu as et ce que tu souhaites faire ? Les messages ici sont plutôt prévus pour éclaircir des points mentionnés dans le tutoriel, et moins pour des demandes d’aide spécifiques.

+0 -0

Bonjour,

1
$query = 'SELECT CALC_FOUND_ROWS * AS `total` FROM `membres` LIMIT :limite OFFSET :debut';

ne fonctionne pas apparemment à cause de CALC_FOUND_ROWS…

De plus

1
2
3
4
// Partie "Boucle"
while ($element = $resultSet->fetch()) {
    // C'est là qu'on affiche les données  :)
}

je ne sais pas ce qu’on doit mettre exactement dedans, car peu importe ce que j’insère, il me dit que je ne peux pas utiliser fetch sur un booléen :(

+0 -0

Merci du retour, je vais regarder ça.

Est-ce que je pourrais savoir quelle est la version de MySQL/MariaDB ?

Le second souci est "normal" dans la mesure où, la requête n’ayant pu être exécutée, c’est un booléen qui est retourné, donc effectivement pas moyen de récupérer des données avec.

Edit

En fait, on ne peut pas donner d’alias au nombre total. Comme le stipule le tutoriel, cela ne créé pas une nouvelle valeur récupérable dans le jeu de résultat, mais un résultat "caché" à récupérer avec une autre requête. La partie * as `total` n’est pas correcte, il faut s’en tenir à *.

Il y a une subtilité avec l’utilisation de CALC_FOUND_ROWS : comme je l’ai mis dans la légende du code, le nombre n’est pas récupéré avec les autres données, il faut le récupérer à part. Cela se fait avec la requête suivante :

1
SELECT found_rows()
+1 -0

Salut !

C’est évidemment possible, mais n’entre plus d’assez près dans le sujet du tutoriel. Si tu as un souci avec la manière d’implémenter ce choix du nombre d’éléments par page, je te propose de créer un sujet dans le forum adéquat. Les commentaires sont prévus pour des questions sur la forme principalement.

Et pour les remerciements, évidemment  :lol:

+1 -0

Bonjour, merci pour ce tuto qui fonctionne parfaitement ! Juste une petite question : je ne suis pas très à l’aise avec les boucles, mais y a-t-il un moyen de ne pas mettre de <a> sur le numéro de la page en cours, dans la liste des liens ? (pour ne pas induire en erreur un utilisateur qui ne regarderait pas forcément ce numéro dans l’url) Merci :)

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte