PaginatorTrait::getNextPageItem()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 9
rs 10
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 3.0.0
13
 */
14
15
namespace Quantum\Paginator\Traits;
16
17
use Quantum\Paginator\Enums\Pagination;
18
19
/**
20
 * Trait PaginatorTrait
21
 * @package Quantum\Paginator
22
 */
23
trait PaginatorTrait
24
{
25
    /**
26
     * @var string
27
     */
28
    protected $baseUrl;
29
30
    /**
31
     * @var int
32
     */
33
    protected $total;
34
35
    /**
36
     * @var int
37
     */
38
    protected $perPage;
39
40
    /**
41
     * @var int
42
     */
43
    protected $page;
44
45
    /**
46
     * @param int $perPage
47
     * @param int $page
48
     */
49
    protected function initialize(int $perPage, int $page = 1): void
50
    {
51
        $this->baseUrl = base_url();
52
        $this->perPage = $perPage;
53
        $this->page = $page;
54
    }
55
56
    /**
57
     * Get total number of items
58
     * @return int
59
     */
60
    public function total(): int
61
    {
62
        return $this->total;
63
    }
64
65
    /**
66
     * Get current page number
67
     * @return int
68
     */
69
    public function currentPageNumber(): int
70
    {
71
        return $this->page;
72
    }
73
74
    /**
75
     * Get previous page number
76
     * @return int|null
77
     */
78
    public function previousPageNumber(): ?int
79
    {
80
        if ($this->page > 1) {
81
            return $this->page - 1;
82
        }
83
84
        if ($this->page == 1) {
85
            return $this->page;
86
        }
87
88
        return null;
89
    }
90
91
    /**
92
     * Get next page number
93
     * @return int|null
94
     */
95
    public function nextPageNumber(): ?int
96
    {
97
        if ($this->page < $this->lastPageNumber()) {
98
            return $this->page + 1;
99
        }
100
101
        if ($this->page == $this->lastPageNumber()) {
102
            return $this->page;
103
        }
104
105
        return null;
106
    }
107
108
    /**
109
     * Get last page number
110
     * @return int
111
     */
112
    public function lastPageNumber(): int
113
    {
114
        return (int)ceil($this->total() / $this->perPage);
115
    }
116
117
    /**
118
     * Get current page link
119
     * @param bool $withBaseUrl
120
     * @return string|null
121
     */
122
    public function currentPageLink(bool $withBaseUrl = false): ?string
123
    {
124
        return $this->getPageLink($this->page, $withBaseUrl);
125
    }
126
127
    /**
128
     * Get first page link
129
     * @param bool $withBaseUrl
130
     * @return string|null
131
     */
132
    public function firstPageLink(bool $withBaseUrl = false): ?string
133
    {
134
        return $this->getPageLink(Pagination::FIRST_PAGE_NUMBER, $withBaseUrl);
135
    }
136
137
    /**
138
     * Get previous page link
139
     * @param bool $withBaseUrl
140
     * @return string|null
141
     */
142
    public function previousPageLink(bool $withBaseUrl = false): ?string
143
    {
144
        return $this->getPageLink($this->previousPageNumber(), $withBaseUrl);
145
    }
146
147
    /**
148
     * Get next page link
149
     * @param bool $withBaseUrl
150
     * @return string|null
151
     */
152
    public function nextPageLink(bool $withBaseUrl = false): ?string
153
    {
154
        return $this->getPageLink($this->nextPageNumber(), $withBaseUrl);
155
    }
156
157
    /**
158
     * Get last page link
159
     * @param bool $withBaseUrl
160
     * @return string|null
161
     */
162
    public function lastPageLink(bool $withBaseUrl = false): ?string
163
    {
164
        return $this->getPageLink($this->lastPageNumber(), $withBaseUrl);
165
    }
166
167
    /**
168
     * Get items per page
169
     * @return int
170
     */
171
    public function perPage(): int
172
    {
173
        return $this->perPage;
174
    }
175
176
    /**
177
     * Get all page links
178
     * @param bool $withBaseUrl
179
     * @return array
180
     */
181
    public function links(bool $withBaseUrl = false): array
182
    {
183
        $links = [];
184
185
        for ($i = 1; $i <= $this->lastPageNumber(); $i++) {
186
            $links[] = $this->getPageLink($i, $withBaseUrl);
187
        }
188
189
        return $links;
190
    }
191
192
    /**
193
     * Get pagination HTML
194
     * @param bool $withBaseUrl
195
     * @param int|null $pageItemsCount
196
     * @return string|null
197
     */
198
    public function getPagination(bool $withBaseUrl = false, ?int $pageItemsCount = null): ?string
199
    {
200
        $totalPages = $this->lastPageNumber();
201
        $currentPage = $this->currentPageNumber();
202
203
        if ($totalPages <= 1) {
204
            return null;
205
        }
206
207
        $pageItemsCount = max(Pagination::MINIMUM_PAGE_ITEMS_COUNT, $pageItemsCount ?? Pagination::MINIMUM_PAGE_ITEMS_COUNT);
208
209
        $pagination = ['<ul class="' . Pagination::PAGINATION_CLASS . '">'];
210
211
        if ($currentPage > 1) {
212
            $pagination[] = $this->getPreviousPageItem($this->previousPageLink());
213
        }
214
215
        if ($pageItemsCount) {
216
            $links = $this->links($withBaseUrl);
217
218
            [$startPage, $endPage] = $this->calculateStartEndPages($currentPage, $totalPages, $pageItemsCount);
219
220
            $pagination[] = $this->addFirstPageLink($startPage);
221
            $pagination[] = $this->getItemsLinks($startPage, $endPage, $currentPage, $links);
222
            $pagination[] = $this->addLastPageLink($endPage, $totalPages, $links);
223
        }
224
225
        if ($currentPage < $totalPages) {
226
            $pagination[] = $this->getNextPageItem($this->nextPageLink());
227
        }
228
229
        $pagination[] = '</ul>';
230
231
        return implode('', $pagination);
232
    }
233
234
    /**
235
     * Get the URI for pagination
236
     * @param bool $withBaseUrl
237
     * @return string
238
     */
239
    protected function getUri(bool $withBaseUrl = false): string
240
    {
241
        $routeUrl = preg_replace('/([?&](page|per_page)=\d+)/', '', route_uri());
242
        $routeUrl = preg_replace('/&/', '?', $routeUrl, 1);
243
        $url = $routeUrl;
244
245
        if ($withBaseUrl) {
246
            $url = $this->baseUrl . $routeUrl;
247
        }
248
249
        $delimiter = strpos($url, '?') ? '&' : '?';
250
251
        return $url . $delimiter;
252
    }
253
254
    /**
255
     * Get page link
256
     * @param int|null $pageNumber
257
     * @param bool $withBaseUrl
258
     * @return string|null
259
     */
260
    protected function getPageLink(?int $pageNumber, bool $withBaseUrl = false): ?string
261
    {
262
        if ($pageNumber !== null && $pageNumber !== 0) {
263
            return $this->getUri($withBaseUrl) . Pagination::PER_PAGE . '=' . $this->perPage . '&' . Pagination::PAGE . '=' . $pageNumber;
264
        }
265
266
        return null;
267
    }
268
269
    /**
270
     * Get next page item HTML
271
     * @param string|null $nextPageLink
272
     * @return string
273
     */
274
    protected function getNextPageItem(?string $nextPageLink): string
275
    {
276
        $link = '';
277
278
        if (!in_array($nextPageLink, [null, '', '0'], true)) {
279
            $link = '<li><a href="' . $nextPageLink . '">' . t('common.pagination.next') . '</a></li>';
280
        }
281
282
        return $link;
283
    }
284
285
    /**
286
     * Get previous page item HTML
287
     * @param string|null $previousPageLink
288
     * @return string
289
     */
290
    protected function getPreviousPageItem(?string $previousPageLink): string
291
    {
292
        $link = '';
293
294
        if (!in_array($previousPageLink, [null, '', '0'], true)) {
295
            $link = '<li><a href="' . $previousPageLink . '">' . t('common.pagination.prev') . '</a></li>';
296
        }
297
298
        return $link;
299
    }
300
301
    /**
302
     * Get items links HTML
303
     * @param int $startPage
304
     * @param int $endPage
305
     * @param int $currentPage
306
     * @param array $links
307
     * @return string
308
     */
309
    protected function getItemsLinks(int $startPage, int $endPage, int $currentPage, array $links): string
310
    {
311
        $pagination = [];
312
313
        for ($i = $startPage; $i <= $endPage; $i++) {
314
            $active = $i === $currentPage ? 'class="' . Pagination::PAGINATION_CLASS_ACTIVE . '"' : '';
315
            $pagination .= '<li ' . $active . '><a href="' . $links[$i - 1] . '">' . $i . '</a></li>';
316
        }
317
318
        return $pagination;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $pagination could return the type array which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
319
    }
320
321
    /**
322
     * Calculate start and end pages
323
     * @param int $currentPage
324
     * @param int $totalPages
325
     * @param int $pageItemsCount
326
     * @return array
327
     */
328
    protected function calculateStartEndPages(int $currentPage, int $totalPages, int $pageItemsCount): array
329
    {
330
        $startPage = max(1, $currentPage - ceil(($pageItemsCount - Pagination::EDGE_PADDING) / 2));
331
        $endPage = min($totalPages, $startPage + $pageItemsCount - Pagination::EDGE_PADDING);
332
333
        return [$startPage, $endPage];
334
    }
335
336
    /**
337
     * Add first page link HTML
338
     * @param int $startPage
339
     * @return string
340
     */
341
    protected function addFirstPageLink(int $startPage): string
342
    {
343
        $pagination = '';
344
345
        if ($startPage > 1) {
346
            $pagination .= '<li><a href="' . $this->firstPageLink() . '">' . Pagination::FIRST_PAGE_NUMBER . '</a></li>';
347
            if ($startPage > 2) {
348
                $pagination .= '<li><span>...</span></li>';
349
            }
350
        }
351
352
        return $pagination;
353
    }
354
355
    /**
356
     * Add last page link HTML
357
     * @param int $endPage
358
     * @param int $totalPages
359
     * @param array $links
360
     * @return string
361
     */
362
    protected function addLastPageLink(int $endPage, int $totalPages, array $links): string
363
    {
364
        $pagination = '';
365
366
        if ($endPage < $totalPages) {
367
            if ($endPage < $totalPages - 1) {
368
                $pagination .= '<li><span>...</span></li>';
369
            }
370
            $pagination .= '<li><a href="' . $links[$totalPages - 1] . '">' . $totalPages . '</a></li>';
371
        }
372
373
        return $pagination;
374
    }
375
}
376