Passed
Push — 5.2 ( e82ddc...48fd10 )
by liu
02:37
created

Collection::slice()   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
nc 1
nop 3
dl 0
loc 3
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 Countable;
18
use IteratorAggregate;
19
use JsonSerializable;
20
21
class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
1 ignored issue
show
Coding Style introduced by
Missing class doc comment
Loading history...
22
{
23
    /**
24
     * 数据集数据
25
     * @var array
26
     */
27
    protected $items = [];
28
29
    public function __construct($items = [])
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
30
    {
31
        $this->items = $this->convertToArray($items);
32
    }
33
34
    public static function make($items = [])
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
35
    {
36
        return new static($items);
37
    }
38
39
    /**
40
     * 是否为空
41
     * @access public
42
     * @return bool
43
     */
44
    public function isEmpty(): bool
45
    {
46
        return empty($this->items);
47
    }
48
49
    public function toArray(): array
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
50
    {
51
        return array_map(function ($value) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
52
            return ($value instanceof Model || $value instanceof self) ? $value->toArray() : $value;
53
        }, $this->items);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
54
    }
55
56
    public function all(): array
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
57
    {
58
        return $this->items;
59
    }
60
61
    /**
62
     * 合并数组
63
     *
64
     * @access public
65
     * @param  mixed $items 数据
66
     * @return static
67
     */
68
    public function merge($items)
69
    {
70
        return new static(array_merge($this->items, $this->convertToArray($items)));
71
    }
72
73
    /**
74
     * 按指定键整理数据
75
     *
76
     * @access public
77
     * @param  mixed  $items    数据
78
     * @param  string $indexKey 键名
79
     * @return array
80
     */
81
    public function dictionary($items = null, string &$indexKey = null)
82
    {
83
        if ($items instanceof self || $items instanceof Paginator) {
84
            $items = $items->all();
85
        }
86
87
        $items = is_null($items) ? $this->items : $items;
88
89
        if ($items && empty($indexKey)) {
90
            $indexKey = is_array($items[0]) ? 'id' : $items[0]->getPk();
91
        }
92
93
        if (isset($indexKey) && is_string($indexKey)) {
94
            return array_column($items, null, $indexKey);
95
        }
96
97
        return $items;
98
    }
99
100
    /**
101
     * 比较数组,返回差集
102
     *
103
     * @access public
104
     * @param  mixed  $items    数据
105
     * @param  string $indexKey 指定比较的键名
106
     * @return static
107
     */
108
    public function diff($items, string $indexKey = null)
109
    {
110
        if ($this->isEmpty() || is_scalar($this->items[0])) {
111
            return new static(array_diff($this->items, $this->convertToArray($items)));
112
        }
113
114
        $diff       = [];
115
        $dictionary = $this->dictionary($items, $indexKey);
116
117
        if (is_string($indexKey)) {
118
            foreach ($this->items as $item) {
119
                if (!isset($dictionary[$item[$indexKey]])) {
120
                    $diff[] = $item;
121
                }
122
            }
123
        }
124
125
        return new static($diff);
126
    }
127
128
    /**
129
     * 比较数组,返回交集
130
     *
131
     * @access public
132
     * @param  mixed  $items    数据
133
     * @param  string $indexKey 指定比较的键名
134
     * @return static
135
     */
136
    public function intersect($items, string $indexKey = null)
137
    {
138
        if ($this->isEmpty() || is_scalar($this->items[0])) {
139
            return new static(array_diff($this->items, $this->convertToArray($items)));
140
        }
141
142
        $intersect  = [];
143
        $dictionary = $this->dictionary($items, $indexKey);
144
145
        if (is_string($indexKey)) {
146
            foreach ($this->items as $item) {
147
                if (isset($dictionary[$item[$indexKey]])) {
148
                    $intersect[] = $item;
149
                }
150
            }
151
        }
152
153
        return new static($intersect);
154
    }
155
156
    /**
157
     * 交换数组中的键和值
158
     *
159
     * @access public
160
     * @return static
161
     */
162
    public function flip()
163
    {
164
        return new static(array_flip($this->items));
165
    }
