Completed
Push — 6.0 ( 800870...267f59 )
by yun
03:41 queued 17s
created

Paginator::make()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 6
dl 0
loc 7
ccs 0
cts 4
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: zhangyajun <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
use ArrayAccess;
16
use ArrayIterator;
17
use Closure;
18
use Countable;
19
use DomainException;
20
use IteratorAggregate;
21
use JsonSerializable;
22
use think\paginator\driver\Bootstrap;
23
use Traversable;
24
25
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
26
 * @method array all()
27
 */
5 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
28
abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
29
{
30
    /**
31
     * 是否简洁模式
32
     * @var bool
33
     */
34
    protected $simple = false;
35
36
    /**
37
     * 数据集
38
     * @var Collection
39
     */
40
    protected $items;
41
42
    /**
43
     * 当前页
44
     * @var integer
45
     */
46
    protected $currentPage;
47
48
    /**
49
     * 最后一页
50
     * @var integer
51
     */
52
    protected $lastPage;
53
54
    /**
55
     * 数据总数
56
     * @var integer|null
57
     */
58
    protected $total;
59
60
    /**
61
     * 每页数量
62
     * @var integer
63
     */
64
    protected $listRows;
65
66
    /**
67
     * 是否有下一页
68
     * @var bool
69
     */
70
    protected $hasMore;
71
72
    /**
73
     * 分页配置
74
     * @var array
75
     */
76
    protected $options = [
77
        'var_page' => 'page',
78
        'path'     => '/',
79
        'query'    => [],
80
        'fragment' => '',
81
    ];
82
83
    /**
84
     * 获取当前页码
85
     * @var Closure
86
     */
87
    protected static $currentPageResolver;
88
89
    /**
90
     * 获取当前路径
91
     * @var Closure
92
     */
93
    protected static $currentPathResolver;
94
95
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
96
     * @var Closure
97
     */
98
    protected static $maker;
99
100
    public function __construct($items, int $listRows, int $currentPage = 1, int $total = null, bool $simple = false, array $options = [])
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
101
    {
102
        $this->options = array_merge($this->options, $options);
103
104
        $this->options['path'] = '/' != $this->options['path'] ? rtrim($this->options['path'], '/') : $this->options['path'];
105
106
        $this->simple   = $simple;
107
        $this->listRows = $listRows;
108
109
        if (!$items instanceof Collection) {
110
            $items = Collection::make($items);
111
        }
112
113
        if ($simple) {
114
            $this->currentPage = $this->setCurrentPage($currentPage);
115
            $this->hasMore     = count($items) > ($this->listRows);
116
            $items             = $items->slice(0, $this->listRows);
117
        } else {
118
            $this->total       = $total;
119
            $this->lastPage    = (int) ceil($total / $listRows);
120
            $this->currentPage = $this->setCurrentPage($currentPage);
121
            $this->hasMore     = $this->currentPage < $this->lastPage;
122
        }
123
        $this->items = $items;
124
    }
125
126
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
127
     * @access public
128
     * @param mixed $items
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
129
     * @param int   $listRows
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
130
     * @param int   $currentPage
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
131
     * @param int   $total
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
132
     * @param bool  $simple
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
133
     * @param array $options
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
134
     * @return Paginator
135
     */
136
    public static function make($items, int $listRows, int $currentPage = 1, int $total = null, bool $simple = false, array $options = [])
137
    {
138
        if (isset(static::$maker)) {
139
            return call_user_func(static::$maker, $items, $listRows, $currentPage, $total, $simple, $options);
140
        }
141
142
        return new Bootstrap($items, $listRows, $currentPage, $total, $simple, $options);
143
    }
144
145
    public static function maker(Closure $resolver)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function maker()
Loading history...
146
    {
147
        static::$maker = $resolver;
148
    }
149
150
    protected function setCurrentPage(int $currentPage): int
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function setCurrentPage()
Loading history...
151
    {
152
        if (!$this->simple && $currentPage > $this->lastPage) {
153
            return $this->lastPage > 0 ? $this->lastPage : 1;
154
        }
155
156
        return $currentPage;
157
    }
158
159
    /**
160
     * 获取页码对应的链接
161
     *
162
     * @access protected
163
     * @param int $page
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
164
     * @return string
165
     */
166
    protected function url(int $page): string
167
    {
168
        if ($page <= 0) {
169
            $page = 1;
170
        }
171
172
        if (strpos($this->options['path'], '[PAGE]') === false) {
173
            $parameters = [$this->options['var_page'] => $page];
174
            $path       = $this->options['path'];
175
        } else {
176
            $parameters = [];
177
            $path       = str_replace('[PAGE]', $page, $this->options['path']);
178
        }
179
180
        if (count($this->options['query']) > 0) {
181
            $parameters = array_merge($this->options['query'], $parameters);
182
        }
183
184
        $url = $path;
185
        if (!empty($parameters)) {
186
            $url .= '?' . http_build_query($parameters, '', '&');
187
        }
188
189
        return $url . $this->buildFragment();
190
    }
191
192
    /**
193
     * 自动获取当前页码
194
     * @access public
195
     * @param string $varPage
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
196
     * @param int    $default
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
197
     * @return int
198
     */
199
    public static function getCurrentPage(string $varPage = 'page', int $default = 1): int
200
    {
201
        if (isset(static::$currentPageResolver)) {
202
            return call_user_func(static::$currentPageResolver, $varPage);
203
        }
204
205
        return $default;
206
    }
207
208
    /**
209
     * 设置获取当前页码闭包
210
     * @param Closure $resolver
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
211
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
212
    public static function currentPageResolver(Closure $resolver)
213
    {
214
        static::$currentPageResolver = $resolver;
215
    }
216
217
    /**
218
     * 自动获取当前的path
219
     * @access public
220
     * @param string $default
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
221
     * @return string
222
     */
223
    public static function getCurrentPath($default = '/'): string
224
    {
225
        if (isset(static::$currentPathResolver)) {
226
            return call_user_func(static::$currentPathResolver);
227
        }
228
229
        return $default;
230
    }
231
232
    /**
233
     * 设置获取当前路径闭包
234
     * @param Closure $resolver
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
235
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
236
    public static function currentPathResolver(Closure $resolver)
237
    {
238
        static::$currentPathResolver = $resolver;
239
    }
240
241
    public function total(): int
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function total()
Loading history...
242
    {
243
        if ($this->simple) {
244
            throw new DomainException('not support total');
245
        }
246
247
        return $this->total;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->total could return the type null which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
248
    }
249
250
    public function listRows(): int
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function listRows()
Loading history...
251
    {
252
        return $this->listRows;
253
    }
254
255
    public function currentPage(): int
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function currentPage()
Loading history...
256
    {
257
        return $this->currentPage;
258
    }
259
260
    public function lastPage(): int
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function lastPage()
Loading history...
261
    {
262
        if ($this->simple) {
263
            throw new DomainException('not support last');
264
        }
265
266
        return $this->lastPage;
267
    }
268
269
    /**
270
     * 数据是否足够分页
271
     * @access public
272
     * @return bool
273
     */
274
    public function hasPages(): bool
275
    {
276
        return !(1 == $this->currentPage && !$this->hasMore);
277
    }
278
279
    /**
280
     * 创建一组分页链接
281
     *
282
     * @access public
283
     * @param int $start
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
284
     * @param int $end
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
285
     * @return array
286
     */
287
    public function getUrlRange(int $start, int $end): array
288
    {
289
        $urls = [];
290
291
        for ($page = $start; $page <= $end; $page++) {
292
            $urls[$page] = $this->url($page);
293
        }
294
295
        return $urls;
296
    }
297
298
    /**
299
     * 设置URL锚点
300
     *
301
     * @access public
302
     * @param string|null $fragment
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
303
     * @return $this
304
     */
305
    public function fragment(string $fragment = null)
306
    {
307
        $this->options['fragment'] = $fragment;
308
309
        return $this;
310
    }
311
312
    /**
313
     * 添加URL参数
314
     *
315
     * @access public
316
     * @param array $append
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
317
     * @return $this
318
     */
319
    public function appends(array $append)
320
    {
321
        foreach ($append as $k => $v) {
322
            if ($k !== $this->options['var_page']) {
323
                $this->options['query'][$k] = $v;
324
            }
325
        }
326
327
        return $this;
328
    }
329
330
    /**
331
     * 构造锚点字符串
332
     *
333
     * @access public
334
     * @return string
335
     */
336
    protected function buildFragment(): string
337
    {
338
        return $this->options['fragment'] ? '#' . $this->options['fragment'] : '';
339
    }
340
341
    /**
342
     * 渲染分页html
343
     * @access public
344
     * @return mixed
345
     */
346
    abstract public function render();
347
348
    public function items()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function items()
Loading history...
349
    {
350
        return $this->items->all();
351
    }
352
353
    public function getCollection()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getCollection()
Loading history...
354
    {
355
        return $this->items;
356
    }
357
358
    public function isEmpty(): bool
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function isEmpty()
Loading history...
359
    {
360
        return $this->items->isEmpty();
361
    }
362
363
    /**
364
     * 给每个元素执行个回调
365
     *
366
     * @access public
367
     * @param callable $callback
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
368
     * @return $this
369
     */
370
    public function each(callable $callback)
371
    {
372
        foreach ($this->items as $key => $item) {
373
            $result = $callback($item, $key);
374
375
            if (false === $result) {
376
                break;
377
            } elseif (!is_object($item)) {
378
                $this->items[$key] = $result;
379
            }
380
        }
381
382
        return $this;
383
    }
384
385
    /**
386
     * Retrieve an external iterator
387
     * @access public
388
     * @return Traversable An instance of an object implementing <b>Iterator</b> or
389
     * <b>Traversable</b>
390
     */
391
    public function getIterator()
392
    {
393
        return new ArrayIterator($this->items->all());
394
    }
395
396
    /**
397
     * Whether a offset exists
398
     * @access public
399
     * @param mixed $offset
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
400
     * @return bool
401
     */
402
    public function offsetExists($offset)
403
    {
404
        return $this->items->offsetExists($offset);
405
    }
406
407
    /**
408
     * Offset to retrieve
409
     * @access public
410
     * @param mixed $offset
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
411
     * @return mixed
412
     */
413
    public function offsetGet($offset)
414
    {
415
        return $this->items->offsetGet($offset);
416
    }
417
418
    /**
419
     * Offset to set
420
     * @access public
421
     * @param mixed $offset
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
422
     * @param mixed $value
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
423
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
424
    public function offsetSet($offset, $value)
425
    {
426
        $this->items->offsetSet($offset, $value);
427
    }
428
429
    /**
430
     * Offset to unset
431
     * @access public
432
     * @param mixed $offset
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
433
     * @return void
434
     * @since  5.0.0
435
     */
436
    public function offsetUnset($offset)
437
    {
438
        $this->items->offsetUnset($offset);
439
    }
440
441
    /**
442
     * Count elements of an object
443
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
444
    public function count(): int
445
    {
446
        return $this->items->count();
447
    }
448
449
    public function __toString()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __toString()
Loading history...
450
    {
451
        return (string) $this->render();
452
    }
453
454
    public function toArray(): array
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function toArray()
Loading history...
455
    {
456
        try {
457
            $total = $this->total();
458
        } catch (DomainException $e) {
459
            $total = null;
460
        }
461
462
        return [
463
            'total'        => $total,
464
            'per_page'     => $this->listRows(),
465
            'current_page' => $this->currentPage(),
466
            'last_page'    => $this->lastPage,
467
            'data'         => $this->items->toArray(),
468
        ];
469
    }
470
471
    /**
472
     * Specify data which should be serialized to JSON
473
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
474
    public function jsonSerialize()
475
    {
476
        return $this->toArray();
477
    }
478
479
    public function __call($name, $arguments)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __call()
Loading history...
480
    {
481
        $collection = $this->getCollection();
482
483
        $result = call_user_func_array([$collection, $name], $arguments);
484
485
        if ($result === $collection) {
486
            return $this;
487
        }
488
489
        return $result;
490
    }
491
492
}
493