Voir le flux RSS

rawsrc

Pagination

Note : 2 votes pour une moyenne de 4,50.
par , 24/06/2019 à 19h16 (225 Affichages)
Salut les développeurs,

aujourd'hui je vais vous parler pagination.

La pagination est très pratique car elle permet d'afficher de gros volumes de données en les découpant en sous-ensembles humainement et informatiquement gérables.

Quand une de vos requête renvoie par exemple 15 000 enregistrements, il n'est pas possible de les afficher sans réduire leur quantité. C'est le rôle de la pagination.
Pour que cela fonctionne, il faut que le système de pagination soit capable de calculer et de positionner correctement le curseur des pages en fonction de beaucoup de paramètres dynamiques :

  • le nombre total d'enregistrements
  • le numéro de page demandé
  • le nombre d'enregistrements par page
  • le nombre de pages à afficher dans le système de pagination
  • affichage opportun des accès directs tels que : premier, précédent, suivant, dernier


Bref, c'est un travail fastidieux et répétitif que je me propose de vous simplifier avec une classe qui fait tout le boulot et qui en plus (cerise sur le gâteau) permet de déterminer la clause SQL qui va vous permettre d'extraire correctement les données de votre base en fonction de tous ces paramètres dynamiques (la fameuse clause LIMIT)

Code php : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
<?php
 
declare(strict_types=1);
 
/**
 * 2019-06-24
 *
 * Licence : vous en faite ce que vous voulez
 *
 * @author rawsrc   https://www.developpez.net/forums/u32058/rawsrc/
 */
class Paginator
{
    /**
     * @var bool
     */
    private $show_first_prev = true;
    /**
     * @var bool
     */
    private $show_next_last = true;
    /**
     * @var int
     */
    private $asked_page = 1;
    /**
     * @var int
     */
    private $nb_rows_per_page = 10;
    /**
     * @var int   Total number of records in the dataset before pagination
     */
    private $nb_records = 0;
    /**
     * @var int  How many cells to render between the min and max page index
     */
    private $pages_range = 10;
 
    /**
     * params => [
     *     show_first_prev  => bool,
     *     show_next_last   => bool,
     *     asked_page       => int,
     *     nb_rows_per_page => int,
     *     nb_records       => int,
     *     pages_range      => int
     * ]
     *
     * @param array $params
     */
    public function __construct(array $params)
    {
        if (isset($params['show_first_prev'])) {
            $this->show_first_prev = (bool)$params['show_first_prev'];
        }
 
        if (isset($params['show_next_last'])) {
            $this->show_next_last = (bool)$params['show_next_last'];
        }
 
        if (isset($params['asked_page'])) {
            $this->asked_page = (int)$params['asked_page'];
        }
 
        if (isset($params['nb_rows_per_page'])) {
            $this->nb_rows_per_page = (int)$params['nb_rows_per_page'];
        }
 
        if (isset($params['nb_records'])) {
            $this->nb_records = (int)$params['nb_records'];
        }
 
        if (isset($params['pages_range'])) {
            $this->pages_range = (int)$params['pages_range'];
        }
    }
 
    /**
     * @return bool
     */
    public function showFirstPrev(): bool
    {
        return $this->show_first_prev;
    }
 
    /**
     * @return bool
     */
    public function showNextLast(): bool
    {
        return $this->show_next_last;
    }
 
    /**
     * @return int
     */
    public function askedPage(): int
    {
        return $this->asked_page;
    }
 
    /**
     * @return int
     */
    public function nbRowsPerPage(): int
    {
        return $this->nb_rows_per_page;
    }
 
    /**
     * @return int
     */
    public function nbRecords(): int
    {
        return $this->nb_records;
    }
 
    /**
     * @return int
     */
    public function pagesRange(): int
    {
        return $this->pages_range;
    }
 
    /**
     * @return int
     */
    public function nbPages(): int
    {
        return ($this->nb_rows_per_page > 0) ? ceil($this->nb_records/$this->nb_rows_per_page) : 0;
    }
 