166
167
    /**
168
     * 返回数组中所有的键名
169
     *
170
     * @access public
171
     * @return static
172
     */
173
    public function keys()
174
    {
175
        return new static(array_keys($this->items));
176
    }
177
178
    /**
179
     * 返回数组中所有的值组成的新 Collection 实例
180
     * @access public
181
     * @return static
182
     */
183
    public function values()
184
    {
185
        return new static(array_values($this->items));
186
    }
187
188
    /**
189
     * 删除数组的最后一个元素(出栈)
190
     *
191
     * @access public
192
     * @return mixed
193
     */
194
    public function pop()
195
    {
196
        return array_pop($this->items);
197
    }
198
199
    /**
200
     * 通过使用用户自定义函数,以字符串返回数组
201
     *
202
     * @access public
203
     * @param  callable $callback 调用方法
204
     * @param  mixed    $initial
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
205
     * @return mixed
206
     */
207
    public function reduce(callable $callback, $initial = null)
208
    {
209
        return array_reduce($this->items, $callback, $initial);
210
    }
211
212
    /**
213
     * 以相反的顺序返回数组。
214
     *
215
     * @access public
216
     * @return static
217
     */
218
    public function reverse()
219
    {
220
        return new static(array_reverse($this->items));
221
    }
222
223
    /**
224
     * 删除数组中首个元素,并返回被删除元素的值
225
     *
226
     * @access public
227
     * @return mixed
228
     */
229
    public function shift()
230
    {
231
        return array_shift($this->items);
232
    }
233
234
    /**
235
     * 在数组结尾插入一个元素
236
     * @access public
237
     * @param  mixed  $value 元素
238
     * @param  string $key KEY
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 1 found
Loading history...
239
     * @return void
240
     */
241
    public function push($value, string $key = null): void
242
    {
243
        if (is_null($key)) {
244
            $this->items[] = $value;
245
        } else {
246
            $this->items[$key] = $value;
247
        }
248
    }
249
250
    /**
251
     * 把一个数组分割为新的数组块.
252
     *
253
     * @access public
254
     * @param  int  $size 块大小
0 ignored issues
show
Coding Style introduced by
Expected 9 spaces after parameter name; 1 found
Loading history...
255
     * @param  bool $preserveKeys
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
256
     * @return static
257
     */
258
    public function chunk(int $size, bool $preserveKeys = false)
259
    {
260
        $chunks = [];
261
262
        foreach (array_chunk($this->items, $size, $preserveKeys) as $chunk) {
263
            $chunks[] = new static($chunk);
264
        }
265
266
        return new static($chunks);
267
    }
268
269
    /**
270
     * 在数组开头插入一个元素
271
     * @access public
272
     * @param mixed  $value 元素
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
273
     * @param string $key KEY
1 ignored issue
show
Coding Style introduced by
Expected 3 spaces after parameter name; 1 found
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
274
     * @return void
275
     */
276
    public function unshift($value, string $key = null): void
277
    {
278
        if (is_null($key)) {
279
            array_unshift($this->items, $value);
280
        } else {
281
            $this->items = [$key => $value] + $this->items;
282
        }
283
    }
284
285
    /**
286
     * 给每个元素执行个回调
287
     *
288
     * @access public
289
     * @param  callable $callback 回调
290
     * @return $this
291
     */
292
    public function each(callable $callback)
293
    {
294
        foreach ($this->items as $key => $item) {
295
            $result = $callback($item, $key);
296
297
            if (false === $result) {
298
                break;
299
            } elseif (!is_object($item)) {
300
                $this->items[$key] = $result;
301
            }
302
        }
303
304
        return $this;
305
    }
306
307
    /**
308
     * 用回调函数处理数组中的元素
309
     * @access public
310
     * @param  callable|null $callback 回调
311
     * @return static
312
     */
313
    public function map(callable $callback)
314
    {
315
        return new static(array_map($callback, $this->items));
316
    }
317
318
    /**
319
     * 用回调函数过滤数组中的元素
320
     * @access public
321
     * @param  callable|null $callback 回调
322
     * @return static
323
     */
