Passed
Pull Request — master (#190)
by Arman
04:27
created

PaginatorTrait::total()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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