    /**
     * Compute the page index manager and return an array of values
     * ex: first, prev, list of numeric page number, next, last
     *
     * The current page will always be in the middle of the range
     *
     * @return array
     */
    public function pageList(): array
    {
        if ($this->nb_records > 0) {
 
            if ($this->nb_rows_per_page <= 0) {
                $this->nb_rows_per_page = 10;
            }
 
            if ($this->pages_range <= 0) {
                $this->pages_range = 10;
            }
 
            $nb_pages = $this->nbPages();
 
            if ($nb_pages === 0) {
                return [];
            }
 
            if ($nb_pages <= $this->pages_range) {
                $start = 1;
                $end   = $nb_pages;
            } elseif ($this->asked_page === 1) {
                $start = 1;
                $end   = $this->pages_range;
            } else {
                // the current page number is in the middle of the limits
                // $pages_range / 2 -> if int value : nb of visible pages on left = nb of visible pages on right - 1
                $half = $this->pages_range / 2;
                if (($this->asked_page - $half) <= 1) {
                    $start = 1;
                    $end   = $this->pages_range;
                } elseif (($this->asked_page + $half) >= $nb_pages) {
                    $start = $nb_pages - $this->pages_range + 1;
                    $end   = $nb_pages;
                } else {
                    if (is_int($half)) {
                        $start = $this->asked_page - $half + 1;
                        $end   = $this->asked_page + $half;
                    } else {
                        $start = $this->asked_page - floor($half);
                        $end   = $this->asked_page + floor($half);
                    }
                }
            }
        }
 
        $pages = range($start, $end);
 
        if ($nb_pages > $this->pages_range) {
            if ($this->show_first_prev) {
                array_unshift($pages, 'first', 'prev');
            }
            if ($this->show_next_last) {
                array_push($pages, 'next', 'last');
            }
        }
 
        return $pages;
    }
 
    /**
     * Compute the limit clause for a SQL statement
     * Careful: Zero based database records number
     *
     * @return array [0 => offset, 1 => length]
     */
    public function limitClauseData(): array
    {
        $nb_pages = $this->nbPages();
 
        // if $nb_pages <= 0 -> we lock the clause LIMIT -> offset 0, length 0
        if ($nb_pages <= 0) {
            return [0, 0];
        }
 
        if ($this->asked_page >= $nb_pages) {
            $this->asked_page = $nb_pages;
        }
        $offset = max(0, ($this->asked_page - 1) * $this->nb_rows_per_page);
 
        return [$offset, $this->nb_rows_per_page];
    }
}
Comment l'utiliser ?

On va prendre un cas concret :
une requête filtrée renvoie 1436 enregistrements que vous devez paginer en affichant les boutons Premier, Précédent, Suivant, Dernier (si nécessaire), la page demandée est la 43ème, vous affichez 20 enregistrements par page et la pagination devra offrir l'accès à 15 pages de rang.
Cela se codera ainsi :
Code php : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
$paginator = new Paginator([
    'show_first_prev'  => true,
    'show_next_last'   => true,
    'asked_page'       => 43,
    'nb_rows_per_page' => 20,
    'nb_records'       => 1436,
    'pages_range'      => 15
]);
 
// pour n'extraire que les données correspondant à la page demandée 43ème, il faudra refaire une requête SQL avec une clause LIMIT : 
$limit = $paginator->limitClauseData();  // return [840, 20]   ==> en sql : LIMIT 840, 20
$pages = $paginator->pageList(); // [first, prev, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, Next, Last]

Maintenant on va changer quelques données :
une requête filtrée renvoie 100 enregistrements que vous devez paginer en affichant les boutons Premier, Précédent, Suivant, Dernier (si nécessaire), la page demandée est la 1ère, vous affichez 20 enregistrements par page et la pagination devra offrir l'accès à 15 pages de rang.
Cela se codera ainsi :
Code php : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
$paginator = new Paginator([
    'show_first_prev'  => true,
    'show_next_last'   => true,
    'asked_page'       => 1,
    'nb_rows_per_page' => 20,
    'nb_records'       => 100,
    'pages_range'      => 15
]);
 
// pour n'extraire que les données correspondant à la page demandée 1ère, il faudra refaire une requête SQL avec une clause LIMIT : 
$limit = $paginator->limitClauseData();  // return [0, 20]   ==> en sql : LIMIT 0, 20
$pages = $paginator->pageList(); // [1, 2, 3, 4, 5]
Remarquez que dans ce deuxième exemple, les boutons inutiles ne sont pas affichés.

Enfin, veuillez noter que la page demandée est toujours centrée (dans la mesure du possible) entre les limites du nombre de pages à afficher dans la pagination (regardez la position de la page 43 du premier exemple dans l'index des pages).

En espérant que cela vous sera utile et comme d'hab, n'hésitez pas à me poser des questions ou faire un retour sur cet outil qui pose une chouette base de travail

Bon codage

Envoyer le billet « Pagination » dans le blog Viadeo Envoyer le billet « Pagination » dans le blog Twitter Envoyer le billet « Pagination » dans le blog Google Envoyer le billet « Pagination » dans le blog Facebook Envoyer le billet « Pagination » dans le blog Digg Envoyer le billet « Pagination » dans le blog Delicious Envoyer le billet « Pagination » dans le blog MySpace Envoyer le billet « Pagination » dans le blog Yahoo

Mis à jour 24/06/2019 à 21h43 par rawsrc

Catégories
PHP , Développement Web

Commentaires