Completed
Push — master ( 654a3a...0d91ac )
by Arman
20s queued 16s
created

PaginatorTrait   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 352
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 87
c 1
b 0
f 0
dl 0
loc 352
rs 9.0399
wmc 42

22 Methods

Rating   Name   Duplication   Size   Complexity  
A currentPageNumber() 0 3 1
A lastPageNumber() 0 3 1
A previousPageNumber() 0 11 3
A links() 0 9 2
A addLastPageLink() 0 12 3
A getItemsLinks() 0 10 3
A getPageLink() 0 7 2
A getPreviousPageItem() 0 9 2
A addFirstPageLink() 0 12 3
A calculateStartEndPages() 0 6 1
A getPagination() 0 34 5
A total() 0 3 1
A nextPageLink() 0 3 1
A getUri() 0 13 3
A getNextPageItem() 0 9 2
A initialize() 0 5 1
A currentPageLink() 0 3 1
A perPage() 0 3 1
A firstPageLink() 0 3 1
A nextPageNumber() 0 11 3
A previousPageLink() 0 3 1
A lastPageLink() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like PaginatorTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PaginatorTrait, and based on these observations, apply Extract Interface, too.

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