1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Spiral Framework. |
4
|
|
|
* |
5
|
|
|
* @license MIT |
6
|
|
|
* @author Anton Titov (Wolfy-J) |
7
|
|
|
*/ |
8
|
|
|
namespace Spiral\Pagination; |
9
|
|
|
|
10
|
|
|
use Psr\Http\Message\ServerRequestInterface; |
11
|
|
|
use Psr\Http\Message\UriInterface; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Default paginator implementation, uses active server request Uri to generate page urls. |
15
|
|
|
*/ |
16
|
|
|
class Paginator implements PredictableInterface, \Countable |
17
|
|
|
{ |
18
|
|
|
/** |
19
|
|
|
* Default limit value. |
20
|
|
|
*/ |
21
|
|
|
const DEFAULT_LIMIT = 25; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Default page parameter. |
25
|
|
|
*/ |
26
|
|
|
const DEFAULT_PARAMETER = 'page'; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* The query array will be connected to every page URL generated by paginator. |
30
|
|
|
* |
31
|
|
|
* @var array |
32
|
|
|
*/ |
33
|
|
|
private $queryData = []; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @var string |
37
|
|
|
*/ |
38
|
|
|
private $pageParameter = 'page'; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* @var int |
42
|
|
|
*/ |
43
|
|
|
private $pageNumber = 1; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @var int |
47
|
|
|
*/ |
48
|
|
|
private $countPages = 1; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @var int |
52
|
|
|
*/ |
53
|
|
|
private $limit = self::DEFAULT_LIMIT; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @var int |
57
|
|
|
*/ |
58
|
|
|
private $count = 0; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @invisible |
62
|
|
|
* @var ServerRequestInterface |
63
|
|
|
*/ |
64
|
|
|
private $request = null; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @var UriInterface |
68
|
|
|
*/ |
69
|
|
|
private $uri = null; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* {@inheritdoc} |
73
|
|
|
*/ |
74
|
|
|
public function __construct( |
75
|
|
|
ServerRequestInterface $request, |
76
|
|
|
$pageParameter = self::DEFAULT_PARAMETER |
77
|
|
|
) { |
78
|
|
|
$this->setRequest($request); |
79
|
|
|
$this->setParameter($pageParameter); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @param ServerRequestInterface $request |
84
|
|
|
*/ |
85
|
|
|
public function setRequest(ServerRequestInterface $request) |
86
|
|
|
{ |
87
|
|
|
$this->request = $request; |
88
|
|
|
$this->uri = $request->getUri(); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* {@inheritdoc} |
93
|
|
|
*/ |
94
|
|
|
public function setUri(UriInterface $uri) |
95
|
|
|
{ |
96
|
|
|
$this->uri = $uri; |
97
|
|
|
|
98
|
|
|
return $this; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* {@inheritdoc} |
103
|
|
|
*/ |
104
|
|
|
public function getUri() |
105
|
|
|
{ |
106
|
|
|
return $this->uri; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* Specify the query (as array) which will be attached to every generated page URL. |
111
|
|
|
* |
112
|
|
|
* @param array $query |
113
|
|
|
* @param bool $replace Replace existed query data entirely. |
114
|
|
|
*/ |
115
|
|
|
public function setQuery(array $query, $replace = false) |
116
|
|
|
{ |
117
|
|
|
$this->queryData = $replace ? $query : $query + $this->queryData; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* @return array |
122
|
|
|
*/ |
123
|
|
|
public function getQuery() |
124
|
|
|
{ |
125
|
|
|
return $this->queryData; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Update page parameter name from request query. Page number should be fetched from queryParams |
130
|
|
|
* of provided request instance. |
131
|
|
|
* |
132
|
|
|
* @param string $pageParameter |
133
|
|
|
* @return self |
134
|
|
|
*/ |
135
|
|
|
public function setParameter($pageParameter) |
136
|
|
|
{ |
137
|
|
|
$this->pageParameter = $pageParameter; |
138
|
|
|
$queryParams = $this->request->getQueryParams(); |
139
|
|
|
if (isset($queryParams[$this->pageParameter])) { |
140
|
|
|
$this->setPage($queryParams[$this->pageParameter]); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
return $this; |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
/** |
147
|
|
|
* Get page query parameter name. |
148
|
|
|
* |
149
|
|
|
* @return string |
150
|
|
|
*/ |
151
|
|
|
public function getParameter() |
152
|
|
|
{ |
153
|
|
|
return $this->pageParameter; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* {@inheritdoc} |
158
|
|
|
*/ |
159
|
|
View Code Duplication |
public function setCount($count) |
|
|
|
|
160
|
|
|
{ |
161
|
|
|
$this->count = abs(intval($count)); |
|
|
|
|
162
|
|
|
if ($this->count > 0) { |
163
|
|
|
$this->countPages = ceil($this->count / $this->limit); |
|
|
|
|
164
|
|
|
} else { |
165
|
|
|
$this->countPages = 1; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
return $this; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* {@inheritdoc} |
173
|
|
|
*/ |
174
|
|
|
public function count() |
175
|
|
|
{ |
176
|
|
|
return $this->count; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* Set pagination limit. |
181
|
|
|
* |
182
|
|
|
* @param int $limit |
183
|
|
|
* @return $this |
184
|
|
|
*/ |
185
|
|
View Code Duplication |
public function setLimit($limit) |
|
|
|
|
186
|
|
|
{ |
187
|
|
|
$this->limit = abs(intval($limit)); |
|
|
|
|
188
|
|
|
if ($this->count > 0) { |
189
|
|
|
$this->countPages = ceil($this->count / $this->limit); |
|
|
|
|
190
|
|
|
} else { |
191
|
|
|
$this->countPages = 1; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
return $this; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* Get pagination limit (items per page). |
199
|
|
|
* |
200
|
|
|
* @return int |
201
|
|
|
*/ |
202
|
|
|
public function getLimit() |
203
|
|
|
{ |
204
|
|
|
return $this->limit; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* {@inheritdoc} |
209
|
|
|
*/ |
210
|
|
|
public function setPage($number) |
211
|
|
|
{ |
212
|
|
|
$this->pageNumber = abs(intval($number)); |
|
|
|
|
213
|
|
|
|
214
|
|
|
//Real page number |
215
|
|
|
return $this->getPage(); |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* {@inheritdoc} |
220
|
|
|
*/ |
221
|
|
|
public function getPage() |
222
|
|
|
{ |
223
|
|
|
if ($this->pageNumber < 1) { |
224
|
|
|
return 1; |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
if ($this->pageNumber > $this->countPages) { |
228
|
|
|
return $this->countPages; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
return $this->pageNumber; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Get pagination offset. |
236
|
|
|
* |
237
|
|
|
* @return int |
238
|
|
|
*/ |
239
|
|
|
public function getOffset() |
240
|
|
|
{ |
241
|
|
|
return ($this->getPage() - 1) * $this->limit; |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
/** |
245
|
|
|
* The count of pages required to represent all records using a specified limit value. |
246
|
|
|
* |
247
|
|
|
* @return int |
248
|
|
|
*/ |
249
|
|
|
public function countPages() |
250
|
|
|
{ |
251
|
|
|
return $this->countPages; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* {@inheritdoc} |
256
|
|
|
*/ |
257
|
|
|
public function countDisplayed() |
258
|
|
|
{ |
259
|
|
|
if ($this->getPage() == $this->countPages) { |
260
|
|
|
return $this->count - $this->getOffset(); |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
return $this->limit; |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* {@inheritdoc} |
268
|
|
|
*/ |
269
|
|
|
public function isRequired() |
270
|
|
|
{ |
271
|
|
|
return ($this->countPages > 1); |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* {@inheritdoc} |
276
|
|
|
*/ |
277
|
|
|
public function nextPage() |
278
|
|
|
{ |
279
|
|
|
if ($this->getPage() != $this->countPages) { |
280
|
|
|
return $this->getPage() + 1; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
return false; |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
/** |
287
|
|
|
* {@inheritdoc} |
288
|
|
|
*/ |
289
|
|
|
public function previousPage() |
290
|
|
|
{ |
291
|
|
|
if ($this->getPage() > 1) { |
292
|
|
|
return $this->getPage() - 1; |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
return false; |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* {@inheritdoc} |
300
|
|
|
*/ |
301
|
|
|
public function paginate(PaginableInterface $paginable) |
302
|
|
|
{ |
303
|
|
|
$this->setCount($paginable->count()); |
304
|
|
|
|
305
|
|
|
$paginable->offset($this->getOffset()); |
306
|
|
|
$paginable->limit($this->getLimit()); |
307
|
|
|
|
308
|
|
|
return $paginable; |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* {@inheritdoc} |
313
|
|
|
*/ |
314
|
|
|
public function uri($pageNumber) |
315
|
|
|
{ |
316
|
|
|
return $this->uri->withQuery(http_build_query( |
317
|
|
|
$this->getQuery() + [$this->pageParameter => $pageNumber] |
318
|
|
|
)); |
319
|
|
|
} |
320
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.