PaginationHelper::getNextPage()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 7
rs 10
cc 2
nc 2
nop 0
1
<?php
2
/**
3
 * File containing the {@link PaginationHelper} class
4
 *
5
 * @access public
6
 * @package Application Utils
7
 * @subpackage Misc
8
 * @see PaginationHelper
9
 */
10
11
declare(strict_types=1);
12
13
namespace AppUtils;
14
15
/**
16
 * Simple pagination calculator that can be used to
17
 * determine previous / next pages depending on the
18
 * amount of items.
19
 * 
20
 * @access public
21
 * @package Application Utils
22
 * @subpackage Misc
23
 * @author Sebastian Mordziol <[email protected]>
24
 */
25
class PaginationHelper
26
{
27
   /**
28
    * @var int
29
    */
30
    protected $total;
31
    
32
   /**
33
    * @var int
34
    */
35
    protected $perPage;
36
    
37
   /**
38
    * @var int
39
    */
40
    protected $current;
41
    
42
   /**
43
    * @var int
44
    */
45
    protected $next = 0;
46
    
47
   /**
48
    * @var int
49
    */
50
    protected $prev = 0;
51
    
52
   /**
53
    * @var int
54
    */
55
    protected $last = 0; 
56
    
57
   /**
58
    * @var int
59
    */
60
    protected $adjacentPages = 3;
61
    
62
   /**
63
    * @var int
64
    */
65
    protected $offsetEnd = 0;
66
    
67
   /**
68
    * @var int
69
    */
70
    protected $offsetStart = 0;
71
    
72
   /**
73
    * @param int $totalItems The total amount of items available.
74
    * @param int $itemsPerPage How many items to display per page.
75
    * @param int $currentPage The current page number (1-based)
76
    */
77
    public function __construct(int $totalItems, int $itemsPerPage, int $currentPage)
78
    {
79
        $this->total = $totalItems;
80
        $this->perPage = $itemsPerPage;
81
        $this->current = $currentPage;
82
        
83
        $this->calculate();
84
    }
85
    
86
   /**
87
    * Sets the amount of adjacent pages to display next to the
88
    * current one when using the pages list.
89
    *
90
    * @param int $amount
91
    * @return PaginationHelper
92
    */
93
    public function setAdjacentPages(int $amount) : PaginationHelper
94
    {
95
        $this->adjacentPages = $amount;
96
        return $this;
97
    }
98
    
99
   /**
100
    * Whether there is a next page after the current page.
101
    * @return bool
102
    */
103
    public function hasNextPage() : bool
104
    {
105
        return $this->next > 0;
106
    }
107
    
108
   /**
109
    * The next page number. Returns the last page
110
    * number if there is no next page.
111
    *  
112
    * @return int
113
    */
114
    public function getNextPage() : int
115
    {
116
        if($this->next === 0) {
117
            return $this->last;
118
        }
119
        
120
        return $this->next;
121
    }
122
    
123
   /**
124
    * Whether there is a previous page before the current page.
125
    * @return bool
126
    */
127
    public function hasPreviousPage() : bool
128
    {
129
        return $this->prev > 0;
130
    }
131
    
132
   /**
133
    * The previous page number. Returns the first page
134
    * number if there is no previous page.
135
    * 
136
    * @return int
137
    */
138
    public function getPreviousPage() : int
139
    {
140
        if($this->prev === 0) {
141
            return 1;
142
        }
143
        
144
        return $this->prev;
145
    }
146
    
147
   /**
148
    * Retrieves the last page number.
149
    * @return int
150
    */
151
    public function getLastPage() : int
152
    {
153
        return $this->last;
154
    }
155
    
156
   /**
157
    * Whether there is more than one page, i.e. whether
158
    * pagination is required at all.
159
    *  
160
    * @return bool
161
    */
162
    public function hasPages() : bool
163
    {
164
        return $this->last > 1;
165
    }
166
    
167
    public function getCurrentPage() : int
168
    {
169
        return $this->current;
170
    }
171
    
172
   /**
173
    * Retrieves a list of page numbers for a page
174
    * navigator, to quickly jump between pages.
175
    *
176
    * @return int[]
177
    */
178
    public function getPageNumbers() : array
179
    {
180
        $adjacent = $this->adjacentPages;
181
182
        // adjust the adjacent value if it exceeds the
183
        // total amount of pages
184
        $adjacentTotal = ($adjacent * 2) + 1;
185
        if($adjacentTotal > $this->last) 
186
        {
187
            $adjacent = (int)floor($this->last / 2);
188
        }
189
        
190
        // determine the maximum amount of 
191
        // pages that one can go forward or
192
        // back from the current position.
193
        $maxBack = $this->current - 1;
194
        $maxFwd = $this->last - $this->current;
195
        $back = 0;
196
        $fwd = 0;
197
        
198
        if($maxBack >= $adjacent) {
199
            $back = $adjacent; 
200
        } else {
201
            $back = $maxBack;
202
        }
203
        
204
        if($maxFwd >= $adjacent)  {
205
            $fwd = $adjacent;
206
        } else {
207
            $fwd = $maxFwd;
208
        }
209
        
210
        // now calculate the amount of pages to add
211
        // left or right, depending on whether we
212
        // are at the beginning of the list, or at
213
        // the end.
214
        $backDiff = $adjacent - $back;
215
        $fwdDiff = $adjacent - $fwd;
216
        
217
        $fwd += $backDiff;
218
        $back += $fwdDiff;
219
        
220
        if($fwd > $maxFwd) { $fwd = $maxFwd; }
221
        if($back > $maxBack) { $back = $maxBack; }
222
        
223
        // calculate the first and last page in the list
224
        $prev = $this->current - $back;
225
        $next = $this->current + $fwd;
226
        
227
        // failsafe so we stay within the bounds
228
        if($prev < 1) { $prev = 1; }
229
        if($next > $this->last) { $next = $this->last; }
230
        
231
        // create and return the page numbers list
232
        $numbers = range($prev, $next);
233
234
        /*
235
        print_r(array(
236
            'current' => $this->current,
237
            'totalPages' => $this->last,
238
            'adjacent' => $adjacent,
239
            'maxBack' => $maxBack,
240
            'maxFwd' => $maxFwd,
241
            'back' => $back,
242
            'fwd' => $fwd,
243
            'backDiff' => $backDiff,
244
            'fwdDiff' => $fwdDiff,
245
            'prev' => $prev,
246
            'next' => $next,
247
            'numbers' => $numbers
248
        ));*/
249
        
250
        return $numbers;
251
    }
252
    
253
   /**
254
    * Whether the specified page number is the current page.
255
    * 
256
    * @param int $pageNumber
257
    * @return bool
258
    */
259
    public function isCurrentPage(int $pageNumber) : bool
260
    {
261
        return $pageNumber === $this->current;
262
    }
263
    
264
   /**
265
    * Retrieves the 1-based starting offset of
266
    * items currently displayed in the page.
267
    * 
268
    * Note: Use this to create a text like 
269
    * "showing entries x to y".
270
    * 
271
    * @return int
272
    * @see PaginationHelper::getOffsetEnd()
273
    */
274
    public function getItemsStart() : int
275
    {
276
        return $this->getOffsetStart() + 1;
277
    }
278
279
   /**
280
    * Retrieves the 1-based ending offset of
281
    * items currently displayed in the page.
282
    * 
283
    * Note: Use this to create a text like 
284
    * "showing entries x to y".
285
    * 
286
    * @return int
287
    * @see PaginationHelper::getOffsetStart()
288
    */
289
    public function getItemsEnd() : int
290
    {
291
        return $this->getOffsetEnd() + 1;
292
    }
293
    
294
   /**
295
    * Retrieves the 0-based starting offset of
296
    * items currently displayed in the page.
297
    * 
298
    * @return int
299
    * @see PaginationHelper::getItemsStart()
300
    */
301
    public function getOffsetStart() : int
302
    {
303
        return $this->offsetStart;
304
    }
305
    
306
   /**
307
    * Retrieves the 0-based ending offset of
308
    * items currently displayed in the page.
309
    * 
310
    * @return int
311
    * @see PaginationHelper::getItemsEnd()
312
    */
313
    public function getOffsetEnd() : int
314
    {
315
        return $this->offsetEnd;
316
    }
317
    
318
    protected function calculate() : void
319
    {
320
        $pages = (int)ceil($this->total / $this->perPage);
321
        
322
        if($this->current < 1)
323
        {
324
            $this->current = 1;
325
        }
326
        else if($this->current > $pages)
327
        {
328
            $this->current = $pages;
329
        }
330
        
331
        $this->last = $pages;
332
        
333
        $nextPage = $this->current + 1;
334
        if($nextPage <= $pages) {
335
            $this->next = $nextPage;
336
        }
337
        
338
        $prevPage = $this->current - 1;
339
        if($prevPage > 0) {
340
            $this->prev = $prevPage;
341
        }
342
        
343
        $this->offsetStart = ($this->current - 1) * $this->perPage;
344
        
345
        $this->offsetEnd = $this->offsetStart + $this->perPage;
346
        if($this->offsetEnd > ($this->total - 1)) {
347
            $this->offsetEnd = ($this->total - 1);
348
        }
349
    }
350
}
351