Passed
Branch master (86f473)
by Povilas
02:34
created

PagerView::getPages()   B

Complexity

Conditions 6
Paths 17

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 35
ccs 20
cts 20
cp 1
rs 8.7377
c 0
b 0
f 0
cc 6
nc 17
nop 1
crap 6
1
<?php
2
namespace Povs\ListerBundle\View;
3
4
use Povs\ListerBundle\Service\Paginator;
5
6
/**
7
 * @author Povilas Margaiatis <[email protected]>
8
 */
9
class PagerView
10
{
11
    /**
12
     * @var int
13
     */
14
    private $currentPage;
15
16
    /**
17
     * @var int|null is set when data is fetched
18
     */
19
    private $total;
20
21
    /**
22
     * @var int
23
     */
24
    private $length;
25
26
    /**
27
     * @var Paginator
28
     */
29
    private $paginator;
30
31
    /**
32
     * @var array|null is set when data is fetched
33
     */
34
    private $data;
35
36
    /**
37
     * PagerView constructor.
38
     *
39
     * @param Paginator $paginator
40
     * @param int       $currentPage
41
     * @param int       $perPage
42
     */
43 28
    public function __construct(Paginator $paginator, int $currentPage, int $perPage)
44
    {
45 28
        $this->paginator = $paginator;
46 28
        $this->currentPage = $currentPage;
47 28
        $this->length = $perPage;
48 28
    }
49
50
    /**
51
     * @return int
52
     */
53 4
    public function getCurrentPage(): int
54
    {
55 4
        return $this->currentPage;
56
    }
57
58
    /**
59
     * @return int
60
     */
61 21
    public function getTotal(): int
62
    {
63 21
        if (!$this->total) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->total of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
64 21
            $this->setData($this->currentPage);
65
        }
66
67 21
        return $this->total;
68
    }
69
70
    /**
71
     * @return int
72
     */
73 2
    public function getLength(): int
74
    {
75 2
        return $this->length;
76
    }
77
78
    /**
79
     * @param int|null $page
80
     *
81
     * @return int
82
     */
83 24
    public function getFirstResult(?int $page = null): int
84
    {
85 24
        return ($page ?? $this->currentPage) * $this->length - ($this->length - 1);
86
    }
87
88
    /**
89
     * @param int|null $page
90
     *
91
     * @return int
92
     */
93 3
    public function getLastResult(?int $page = null) : int
94
    {
95 3
        $lastResult = ($page ?? $this->currentPage) * $this->length;
96 3
        $total = $this->getTotal();
97
98 3
        return $lastResult > $total ? $total : $lastResult;
99
    }
100
101
    /**
102
     * @return int
103
     */
104 7
    public function getLastPage(): int
105
    {
106 7
        return ceil($this->getTotal() / $this->length);
107
    }
108
109
    /**
110
     * @return int|null
111
     */
112 2
    public function getPrevPage(): ?int
113
    {
114 2
        $prevPage = $this->currentPage - 1;
115
116 2
        if (!$this->validatePage($prevPage)) {
117 1
            return null;
118
        }
119
120 1
        return $prevPage;
121
    }
122
123
    /**
124
     * @return int|null
125
     */
126 4
    public function getNextPage(): ?int
127
    {
128 4
        $nextPage = $this->currentPage + 1;
129
130 4
        if (!$this->validatePage($nextPage)) {
131 2
            return null;
132
        }
133
134 2
        return $nextPage;
135
    }
136
137
    /**
138
     * @param int $page
139
     *
140
     * @return bool if valid
141
     */
142 10
    public function validatePage(int $page): bool
143
    {
144 10
        return !($page < 1 || ($page !== 1 && ($page * $this->length - ($this->length - 1) > $this->getTotal())));
145
    }
146
147
    /**
148
     * @param int $page
149
     *
150
     * @return bool
151
     */
152 3
    public function iteratePage(int $page): bool
153
    {
154 3
        if (!$this->validatePage($page)) {
155 1
            return false;
156
        }
157
158 2
        $this->setData($page);
159 2
        $this->currentPage = $page;
160
161 2
        return true;
162
    }
163
164
    /**
165
     * Sets ListView to the next page
166
     *
167
     * @return bool
168
     */
169 2
    public function iterateNextPage(): bool
170
    {
171 2
        if ($nextPage = $this->getNextPage()) {
172 1
            return $this->iteratePage($nextPage);
173
        }
174
175 1
        return false;
176
    }
177
178
    /**
179
     * @return array
180
     */
181 3
    public function getData(): array
182
    {
183 3
        if (!$this->data) {
184 1
            $this->setData($this->currentPage);
185
        }
186
187 3
        return $this->data;
188
    }
189
190
    /**
191
     * creates pages array for rendering it in front.
192
     *
193
     * @param int $length To determinate pager length. (2*$length+5)
194
     *                    Basically how much pages has to be added around active page
195
     *                    for example length 2 with active page 10 and total pages 20 will be rendered like this:
196
     *                    1 ... 8 9 10 11 12 ... 20
197
     *                    With length 1:
198
     *                    1 ... 9 10 11 ... 201
199
     *
200
     * @return array = [
201
     *      'page' => int|null     if null - skip mark should be added (like "...")
202
     *      'active' => true|false whether this page is equal to current page
203
     * ][]
204
     */
205 7
    public function getPages(int $length = 1): array
206
    {
207 7
        if ($this->getTotal() === 0) {
208 1
            return [];
209
        }
210
211 6
        $pagerLength = 2 * $length + 5;
212 6
        $pages = [];
213 6
        $lastPage = $this->getLastPage();
214
215 6
        if ($pagerLength > $lastPage) {
216 1
            $pagerLength = $lastPage;
217
        }
218
219 6
        $range = $this->getRange($pagerLength, $lastPage);
220
221 6
        if ($range[0] !== 1) {
222 4
            $range[0] = 1;
223 4
            $range[1] = null;
224
        }
225
226 6
        if ($range[$pagerLength - 1] !== $lastPage) {
227 3
            $range[$pagerLength - 1] = $lastPage;
228 3
            $range[$pagerLength - 2] = null;
229
        }
230
231 6
        foreach ($range as $item) {
232 6
            $pages[] = [
233 6
                'page' => $item,
234 6
                'active' => $item === $this->currentPage
235
            ];
236
        }
237
238 6
        return $pages;
239
    }
240
241
    /**
242
     * Sets data for provided page number
243
     *
244
     * @param int $page
245
     */
246 22
    private function setData(int $page): void
247
    {
248 22
        $firstResult = $this->getFirstResult($page);
249 22
        $this->total = $this->paginator->getCount();
250 22
        $this->data = $this->paginator->getData($firstResult - 1, $this->length);
251 22
    }
252
253
    /**
254
     * @param int $pagerLength
255
     * @param int $lastPage
256
     *
257
     * @return array
258
     */
259 6
    private function getRange(int $pagerLength, int $lastPage): array
260
    {
261 6
        $lng = (int) floor($pagerLength / 2);
262 6
        $from = $this->currentPage - $lng;
263 6
        $to = $this->currentPage + $lng;
264
265 6
        if ($from < 1) {
266 1
            $diff = 1 - $from;
267 1
            $to += $diff;
268 1
            $from = 1;
269
        }
270
271 6
        if ($to > $lastPage) {
272 2
            $diff = $to - $lastPage;
273 2
            $to = $lastPage;
274 2
            $from = $from - $diff < 1 ? 1 : $from - $diff;
275
        }
276
277 6
        return range($from, $to);
278
    }
279
}