PagerView::getRange()   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 12
c 1
b 0
f 0
dl 0
loc 19
ccs 13
cts 13
cp 1
rs 9.8666
cc 4
nc 6
nop 2
crap 4
1
<?php
2
3
namespace Povs\ListerBundle\View;
4
5
use Povs\ListerBundle\Service\Paginator;
6
7
/**
8
 * @author Povilas Margaiatis <[email protected]>
9
 */
10
class PagerView
11
{
12
    /**
13
     * @var int
14
     */
15
    private $currentPage;
16
17
    /**
18
     * @var int|null is set when data is fetched
19
     */
20
    private $total;
21
22
    /**
23
     * @var int
24
     */
25
    private $length;
26
27
    /**
28
     * @var Paginator
29
     */
30
    private $paginator;
31
32
    /**
33
     * @var array|null is set when data is fetched
34
     */
35
    private $data;
36
37
    /**
38
     * PagerView constructor.
39
     *
40
     * @param Paginator $paginator
41
     * @param int       $currentPage
42
     * @param int       $perPage
43
     */
44 28
    public function __construct(Paginator $paginator, int $currentPage, int $perPage)
45
    {
46 28
        $this->paginator = $paginator;
47 28
        $this->currentPage = $currentPage;
48 28
        $this->length = $perPage;
49
    }
50
51
    /**
52
     * @return int
53
     */
54 4
    public function getCurrentPage(): int
55
    {
56 4
        return $this->currentPage;
57
    }
58
59
    /**
60
     * @return int
61
     */
62 21
    public function getTotal(): int
63
    {
64 21
        if (null === $this->total) {
65 21
            $this->setData($this->currentPage);
66
        }
67
68 21
        return $this->total;
69
    }
70
71
    /**
72
     * @return int
73
     */
74 2
    public function getLength(): int
75
    {
76 2
        return $this->length;
77
    }
78
79
    /**
80
     * @param int|null $page
81
     *
82
     * @return int
83
     */
84 24
    public function getFirstResult(?int $page = null): int
85
    {
86 24
        return ($page ?? $this->currentPage) * $this->length - ($this->length - 1);
87
    }
88
89
    /**
90
     * @param int|null $page
91
     *
92
     * @return int
93
     */
94 3
    public function getLastResult(?int $page = null): int
95
    {
96 3
        $lastResult = ($page ?? $this->currentPage) * $this->length;
97 3
        $total = $this->getTotal();
98
99 3
        return $lastResult > $total ? $total : $lastResult;
100
    }
101
102
    /**
103
     * @return int
104
     */
105 7
    public function getLastPage(): int
106
    {
107 7
        return (int) ceil($this->getTotal() / $this->length);
108
    }
109
110
    /**
111
     * @return int|null
112
     */
113 2
    public function getPrevPage(): ?int
114
    {
115 2
        $prevPage = $this->currentPage - 1;
116
117 2
        if (!$this->validatePage($prevPage)) {
118 1
            return null;
119
        }
120
121 1
        return $prevPage;
122
    }
123
124
    /**
125
     * @return int|null
126
     */
127 4
    public function getNextPage(): ?int
128
    {
129 4
        $nextPage = $this->currentPage + 1;
130
131 4
        if (!$this->validatePage($nextPage)) {
132 2
            return null;
133
        }
134
135 2
        return $nextPage;
136
    }
137
138
    /**
139
     * @param int $page
140
     *
141
     * @return bool if valid
142
     */
143 10
    public function validatePage(int $page): bool
144
    {
145 10
        return !($page < 1 || ($page !== 1 && ($page * $this->length - ($this->length - 1) > $this->getTotal())));
146
    }
147
148
    /**
149
     * @param int $page
150
     *
151
     * @return bool
152
     */
153 3
    public function iteratePage(int $page): bool
154
    {
155 3
        if (!$this->validatePage($page)) {
156 1
            return false;
157
        }
158
159 2
        $this->setData($page);
160 2
        $this->currentPage = $page;
161
162 2
        return true;
163
    }
164
165
    /**
166
     * Sets ListView to the next page
167
     *
168
     * @return bool
169
     */
170 2
    public function iterateNextPage(): bool
171
    {
172 2
        if ($nextPage = $this->getNextPage()) {
173 1
            return $this->iteratePage($nextPage);
174
        }
175
176 1
        return false;
177
    }
178
179
    /**
180
     * @return array
181
     */
182 3
    public function getData(): array
183
    {
184 3
        if (!$this->data) {
185 1
            $this->setData($this->currentPage);
186
        }
187
188 3
        return $this->data;
189
    }
190
191
    /**
192
     * creates pages array for rendering it in front.
193
     *
194
     * @param int $length To determinate pager length. (2*$length+5)
195
     *                    Basically how much pages has to be added around active page
196
     *                    for example length 2 with active page 10 and total pages 20 will be rendered like this:
197
     *                    1 ... 8 9 10 11 12 ... 20
198
     *                    With length 1:
199
     *                    1 ... 9 10 11 ... 201
200
     *
201
     * @return array = [
202
     *      'page' => int|null     if null - skip mark should be added (like "...")
203
     *      'active' => true|false whether this page is equal to current page
204
     * ][]
205
     */
206 7
    public function getPages(int $length = 1): array
207
    {
208 7
        if ($this->getTotal() === 0) {
209 1
            return [];
210
        }
211
212 6
        $pagerLength = 2 * $length + 5;
213 6
        $pages = [];
214 6
        $lastPage = $this->getLastPage();
215
216 6
        if ($pagerLength > $lastPage) {
217 1
            $pagerLength = $lastPage;
218
        }
219
220 6
        $range = $this->getRange($pagerLength, $lastPage);
221
222 6
        if ($range[0] !== 1) {
223 4
            $range[0] = 1;
224 4
            $range[1] = null;
225
        }
226
227 6
        if ($range[$pagerLength - 1] !== $lastPage) {
228 3
            $range[$pagerLength - 1] = $lastPage;
229 3
            $range[$pagerLength - 2] = null;
230
        }
231
232 6
        foreach ($range as $item) {
233 6
            $pages[] = [
234 6
                'page' => $item,
235 6
                'active' => $item === $this->currentPage
236 6
            ];
237
        }
238
239 6
        return $pages;
240
    }
241
242
    /**
243
     * Sets data for provided page number
244
     *
245
     * @param int $page
246
     */
247 22
    private function setData(int $page): void
248
    {
249 22
        $firstResult = $this->getFirstResult($page);
250 22
        $this->total = $this->paginator->getCount();
251 22
        $this->data = $this->paginator->getData($firstResult - 1, $this->length);
252
    }
253
254
    /**
255
     * @param int $pagerLength
256
     * @param int $lastPage
257
     *
258
     * @return array
259
     */
260 6
    private function getRange(int $pagerLength, int $lastPage): array
261
    {
262 6
        $lng = (int) floor($pagerLength / 2);
263 6
        $from = $this->currentPage - $lng;
264 6
        $to = $this->currentPage + $lng;
265
266 6
        if ($from < 1) {
267 1
            $diff = 1 - $from;
268 1
            $to += $diff;
269 1
            $from = 1;
270
        }
271
272 6
        if ($to > $lastPage) {
273 2
            $diff = $to - $lastPage;
274 2
            $to = $lastPage;
275 2
            $from = $from - $diff < 1 ? 1 : $from - $diff;
276
        }
277
278 6
        return range($from, $to);
279
    }
280
}
281