Completed
Branch develop (f7dc53)
by Anton
05:49
created

Paginator::nextPage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 8
rs 9.4286
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
namespace Spiral\Pagination;
9
10
use Psr\Http\Message\ServerRequestInterface;
11
use Psr\Http\Message\UriInterface;
12
13
/**
14
 * Default paginator implementation, uses active server request Uri to generate page urls.
15
 */
16
class Paginator implements PredictableInterface, \Countable
17
{
18
    /**
19
     * Default limit value.
20
     */
21
    const DEFAULT_LIMIT = 25;
22
23
    /**
24
     * Default page parameter.
25
     */
26
    const DEFAULT_PARAMETER = 'page';
27
28
    /**
29
     * The query array will be connected to every page URL generated by paginator.
30
     *
31
     * @var array
32
     */
33
    private $queryData = [];
34
35
    /**
36
     * @var string
37
     */
38
    private $pageParameter = 'page';
39
40
    /**
41
     * @var int
42
     */
43
    private $pageNumber = 1;
44
45
    /**
46
     * @var int
47
     */
48
    private $countPages = 1;
49
50
    /**
51
     * @var int
52
     */
53
    private $limit = self::DEFAULT_LIMIT;
54
55
    /**
56
     * @var int
57
     */
58
    private $count = 0;
59
60
    /**
61
     * @invisible
62
     * @var ServerRequestInterface
63
     */
64
    private $request = null;
65
66
    /**
67
     * @var UriInterface
68
     */
69
    private $uri = null;
70
71
    /**
72
     * {@inheritdoc}
73
     */
74
    public function __construct(
75
        ServerRequestInterface $request,
76
        $pageParameter = self::DEFAULT_PARAMETER
77
    ) {
78
        $this->setRequest($request);
79
        $this->setParameter($pageParameter);
80
    }
81
82
    /**
83
     * @param ServerRequestInterface $request
84
     */
85
    public function setRequest(ServerRequestInterface $request)
86
    {
87
        $this->request = $request;
88
        $this->uri = $request->getUri();
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function setUri(UriInterface $uri)
95
    {
96
        $this->uri = $uri;
97
98
        return $this;
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104
    public function getUri()
105
    {
106
        return $this->uri;
107
    }
108
109
    /**
110
     * Specify the query (as array) which will be attached to every generated page URL.
111
     *
112
     * @param array $query
113
     * @param bool  $replace Replace existed query data entirely.
114
     */
115
    public function setQuery(array $query, $replace = false)
116
    {
117
        $this->queryData = $replace ? $query : $query + $this->queryData;
118
    }
119
120
    /**
121
     * @return array
122
     */
123
    public function getQuery()
124
    {
125
        return $this->queryData;
126
    }
127
128
    /**
129
     * Update page parameter name from request query. Page number should be fetched from queryParams
130
     * of provided request instance.
131
     *
132
     * @param string $pageParameter
133
     * @return self
134
     */
135
    public function setParameter($pageParameter)
136
    {
137
        $this->pageParameter = $pageParameter;
138
        $queryParams = $this->request->getQueryParams();
139
        if (isset($queryParams[$this->pageParameter])) {
140
            $this->setPage($queryParams[$this->pageParameter]);
141
        }
142
143
        return $this;
144
    }
145
146
    /**
147
     * Get page query parameter name.
148
     *
149
     * @return string
150
     */
151
    public function getParameter()
152
    {
153
        return $this->pageParameter;
154
    }
155
156
    /**
157
     * {@inheritdoc}
158
     */
159 View Code Duplication
    public function setCount($count)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
160
    {
161
        $this->count = abs(intval($count));
0 ignored issues
show
Documentation Bug introduced by
It seems like abs(intval($count)) can also be of type double. However, the property $count is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
162
        if ($this->count > 0) {
163
            $this->countPages = ceil($this->count / $this->limit);
0 ignored issues
show
Documentation Bug introduced by
The property $countPages was declared of type integer, but ceil($this->count / $this->limit) is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
164
        } else {
165
            $this->countPages = 1;
166
        }
167
168
        return $this;
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174
    public function count()
175
    {
176
        return $this->count;
177
    }
178
179
    /**
180
     * Set pagination limit.
181
     *
182
     * @param int $limit
183
     * @return $this
184
     */
185 View Code Duplication
    public function setLimit($limit)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
186
    {
187
        $this->limit = abs(intval($limit));
0 ignored issues
show
Documentation Bug introduced by
It seems like abs(intval($limit)) can also be of type double. However, the property $limit is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
188
        if ($this->count > 0) {
189
            $this->countPages = ceil($this->count / $this->limit);
0 ignored issues
show
Documentation Bug introduced by
The property $countPages was declared of type integer, but ceil($this->count / $this->limit) is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
190
        } else {
191
            $this->countPages = 1;
192
        }
193
194
        return $this;
195
    }
196
197
    /**
198
     * Get pagination limit (items per page).
199
     *
200
     * @return int
201
     */
202
    public function getLimit()
203
    {
204
        return $this->limit;
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     */
210
    public function setPage($number)
211
    {
212
        $this->pageNumber = abs(intval($number));
0 ignored issues
show
Documentation Bug introduced by
It seems like abs(intval($number)) can also be of type double. However, the property $pageNumber is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
213
214
        //Real page number
215
        return $this->getPage();
216
    }
217
218
    /**
219
     * {@inheritdoc}
220
     */
221
    public function getPage()
222
    {
223
        if ($this->pageNumber < 1) {
224
            return 1;
225
        }
226
227
        if ($this->pageNumber > $this->countPages) {
228
            return $this->countPages;
229
        }
230
231
        return $this->pageNumber;
232
    }
233
234
    /**
235
     * Get pagination offset.
236
     *
237
     * @return int
238
     */
239
    public function getOffset()
240
    {
241
        return ($this->getPage() - 1) * $this->limit;
242
    }
243
244
    /**
245
     * The count of pages required to represent all records using a specified limit value.
246
     *
247
     * @return int
248
     */
249
    public function countPages()
250
    {
251
        return $this->countPages;
252
    }
253
254
    /**
255
     * {@inheritdoc}
256
     */
257
    public function countDisplayed()
258
    {
259
        if ($this->getPage() == $this->countPages) {
260
            return $this->count - $this->getOffset();
261
        }
262
263
        return $this->limit;
264
    }
265
266
    /**
267
     * {@inheritdoc}
268
     */
269
    public function isRequired()
270
    {
271
        return ($this->countPages > 1);
272
    }
273
274
    /**
275
     * {@inheritdoc}
276
     */
277
    public function nextPage()
278
    {
279
        if ($this->getPage() != $this->countPages) {
280
            return $this->getPage() + 1;
281
        }
282
283
        return false;
284
    }
285
286
    /**
287
     * {@inheritdoc}
288
     */
289
    public function previousPage()
290
    {
291
        if ($this->getPage() > 1) {
292
            return $this->getPage() - 1;
293
        }
294
295
        return false;
296
    }
297
298
    /**
299
     * {@inheritdoc}
300
     */
301
    public function paginate(PaginableInterface $paginable)
302
    {
303
        $this->setCount($paginable->count());
304
305
        $paginable->offset($this->getOffset());
306
        $paginable->limit($this->getLimit());
307
308
        return $paginable;
309
    }
310
311
    /**
312
     * {@inheritdoc}
313
     */
314
    public function uri($pageNumber)
315
    {
316
        return $this->uri->withQuery(http_build_query(
317
            $this->getQuery() + [$this->pageParameter => $pageNumber]
318
        ));
319
    }
320
}