324
    public function filter(callable $callback = null)
325
    {
326
        if ($callback) {
327
            return new static(array_filter($this->items, $callback));
328
        }
329
330
        return new static(array_filter($this->items));
331
    }
332
333
    /**
334
     * 根据字段条件过滤数组中的元素
335
     * @access public
336
     * @param  string $field 字段名
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
337
     * @param  mixed  $operator 操作符
338
     * @param  mixed  $value 数据
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
339
     * @return static
340
     */
341
    public function where(string $field, $operator, $value = null)
342
    {
343
        if (is_null($value)) {
344
            $value    = $operator;
345
            $operator = '=';
346
        }
347
348
        return $this->filter(function ($data) use ($field, $operator, $value) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
349
            if (strpos($field, '.')) {
350
                list($field, $relation) = explode('.', $field);
351
352
                $result = $data[$field][$relation] ?? null;
353
            } else {
354
                $result = $data[$field] ?? null;
355
            }
356
357
            switch ($operator) {
358
                case '===':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
359
                    return $result === $value;
360
                case '!==':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
361
                    return $result !== $value;
362
                case '!=':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
363
                case '<>':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
364
                    return $result != $value;
365
                case '>':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
366
                    return $result > $value;
367
                case '>=':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
368
                    return $result >= $value;
369
                case '<':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
370
                    return $result < $value;
371
                case '<=':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
372
                    return $result <= $value;
373
                case 'like':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
374
                    return is_string($result) && false !== strpos($result, $value);
375
                case 'not like':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
376
                    return is_string($result) && false === strpos($result, $value);
377
                case 'in':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
378
                    return is_scalar($result) && in_array($result, $value, true);
379
                case 'not in':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
380
                    return is_scalar($result) && !in_array($result, $value, true);
381
                case 'between':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
382
                    list($min, $max) = is_string($value) ? explode(',', $value) : $value;
383
                    return is_scalar($result) && $result >= $min && $result <= $max;
384
                case 'not between':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
385
                    list($min, $max) = is_string($value) ? explode(',', $value) : $value;
386
                    return is_scalar($result) && $result > $max || $result < $min;
387
                case '==':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
388
                case '=':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
389
                default:
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
390
                    return $result == $value;
391
            }
392
        });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
393
    }
394
395
    /**
396
     * LIKE过滤
397
     * @access public
398
     * @param  string $field 字段名
399
     * @param  string $value 数据
400
     * @return static
401
     */
402
    public function whereLike(string $field, string $value)
403
    {
404
        return $this->where($field, 'like', $value);
405
    }
406
407
    /**
408
     * NOT LIKE过滤
409
     * @access public
410
     * @param  string $field 字段名
411
     * @param  string $value 数据
412
     * @return static
413
     */
414
    public function whereNotLike(string $field, string $value)
415
    {
416
        return $this->where($field, 'not like', $value);
417
    }
418
419
    /**
420
     * IN过滤
421
     * @access public
422
     * @param  string $field 字段名
423
     * @param  array  $value 数据
424
     * @return static
425
     */
426
    public function whereIn(string $field, array $value)
427
    {
428
        return $this->where($field, 'in', $value);
429
    }
430
431
    /**
432
     * NOT IN过滤
433
     * @access public
434
     * @param  string $field 字段名
435
     * @param  array  $value 数据
436
     * @return static
437
     */
438
    public function whereNotIn(string $field, array $value)
439
    {
440
        return $this->where($field, 'not in', $value);
441
    }
442
443
    /**
444
     * BETWEEN 过滤
445
     * @access public
446
     * @param  string $field 字段名
447
     * @param  mixed  $value 数据
448
     * @return static
449
     */
450
    public function whereBetween(string $field, $value)
451
    {
452
        return $this->where($field, 'between', $value);
453
    }
454
455
    /**
456
     * NOT BETWEEN 过滤
457
     * @access public
458
     * @param  string $field 字段名
459
     * @param  mixed  $value 数据
460
     * @return static
461
     */
462
    public function whereNotBetween(string $field, $value)
