Completed
Push — master ( 391477...8763ad )
by Arman
21s queued 15s
created

BasePaginator::getUri()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 7
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 12
rs 10
1
<?php
2
3
namespace Quantum\Libraries\Database;
4
5
abstract class BasePaginator implements PaginatorInterface
6
{
7
	/**
8
	 * @var string
9
	 */
10
	protected const PAGINATION_CLASS = 'pagination';
11
12
	/**
13
	 * @var string
14
	 */
15
	protected const PAGINATION_CLASS_ACTIVE = 'active';
16
17
	/**
18
	 * @var string
19
	 */
20
	protected const PER_PAGE = 'per_page';
21
22
	/**
23
	 * @var string
24
	 */
25
	protected const PAGE = 'page';
26
27
	/**
28
	 * @var int
29
	 */
30
	protected const FIRST_PAGE_NUMBER = 1;
31
32
	/**
33
	 * @var int
34
	 */
35
	protected const MINIMUM_PAGE_ITEMS_COUNT = 3;
36
37
	/**
38
	 * @var int
39
	 */
40
	protected const EDGE_PADDING = 3;
41
42
	/**
43
	 * @var int
44
	 */
45
	protected $total;
46
47
	/**
48
	 * @var string
49
	 */
50
	protected $baseUrl;
51
52
	/**
53
	 * @var int
54
	 */
55
	protected $perPage;
56
57
	/**
58
	 * @var int
59
	 */
60
	protected $page;
61
62
	/**
63
	 * @return int
64
	 */
65
	public function currentPageNumber(): int
66
	{
67
		return $this->page;
68
	}
69
70
	/**
71
	 * @param bool $withBaseUrl
72
	 * @return string|null
73
	 */
74
	public function currentPageLink(bool $withBaseUrl = false): ?string
75
	{
76
		return $this->getPageLink($this->page, $withBaseUrl);
77
	}
78
79
	/**
80
	 * @return int|null
81
	 */
82
	public function previousPageNumber(): ?int
83
	{
84
		$previous = null;
85
		if ($this->page > 1) {
86
			$previous = $this->page - 1;
87
		} elseif ($this->page == 1) {
88
			$previous = $this->page;
89
		}
90
91
		return $previous;
92
	}
93
94
	/**
95
	 * @param bool $withBaseUrl
96
	 * @return string|null
97
	 */
98
	public function previousPageLink(bool $withBaseUrl = false): ?string
99
	{
100
		return $this->getPageLink($this->previousPageNumber(), $withBaseUrl);
101
	}
102
103
	/**
104
	 * @return int|null
105
	 */
106
	public function nextPageNumber(): ?int
107
	{
108
		$next = null;
109
		if ($this->page < $this->lastPageNumber()) {
110
			$next = $this->page + 1;
111
		} elseif ($this->page == $this->lastPageNumber()) {
112
			$next = $this->page;
113
		}
114
		return $next;
115
	}
116
117
	/**
118
	 * @param bool $withBaseUrl
119
	 * @return string|null
120
	 */
121
	public function nextPageLink(bool $withBaseUrl = false): ?string
122
	{
123
		return $this->getPageLink($this->nextPageNumber(), $withBaseUrl);
124
	}
125
126
	/**
127
	 * @param bool $withBaseUrl
128
	 * @return string|null
129
	 */
130
	public function firstPageLink(bool $withBaseUrl = false): ?string
131
	{
132
		return $this->getPageLink(self::FIRST_PAGE_NUMBER, $withBaseUrl);
133
	}
134
135
	/**
136
	 * @return int
137
	 */
138
	public function lastPageNumber(): int
139
	{
140
		return (int)ceil($this->total() / $this->perPage);
141
	}
142
143
	/**
144
	 * @param bool $withBaseUrl
145
	 * @return string|null
146
	 */
147
	public function lastPageLink(bool $withBaseUrl = false): ?string
148
	{
149
		return $this->getPageLink($this->lastPageNumber(), $withBaseUrl);
150
	}
151
152
	/**
153
	 * @return int
154
	 */
155
	public function perPage(): int
156
	{
157
		return $this->perPage;
158
	}
159
160
	/**
161
	 * @return int
162
	 */
163
	public function total(): int
164
	{
165
		return $this->total;
166
	}
167
168
	/**
169
	 * @param bool $withBaseUrl
170
	 * @return array
171
	 */
172
	public function links(bool $withBaseUrl = false): array
173
	{
174
		$links = [];
175
		for ($i = 1; $i <= $this->lastPageNumber(); $i++) {
176
			$links[] = $this->getPageLink($i, $withBaseUrl);
177
		}
178
179
		return $links;
180
	}
181
182
	/**
183
	 * @param bool $withBaseUrl
184
	 * @return string
185
	 */
186
	protected function getUri(bool $withBaseUrl = false): string
187
	{
188
		$routeUrl = preg_replace('/([?&](page|per_page)=\d+)/', '', route_uri());
189
		$routeUrl = preg_replace('/&/', '?', $routeUrl, 1);
190
		$url = $routeUrl;
191
192
		if ($withBaseUrl) {
193
			$url = $this->baseUrl . $routeUrl;
194
		}
195
196
		$delimiter = strpos($url, '?') ? '&' : '?';
197
		return $url . $delimiter;
198
	}
199
200
	/**
201
	 * @param $pageNumber
202
	 * @param bool $withBaseUrl
203
	 * @return string|null
204
	 */
205
	protected function getPageLink($pageNumber, bool $withBaseUrl = false): ?string
206
	{
207
		if (!empty($pageNumber)){
208
			return $this->getUri($withBaseUrl) . self::PER_PAGE .'=' . $this->perPage . '&'. self::PAGE .'=' . $pageNumber;
209
		}
210
		return null;
211
	}
212
213
	/**
214
	 * @param bool $withBaseUrl
215
	 * @param $pageItemsCount
216
	 * @return string|null
217
	 */
218
	public function getPagination(bool $withBaseUrl = false, $pageItemsCount = null): ?string
219
	{
220
		$totalPages = $this->lastPageNumber();
221
		if ($totalPages <= 1) {
222
			return null;
223
		}
224
225
		if (!is_null($pageItemsCount) && $pageItemsCount < self::MINIMUM_PAGE_ITEMS_COUNT) {
226
			$pageItemsCount = self::MINIMUM_PAGE_ITEMS_COUNT;
227
		}
228
229
		$pagination = '<ul class="'. self::PAGINATION_CLASS .'">';
230
		$currentPage = $this->currentPageNumber();
231
232
		if ($currentPage > 1) {
233
			$pagination .= $this->getPreviousPageItem($this->previousPageLink());
234
		}
235
236
		if ($pageItemsCount) {
237
			$links = $this->links($withBaseUrl);
238
			list($startPage, $endPage) = $this->calculateStartEndPages($currentPage, $totalPages, $pageItemsCount);
239
			$pagination .= $this->addFirstPageLink($startPage);
240
			$pagination .= $this->getItemsLinks($startPage, $endPage, $currentPage, $links);
241
			$pagination .= $this->addLastPageLink($endPage, $totalPages, $links);
242
		}
243
244
		if ($currentPage < $totalPages) {
245
			$pagination .= $this->getNextPageItem($this->nextPageLink());
246
		}
247
248
		$pagination .= '</ul>';
249
250
		return $pagination;
251
	}
252
253
	/**
254
	 * @param string|null $nextPageLink
255
	 * @return string
256
	 */
257
	protected function getNextPageItem(?string $nextPageLink): string
258
	{
259
		$link = '';
260
		if (!empty($nextPageLink)){
261
			$link = '<li><a href="' . $nextPageLink . '">Next &raquo;</a></li>';
262
		}
263
		return $link;
264
	}
265
266
	/**
267
	 * @param string|null $previousPageLink
268
	 * @return string
269
	 */
270
	protected function getPreviousPageItem(?string $previousPageLink): string
271
	{
272
		$link = '';
273
		if (!empty($previousPageLink)){
274
			$link = '<li><a href="' . $previousPageLink . '">&laquo; Previous</a></li>';
275
		}
276
		return $link;
277
	}
278
279
	/**
280
	 * @param $startPage
281
	 * @param $endPage
282
	 * @param $currentPage
283
	 * @param array $links
284
	 * @return string
285
	 */
286
	protected function getItemsLinks($startPage, $endPage, $currentPage, array $links): string
287
	{
288
		$pagination = '';
289
		for ($i = $startPage; $i <= $endPage; $i++) {
290
			$active = $i == $currentPage ? 'class="'. self::PAGINATION_CLASS_ACTIVE .'"' : '';
291
			$pagination .= '<li ' . $active . '><a href="' . $links[$i - 1] . '">' . $i . '</a></li>';
292
		}
293
		return $pagination;
294
	}
295
296
	/**
297
	 * @param $currentPage
298
	 * @param $totalPages
299
	 * @param $pageItemsCount
300
	 * @return array
301
	 */
302
	protected function calculateStartEndPages($currentPage, $totalPages,  $pageItemsCount): array
303
	{
304
		$startPage = max(1, $currentPage - ceil(($pageItemsCount - self::EDGE_PADDING) / 2));
305
		$endPage = min($totalPages, $startPage + $pageItemsCount - self::EDGE_PADDING);
306
307
		return [$startPage, $endPage];
308
	}
309
310
	/**
311
	 * @param $startPage
312
	 * @return string
313
	 */
314
	protected function addFirstPageLink($startPage): string
315
	{
316
		$pagination = '';
317
		if ($startPage > 1) {
318
			$pagination .= '<li><a href="' . $this->firstPageLink() . '">'. self::FIRST_PAGE_NUMBER .'</a></li>';
319
			if ($startPage > 2) {
320
				$pagination .= '<li><span>...</span></li>';
321
			}
322
		}
323
		return $pagination;
324
	}
325
326
	/**
327
	 * @param $endPage
328
	 * @param $totalPages
329
	 * @param $links
330
	 * @return string
331
	 */
332
	protected function addLastPageLink($endPage, $totalPages, $links): string
333
	{
334
		$pagination = '';
335
		if ($endPage < $totalPages) {
336
			if ($endPage < $totalPages - 1) {
337
				$pagination .= '<li><span>...</span></li>';
338
			}
339
			$pagination .= '<li><a href="' . $links[$totalPages - 1] . '">' . $totalPages . '</a></li>';
340
		}
341
		return $pagination;
342
	}
343
}