Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
81.01% |
64 / 79 |
|
91.67% |
11 / 12 |
CRAP | |
0.00% |
0 / 1 |
AbstractPaginator | |
81.01% |
64 / 79 |
|
91.67% |
11 / 12 |
39.01 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
setQueryKey | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setBookends | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
5 | |||
getTotal | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getPerPage | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getRange | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getQueryKey | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCurrentPage | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getNumberOfPages | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getBookend | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getBookends | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
calculateRange | |
73.68% |
42 / 57 |
|
0.00% |
0 / 1 |
22.27 |
1 | <?php |
2 | /** |
3 | * Pop PHP Framework (http://www.popphp.org/) |
4 | * |
5 | * @link https://github.com/popphp/popphp-framework |
6 | * @author Nick Sagona, III <dev@nolainteractive.com> |
7 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
8 | * @license http://www.popphp.org/license New BSD License |
9 | */ |
10 | |
11 | /** |
12 | * @namespace |
13 | */ |
14 | namespace Pop\Paginator; |
15 | |
16 | /** |
17 | * Abstract paginator type class |
18 | * |
19 | * @category Pop |
20 | * @package Pop\Paginator |
21 | * @author Nick Sagona, III <dev@nolainteractive.com> |
22 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
23 | * @license http://www.popphp.org/license New BSD License |
24 | * @version 4.0.0 |
25 | */ |
26 | abstract class AbstractPaginator implements PaginatorInterface |
27 | { |
28 | |
29 | /** |
30 | * Total number of items |
31 | * @var int |
32 | */ |
33 | protected int $total = 0; |
34 | |
35 | /** |
36 | * Number of items per page |
37 | * @var int |
38 | */ |
39 | protected int $perPage = 10; |
40 | |
41 | /** |
42 | * Range of pages per page |
43 | * @var int |
44 | */ |
45 | protected int $range = 10; |
46 | |
47 | /** |
48 | * Query key |
49 | * @var string |
50 | */ |
51 | protected string $queryKey = 'page'; |
52 | |
53 | /** |
54 | * Current page property |
55 | * @var int |
56 | */ |
57 | protected int $currentPage = 1; |
58 | |
59 | /** |
60 | * Number of pages property |
61 | * @var ?int |
62 | */ |
63 | protected ?int $numberOfPages = null; |
64 | |
65 | /** |
66 | * Current page start index property |
67 | * @var ?int |
68 | */ |
69 | protected ?int $start = null; |
70 | |
71 | /** |
72 | * Current page end index property |
73 | * @var ?int |
74 | */ |
75 | protected ?int $end = null; |
76 | |
77 | /** |
78 | * Page bookends |
79 | * @var array |
80 | */ |
81 | protected array $bookends = [ |
82 | 'start' => '«', |
83 | 'previous' => '‹', |
84 | 'next' => '›', |
85 | 'end' => '»' |
86 | ]; |
87 | |
88 | /** |
89 | * Constructor |
90 | * |
91 | * Instantiate the paginator object |
92 | * |
93 | * @param int $total |
94 | * @param int $perPage |
95 | * @param int $range |
96 | */ |
97 | public function __construct(int $total, int $perPage = 10, int $range = 10) |
98 | { |
99 | $this->total = $total; |
100 | $this->perPage = $perPage; |
101 | $this->range = $range; |
102 | } |
103 | |
104 | /** |
105 | * Set the query key |
106 | * |
107 | * @param string $key |
108 | * @return AbstractPaginator |
109 | */ |
110 | public function setQueryKey(string $key): AbstractPaginator |
111 | { |
112 | $this->queryKey = $key; |
113 | return $this; |
114 | } |
115 | |
116 | /** |
117 | * Set the bookends |
118 | * |
119 | * @param array $bookends |
120 | * @return AbstractPaginator |
121 | */ |
122 | public function setBookends(array $bookends): AbstractPaginator |
123 | { |
124 | if (array_key_exists('start', $bookends)) { |
125 | $this->bookends['start'] = $bookends['start']; |
126 | } |
127 | if (array_key_exists('previous', $bookends)) { |
128 | $this->bookends['previous'] = $bookends['previous']; |
129 | } |
130 | if (array_key_exists('next', $bookends)) { |
131 | $this->bookends['next'] = $bookends['next']; |
132 | } |
133 | if (array_key_exists('end', $bookends)) { |
134 | $this->bookends['end'] = $bookends['end']; |
135 | } |
136 | |
137 | return $this; |
138 | } |
139 | |
140 | /** |
141 | * Get the content items total |
142 | * |
143 | * @return int |
144 | */ |
145 | public function getTotal(): int |
146 | { |
147 | return $this->total; |
148 | } |
149 | |
150 | /** |
151 | * Get the per page |
152 | * |
153 | * @return int |
154 | */ |
155 | public function getPerPage(): int |
156 | { |
157 | return $this->perPage; |
158 | } |
159 | |
160 | /** |
161 | * Get the page range |
162 | * |
163 | * @return int |
164 | */ |
165 | public function getRange(): int |
166 | { |
167 | return $this->range; |
168 | } |
169 | |
170 | /** |
171 | * Get the query key |
172 | * |
173 | * @return string |
174 | */ |
175 | public function getQueryKey(): string |
176 | { |
177 | return $this->queryKey; |
178 | } |
179 | |
180 | /** |
181 | * Get the current page |
182 | * |
183 | * @return int |
184 | */ |
185 | public function getCurrentPage(): int |
186 | { |
187 | return $this->currentPage; |
188 | } |
189 | |
190 | /** |
191 | * Get the number of pages |
192 | * |
193 | * @return int |
194 | */ |
195 | public function getNumberOfPages(): int |
196 | { |
197 | return $this->numberOfPages; |
198 | } |
199 | |
200 | /** |
201 | * Get a bookend |
202 | * |
203 | * @param string $key |
204 | * @return string|null |
205 | */ |
206 | public function getBookend(string $key): string|null |
207 | { |
208 | return $this->bookends[$key] ?? null; |
209 | } |
210 | |
211 | /** |
212 | * Get the bookends |
213 | * |
214 | * @return array |
215 | */ |
216 | public function getBookends(): array |
217 | { |
218 | return $this->bookends; |
219 | } |
220 | |
221 | /** |
222 | * Calculate the page range |
223 | * |
224 | * @param int $page |
225 | * @return array |
226 | */ |
227 | public function calculateRange(int $page = 1): array |
228 | { |
229 | $this->currentPage = $page; |
230 | |
231 | // Calculate the number of pages based on the remainder. |
232 | $remainder = $this->total % $this->perPage; |
233 | $this->numberOfPages = ($remainder != 0) ? (floor(($this->total / $this->perPage)) + 1) : |
234 | floor(($this->total / $this->perPage)); |
235 | |
236 | // Calculate the start index. |
237 | $this->start = ($page * $this->perPage) - $this->perPage; |
238 | |
239 | // Calculate the end index. |
240 | if (($page == $this->numberOfPages) && ($remainder == 0)) { |
241 | $this->end = $this->start + $this->perPage; |
242 | } else if ($page == $this->numberOfPages) { |
243 | $this->end = (($page * $this->perPage) - ($this->perPage - $remainder)); |
244 | } else { |
245 | $this->end = ($page * $this->perPage); |
246 | } |
247 | |
248 | // Calculate if out of range. |
249 | if ($this->start >= $this->total) { |
250 | $this->start = 0; |
251 | $this->end = $this->perPage; |
252 | } |
253 | |
254 | // Check and calculate for any page ranges. |
255 | if ((($this->range === null) || ($this->range > $this->numberOfPages)) && ($this->total === null)) { |
256 | $range = [ |
257 | 'start' => 1, |
258 | 'end' => $this->numberOfPages, |
259 | 'prev' => false, |
260 | 'next' => false |
261 | ]; |
262 | } else { |
263 | // If page is within the first range block. |
264 | if (($page <= $this->range) && ($this->numberOfPages <= $this->range)) { |
265 | $range = [ |
266 | 'start' => 1, |
267 | 'end' => $this->numberOfPages, |
268 | 'prev' => false, |
269 | 'next' => false |
270 | ]; |
271 | // If page is within the first range block, with a next range. |
272 | } else if (($page <= $this->range) && ($this->numberOfPages > $this->range)) { |
273 | $range = [ |
274 | 'start' => 1, |
275 | 'end' => $this->range, |
276 | 'prev' => false, |
277 | 'next' => true |
278 | ]; |
279 | // Else, if page is within the last range block, with an uneven remainder. |
280 | } else if ($page > ($this->range * floor($this->numberOfPages / $this->range))) { |
281 | $range = [ |
282 | 'start' => ($this->range * floor($this->numberOfPages / $this->range)) + 1, |
283 | 'end' => $this->numberOfPages, |
284 | 'prev' => true, |
285 | 'next' => false |
286 | ]; |
287 | // Else, if page is within the last range block, with no remainder. |
288 | } else if ((($this->numberOfPages % $this->range) == 0) && ($page > ($this->range * (($this->numberOfPages / $this->range) - 1)))) { |
289 | $range = [ |
290 | 'start' => ($this->range * (($this->numberOfPages / $this->range) - 1)) + 1, |
291 | 'end' => $this->numberOfPages, |
292 | 'prev' => true, |
293 | 'next' => false |
294 | ]; |
295 | // Else, if page is within a middle range block. |
296 | } else { |
297 | $posInRange = (($page % $this->range) == 0) ? ($this->range - 1) : (($page % $this->range) - 1); |
298 | $linkStart = $page - $posInRange; |
299 | $range = [ |
300 | 'start' => $linkStart, |
301 | 'end' => $linkStart + ($this->range - 1), |
302 | 'prev' => true, |
303 | 'next' => true |
304 | ]; |
305 | } |
306 | } |
307 | |
308 | return $range; |
309 | } |
310 | |
311 | } |