463
    {
464
        return $this->where($field, 'not between', $value);
465
    }
466
467
    /**
468
     * 返回数据中指定的一列
469
     * @access public
470
     * @param string $columnKey 键名
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
471
     * @param string $indexKey  作为索引值的列
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
472
     * @return array
473
     */
474
    public function column(string $columnKey, string $indexKey = null)
475
    {
476
        return array_column($this->items, $columnKey, $indexKey);
477
    }
478
479
    /**
480
     * 对数组排序
481
     *
482
     * @access public
483
     * @param  callable|null $callback 回调
484
     * @return static
485
     */
486
    public function sort(callable $callback = null)
487
    {
488
        $items = $this->items;
489
490
        $callback = $callback ?: function ($a, $b) {
491
            return $a == $b ? 0 : (($a < $b) ? -1 : 1);
492
493
        };
494
495
        uasort($items, $callback);
496
497
        return new static($items);
498
    }
499
500
    /**
501
     * 指定字段排序
502
     * @access public
503
     * @param  string $field 排序字段
504
     * @param  string $order 排序
505
     * @return $this
506
     */
507
    public function order(string $field, string $order = null)
508
    {
509
        return $this->sort(function ($a, $b) use ($field, $order) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
510
            $fieldA = $a[$field] ?? null;
511
            $fieldB = $b[$field] ?? null;
512
513
            return 'desc' == strtolower($order) ? strcmp($fieldB, $fieldA) : strcmp($fieldA, $fieldB);
514
        });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
515
    }
516
517
    /**
518
     * 将数组打乱
519
     *
520
     * @access public
521
     * @return static
522
     */
523
    public function shuffle()
524
    {
525
        $items = $this->items;
526
527
        shuffle($items);
528
529
        return new static($items);
530
    }
531
532
    /**
533
     * 截取数组
534
     *
535
     * @access public
536
     * @param  int  $offset 起始位置
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter name; 1 found
Loading history...
537
     * @param  int  $length 截取长度
0 ignored issues
show
Coding Style introduced by
Expected 7 spaces after parameter name; 1 found
Loading history...
538
     * @param  bool $preserveKeys preserveKeys
539
     * @return static
540
     */
541
    public function slice(int $offset, int $length = null, bool $preserveKeys = false)
542
    {
543
        return new static(array_slice($this->items, $offset, $length, $preserveKeys));
544
    }
545
546
    // ArrayAccess
547
    public function offsetExists($offset)
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
548
    {
549
        return array_key_exists($offset, $this->items);
550
    }
551
552
    public function offsetGet($offset)
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
553
    {
554
        return $this->items[$offset];
555
    }
556
557
    public function offsetSet($offset, $value)
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
558
    {
559
        if (is_null($offset)) {
560
            $this->items[] = $value;
561
        } else {
562
            $this->items[$offset] = $value;
563
        }
564
    }
565
566
    public function offsetUnset($offset)
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
567
    {
568
        unset($this->items[$offset]);
569
    }
570
571
    //Countable
572
    public function count()
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
573
    {
574
        return count($this->items);
575
    }
576
577
    //IteratorAggregate
578
    public function getIterator()
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
579
    {
580
        return new ArrayIterator($this->items);
581
    }
582
583
    //JsonSerializable
584
    public function jsonSerialize()
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
585
    {
586
        return $this->toArray();
587
    }
588
589
    /**
590
     * 转换当前数据集为JSON字符串
591
     * @access public
592
     * @param  integer $options json参数
593
     * @return string
594
     */
595
    public function toJson(int $options = JSON_UNESCAPED_UNICODE)
596
    {
597
        return json_encode($this->toArray(), $options);
598
    }
599
600
    public function __toString()
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
601
    {
602
        return $this->toJson();
603
    }
604
605
    /**
606
     * 转换成数组
607
     *
608
     * @access public
609
     * @param  mixed $items 数据
610
     * @return array
611
     */
612
    protected function convertToArray($items): array
613
    {
614
        if ($items instanceof self) {
615
            return $items->all();
616
        }
617
618
        return (array) $items;
619
    }
620
}
621