GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Collection::usort()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 21
Code Lines 11

Duplication

Lines 21
Ratio 100 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
dl 21
loc 21
ccs 11
cts 11
cp 1
rs 9.0534
c 0
b 0
f 0
cc 4
eloc 11
nc 4
nop 1
crap 4
1
<?php
2
declare(strict_types=1);
3
namespace Narrowspark\Collection;
4
5
use ArrayAccess;
6
use ArrayIterator;
7
use BadMethodCallException;
8
use CachingIterator;
9
use Closure;
10
use Countable;
11
use InvalidArgumentException;
12
use Iterator;
13
use IteratorAggregate;
14
use JsonSerializable;
15
use Narrowspark\Arr\Arr;
16
use Serializable;
17
use Traversable;
18
19
class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable, Serializable
20
{
21
    /**
22
     * The registered string extensions.
23
     *
24
     * @var array
25
     */
26
    protected static $extensions = [];
27
28
    /**
29
     * The items contained in the collection.
30
     *
31
     * @var array
32
     */
33
    protected $items = [];
34
35
    /**
36
     * Create a new collection.
37
     *
38
     * @param callable|\Closure|array|Traversable\Iterator|self|IteratorAggregate|JsonSerializable $items
39
     */
40 154
    public function __construct($items = [])
41
    {
42 154
        $this->items = $this->getArrayableItems($items);
43 154
    }
44
45
    /**
46
     * Convert the collection to its string representation.
47
     *
48
     * @return string
49
     */
50 1
    public function __toString()
51
    {
52 1
        return $this->toJson();
53
    }
54
55
    /**
56
     * Dynamically handle calls to the class.
57
     *
58
     * @param string $method
59
     * @param array  $parameters
60
     *
61
     * @throws \BadMethodCallException
62
     *
63
     * @return mixed
64
     */
65 1 View Code Duplication
    public static function __callStatic($method, $parameters)
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...
66
    {
67 1
        if (! static::hasExtensions($method)) {
68
            throw new BadMethodCallException("Method {$method} does not exist.");
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $method instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
69
        }
70
71 1
        if (static::$extensions[$method] instanceof Closure) {
72 1
            return call_user_func_array(Closure::bind(static::$extensions[$method], null, static::class), $parameters);
73
        }
74
75
        return call_user_func_array(static::$extensions[$method], $parameters);
76
    }
77
78
    /**
79
     * Dynamically handle calls to the class.
80
     *
81
     * @param string $method
82
     * @param array  $parameters
83
     *
84
     * @throws \BadMethodCallException
85
     *
86
     * @return mixed
87
     */
88 2 View Code Duplication
    public function __call($method, $parameters)
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...
89
    {
90 2
        if (! static::hasExtensions($method)) {
91
            throw new BadMethodCallException("Method {$method} does not exist.");
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $method instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
92
        }
93
94 2
        if (static::$extensions[$method] instanceof Closure) {
95 2
            return call_user_func_array(static::$extensions[$method]->bindTo($this, static::class), $parameters);
96
        }
97
98
        return call_user_func_array(static::$extensions[$method], $parameters);
99
    }
100
101
    /**
102
     * Static alias of normal constructor.
103
     *
104
     * @param callable|\Closure|array|Traversable\Iterator|self|IteratorAggregate|JsonSerializable $items
105
     *
106
     * @return $this
107
     */
108 5
    public static function from($items = []): Collection
109
    {
110 5
        return new self($items);
111
    }
112
113
    /**
114
     * Get the average value of a given key.
115
     *
116
     * @param callable|string|null $callback
117
     *
118
     * @return int|float|null
119
     */
120 4
    public function average($callback = null)
121
    {
122 4
        if ($count = $this->count()) {
123 4
            return $this->sum($callback) / $count;
124
        }
125 1
    }
126
127
    /**
128
     * Get the median of a given key.
129
     *
130
     * @param null $key
131
     *
132
     * @return mixed|null
133
     */
134 5
    public function median($key = null)
135
    {
136 5
        $count = $this->count();
137
138 5
        if ($count == 0) {
139 1
            return;
140
        }
141
142 4
        $collection = isset($key) ? $this->pluck($key) : $this;
143 4
        $values = $collection->sort()->values();
144
145 4
        $middle = (int) ($count / 2);
146
147 4
        if ($count % 2) {
148 1
            return $values->get($middle);
149
        }
150
151 3
        return (new static([
152 3
            $values->get($middle - 1), $values->get($middle),
153 3
        ]))->average();
154
    }
155
156
    /**
157
     * Get the mode of a given key.
158
     *
159
     * @param string|int|null $key
160
     *
161
     * @return array|null
162
     */
163 4
    public function mode($key = null)
164
    {
165 4
        $count = $this->count();
166
167 4
        if ($count == 0) {
168 1
            return;
169
        }
170
171 3
        $collection = isset($key) ? $this->pluck($key) : $this;
172 3
        $counts = new self();
173
174
        $collection->each(function ($value) use ($counts) {
175 3
            $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1;
176 3
        });
177
178 3
        $sorted = $counts->sort();
179 3
        $highestValue = $sorted->last();
180
181
        return $sorted->filter(function ($key, $value) use ($highestValue) {
182 3
            return $value == $highestValue;
183 3
        })->sort()->keys()->all();
184
    }
185
186
    /**
187
     * Get the first item from the collection.
188
     *
189
     * @param callable|null $callback
190
     * @param mixed         $default
191
     *
192
     * @return mixed
193
     */
194 9
    public function first(callable $callback = null, $default = null)
195
    {
196 9
        return Arr::first($this->items, $callback, $default);
197
    }
198
199
    /**
200
     * Get a flattened array of the items in the collection.
201
     *
202
     * @param int|float|string $depth
203
     *
204
     * @return static
205
     */
206 3
    public function flatten($depth = INF): Collection
207
    {
208 3
        return new static(self::flattenCallback($this->items, $depth));
209
    }
210
211
    /**
212
     * Flip the items in the collection.
213
     *
214
     * @return static
215
     */
216 1
    public function flip(): Collection
217
    {
218 1
        return new static(array_flip($this->items));
219
    }
220
221
    /**
222
     * Get all items except for those with the specified keys.
223
     *
224
     * @param mixed $keys
225
     *
226
     * @return static
227
     */
228 1
    public function except($keys): Collection
229
    {
230 1
        $keys = is_array($keys) ? $keys : func_get_args();
231
232 1
        return new static(Arr::except($this->items, $keys));
233
    }
234
235
    /**
236
     * Run a filter over each of the items.
237
     *
238
     * @param callable|null $callback
239
     *
240
     * @return static
241
     */
242 13
    public function filter(callable $callback = null): Collection
243
    {
244 13
        if ($callback) {
245 13
            return new static(Arr::where($this->items, $callback));
246
        }
247
248 1
        return new static(array_filter($this->items));
249
    }
250
251
    /**
252
     * Get all of the items in the collection.
253
     *
254
     * @return array
255
     */
256 84
    public function all(): array
257
    {
258 84
        return $this->items;
259
    }
260
261
    /**
262
     * Merge the collection with the given items.
263
     *
264
     * @param callable|Closure|array|Traversable\Iterator|self|IteratorAggregate|JsonSerializable $items
265
     *
266
     * @return static
267
     */
268 3
    public function merge($items): Collection
269
    {
270 3
        return new static(array_merge($this->items, $this->getArrayableItems($items)));
271
    }
272
273
    /**
274
     * Returns a new collection with $value added as last element. If $key is not provided
275
     * it will be next integer index.
276
     *
277
     * @param mixed $value
278
     * @param mixed $key
279
     *
280
     * @return static
281
     */
282 1
    public function append($value, $key = null): Collection
283
    {
284 1
        $items = $this->items;
285
286 1
        if ($key === null) {
287 1
            $items[] = $value;
288
        } else {
289
            $items[$key] = $value;
290
        }
291
292 1
        return new static($items);
293
    }
294
295
    /**
296
     * Reset the keys on the underlying array.
297
     *
298
     * @return static
299
     */
300 24
    public function values(): Collection
301
    {
302 24
        return new static(array_values($this->items));
303
    }
304
305
    /**
306
     * Determine if an item exists in the collection.
307
     *
308
     * @param mixed $key
309
     * @param mixed $value
310
     *
311
     * @return bool
312
     */
313 2 View Code Duplication
    public function contains($key, $value = null): bool
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...
314
    {
315 2
        if (func_num_args() == 2) {
316
            return $this->contains(function ($itemKey, $item) use ($key, $value) {
317 1
                return self::dataGet($item, $key) == $value;
318 1
            });
319
        }
320
321 2
        if ($this->useAsCallable($key)) {
322 2
            return ! is_null($this->first($key));
323
        }
324
325 1
        return in_array($key, $this->items);
326
    }
327
328
    /**
329
     * Determine if an item exists in the collection using strict comparison.
330
     *
331
     * @param mixed $key
332
     * @param mixed $value
333
     *
334
     * @return bool
335
     */
336 1 View Code Duplication
    public function containsStrict($key, $value = null): bool
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...
337
    {
338 1
        if (func_num_args() == 2) {
339
            return $this->contains(function ($itemKey, $item) use ($key, $value) {
340 1
                return self::dataGet($item, $key) === $value;
341 1
            });
342
        }
343
344 1
        if ($this->useAsCallable($key)) {
345 1
            return ! is_null($this->first($key));
346
        }
347
348 1
        return in_array($key, $this->items, true);
349
    }
350
351
    /**
352
     * Get the items in the collection that are not present in the given items.
353
     *
354
     * @param mixed $items
355
     *
356
     * @return static
357
     */
358 2
    public function diff($items): Collection
359
    {
360 2
        return new static(array_diff($this->items, $this->getArrayableItems($items)));
361
    }
362
363
    /**
364
     * Get the items in the collection whose keys are not present in the given items.
365
     *
366
     * @param mixed $items
367
     *
368
     * @return static
369
     */
370 1
    public function diffKeys($items): Collection
371
    {
372 1
        return new static(array_diff_key($this->items, $this->getArrayableItems($items)));
373
    }
374
375
    /**
376
     * Execute a callback over each item.
377
     *
378
     * @param callable $callback
379
     *
380
     * @return $this
381
     */
382 4
    public function each(callable $callback): Collection
383
    {
384 4
        foreach ($this->items as $key => $item) {
385 4
            if ($callback($item, $key) === false) {
386 4
                break;
387
            }
388
        }
389
390 4
        return $this;
391
    }
392
393
    /**
394
     * Create a new collection consisting of every n-th element.
395
     *
396
     * @param int $step
397
     * @param int $offset
398
     *
399
     * @return static
400
     */
401 1
    public function every($step, $offset = 0): Collection
402
    {
403 1
        $new = [];
404 1
        $position = 0;
405
406 1
        foreach ($this->items as $item) {
407 1
            if ($position % $step === $offset) {
408 1
                $new[] = $item;
409
            }
410
411 1
            ++$position;
412
        }
413
414 1
        return new static($new);
415
    }
416
417
    /**
418
     * Filter items by the given key value pair.
419
     *
420
     * @param string $key
421
     * @param mixed  $operator
422
     * @param mixed  $value
423
     *
424
     * @return static
425
     */
426 2
    public function where(string $key, $operator, $value = null): Collection
427
    {
428 2
        if (func_num_args() === 2) {
429 1
            $value = $operator;
430 1
            $operator = '=';
431
        }
432
433 2
        return $this->filter($this->operatorForWhere($key, $operator, $value));
434
    }
435
436
    /**
437
     * Filter items by the given key value pair using strict comparison.
438
     *
439
     * @param string $key
440
     * @param mixed  $value
441
     *
442
     * @return static
443
     */
444 1
    public function whereStrict(string $key, $value): Collection
445
    {
446 1
        return $this->where($key, '===', $value);
447
    }
448
449
    /**
450
     * Filter items by the given key value pair.
451
     *
452
     * @param string $key
453
     * @param mixed  $values
454
     * @param bool   $strict
455
     *
456
     * @return static
457
     */
458 2
    public function whereIn(string $key, $values, bool $strict = false)
459
    {
460 2
        $values = $this->getArrayableItems($values);
461
462
        return $this->filter(function ($itemKey, $item) use ($key, $values, $strict) {
463 2
            return in_array(self::dataGet($item, $key), $values, $strict);
464 2
        });
465
    }
466
467
    /**
468
     * Filter items by the given key value pair using strict comparison.
469
     *
470
     * @param string $key
471
     * @param mixed  $values
472
     *
473
     * @return static
474
     */
475 1
    public function whereInStrict(string $key, $values): Collection
476
    {
477 1
        return $this->whereIn($key, $values, true);
478
    }
479
480
    /**
481
     * Remove an item from the collection by key.
482
     *
483
     * @param string|array $keys
484
     *
485
     * @return $this
486
     */
487 2
    public function forget($keys): Collection
488
    {
489 2
        foreach ((array) $keys as $key) {
490 2
            $this->offsetUnset($key);
491
        }
492
493 2
        return $this;
494
    }
495
496
    /**
497
     * Get an item from the collection by key.
498
     *
499
     * @param mixed $key
500
     * @param mixed $default
501
     *
502
     * @return mixed
503
     */
504 4
    public function get($key, $default = null)
505
    {
506 4
        if ($this->offsetExists($key)) {
507 4
            return $this->items[$key];
508
        }
509
510
        return value($default);
511
    }
512
513
    /**
514
     * Group an associative array by a field or using a callback.
515
     *
516
     * @param callable|string $groupBy
517
     * @param bool            $preserveKeys
518
     *
519
     * @return static
520
     */
521 6
    public function groupBy($groupBy, bool $preserveKeys = false): Collection
522
    {
523 6
        $groupBy = $this->valueRetriever($groupBy);
524 6
        $results = [];
525
526 6
        foreach ($this->items as $key => $value) {
527 6
            $groupKeys = $groupBy($value, $key);
528
529 6
            if (! is_array($groupKeys)) {
530 4
                $groupKeys = [$groupKeys];
531
            }
532
533 6
            foreach ($groupKeys as $groupKey) {
534 6
                if (! array_key_exists($groupKey, $results)) {
535 6
                    $results[$groupKey] = new static();
536
                }
537
538 6
                $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);
539
            }
540
        }
541
542 6
        return new static($results);
543
    }
544
545
    /**
546
     * Key an associative array by a field or using a callback.
547
     *
548
     * @param callable|string $keyBy
549
     *
550
     * @return static
551
     */
552 2
    public function keyBy($keyBy): Collection
553
    {
554 2
        $keyBy = $this->valueRetriever($keyBy);
555 2
        $results = [];
556 2
        foreach ($this->items as $key => $item) {
557 2
            $results[$keyBy($item, $key)] = $item;
558
        }
559
560 2
        return new static($results);
561
    }
562
563
    /**
564
     * Determine if an item exists in the collection by key.
565
     *
566
     * @param mixed $key
567
     *
568
     * @return bool
569
     */
570
    public function has($key): bool
571
    {
572
        return $this->offsetExists($key);
573
    }
574
575
    /**
576
     * Concatenate values of a given key as a string.
577
     *
578
     * @param string      $value
579
     * @param string|null $glue
580
     *
581
     * @return string
582
     */
583 1
    public function implode(string $value, string $glue = null): string
584
    {
585 1
        $first = $this->first();
586
587 1
        if (is_array($first) || is_object($first)) {
588 1
            return implode($glue, $this->pluck($value)->all());
589
        }
590
591 1
        return implode($value, $this->items);
592
    }
593
594
    /**
595
     * Intersect the collection with the given items.
596
     *
597
     * @param mixed $items
598
     *
599
     * @return static
600
     */
601 2
    public function intersect($items): Collection
602
    {
603 2
        return new static(array_intersect($this->items, $this->getArrayableItems($items)));
604
    }
605
606
    /**
607
     * Determine if the collection is empty or not.
608
     *
609
     * @return bool
610
     */
611 5
    public function isEmpty(): bool
612
    {
613 5
        return empty($this->items);
614
    }
615
616
    /**
617
     * Get the last item from the collection.
618
     *
619
     * @param callable|null $callback
620
     * @param mixed         $default
621
     *
622
     * @return mixed
623
     */
624 7
    public function last(callable $callback = null, $default = null)
625
    {
626 7
        return Arr::last($this->items, $callback, $default);
627
    }
628
629
    /**
630
     * Get the values of a given key.
631
     *
632
     * @param string      $value
633
     * @param string|null $key
634
     *
635
     * @return static
636
     */
637 8
    public function pluck(string $value, $key = null): Collection
638
    {
639 8
        $results = [];
640
641 8
        list($value, $key) = static::explodePluckParameters($value, $key);
642
643 8
        foreach ($this->items as $item) {
644 8
            $itemValue = self::dataGet($item, $value);
645
646 8
            if (is_null($key)) {
647 8
                $results[] = $itemValue;
648
            } else {
649 2
                $itemKey = self::dataGet($item, $key);
650 8
                $results[$itemKey] = $itemValue;
651
            }
652
        }
653
654 8
        return new static($results);
655
    }
656
657
    /**
658
     * Run a map over each of the items.
659
     *
660
     * @param callable $callback
661
     *
662
     * @return static
663
     */
664 8
    public function map(callable $callback): Collection
665
    {
666 8
        $keys = array_keys($this->items);
667 8
        $items = array_map($callback, $this->items, $keys);
668
669 8
        return new static(array_combine($keys, $items));
670
    }
671
672
    /**
673
     * Run an associative map over each of the items.
674
     *
675
     * The callback should return an associative array with a single key/value pair.
676
     *
677
     * @param callable $callback
678
     *
679
     * @return static
680
     */
681 1
    public function mapWithKeys(callable $callback): Collection
682
    {
683 1
        return $this->flatMap($callback);
684
    }
685
686
    /**
687
     * Map a collection and flatten the result by a single level.
688
     *
689
     * @param callable $callback
690
     *
691
     * @return static
692
     */
693 2
    public function flatMap(callable $callback): Collection
694
    {
695 2
        return $this->map($callback)->collapse();
696
    }
697
698
    /**
699
     * Get the max value of a given key.
700
     *
701
     * @param callable|string|null $callback
702
     *
703
     * @return mixed
704
     */
705 1 View Code Duplication
    public function max($callback = null)
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...
706
    {
707 1
        $callback = $this->valueRetriever($callback);
708
709
        return $this->reduce(function ($result, $item) use ($callback) {
710 1
            $value = $callback($item);
711
712 1
            return is_null($result) || $value > $result ? $value : $result;
713 1
        });
714
    }
715
716
    /**
717
     * Create a collection by using this collection for keys and another for its values.
718
     *
719
     * @param mixed $values
720
     *
721
     * @return static
722
     */
723 2
    public function combine($values): Collection
724
    {
725 2
        return new static(array_combine($this->all(), $this->getArrayableItems($values)));
726
    }
727
728
    /**
729
     * Union the collection with the given items.
730
     *
731
     * @param mixed $items
732
     *
733
     * @return static
734
     */
735 3
    public function union($items): Collection
736
    {
737 3
        return new static($this->items + $this->getArrayableItems($items));
738
    }
739
740
    /**
741
     * Get the min value of a given key.
742
     *
743
     * @param callable|string|null $callback
744
     *
745
     * @return mixed
746
     */
747 1 View Code Duplication
    public function min($callback = null)
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...
748
    {
749 1
        $callback = $this->valueRetriever($callback);
750
751
        return $this->reduce(function ($result, $item) use ($callback) {
752 1
            $value = $callback($item);
753
754 1
            return is_null($result) || $value < $result ? $value : $result;
755 1
        });
756
    }
757
758
    /**
759
     * Get the items with the specified keys.
760
     *
761
     * @param mixed $keys
762
     *
763
     * @return static
764
     */
765 1
    public function only($keys): Collection
766
    {
767 1
        $keys = is_array($keys) ? $keys : func_get_args();
768
769 1
        return new static(Arr::only($this->items, $keys));
770
    }
771
772
    /**
773
     * "Paginate" the collection by slicing it into a smaller collection.
774
     *
775
     * @param int $page
776
     * @param int $perPage
777
     *
778
     * @return static
779
     */
780 1
    public function forPage(int $page, int $perPage): Collection
781
    {
782 1
        return $this->slice(($page - 1) * $perPage, $perPage);
783
    }
784
785
    /**
786
     * Pass the collection to the given callback and return the result.
787
     *
788
     * @param callable $callback
789
     *
790
     * @return mixed
791
     */
792 1
    public function pipe(callable $callback)
793
    {
794 1
        return $callback($this);
795
    }
796
797
    /**
798
     * Get and remove the last item from the collection.
799
     *
800
     * @return mixed
801
     */
802 1
    public function pop()
803
    {
804 1
        return array_pop($this->items);
805
    }
806
807
    /**
808
     * Push an item onto the beginning of the collection.
809
     *
810
     * @param mixed $value
811
     * @param mixed $key
812
     *
813
     * @return $this
814
     */
815 1
    public function prepend($value, $key = null): Collection
816
    {
817 1
        $this->items = Arr::prepend($this->items, $value, $key);
818
819 1
        return $this;
820
    }
821
822
    /**
823
     * Push an item onto the end of the collection.
824
     *
825
     * @param mixed $value
826
     *
827
     * @return $this
828
     */
829
    public function push($value): Collection
830
    {
831
        $this->offsetSet(null, $value);
832
833
        return $this;
834
    }
835
836
    /**
837
     * Get and remove an item from the collection.
838
     *
839
     * @param mixed $key
840
     * @param mixed $default
841
     *
842
     * @return mixed
843
     */
844 3
    public function pull($key, $default = null)
845
    {
846 3
        return Arr::pull($this->items, $key, $default);
847
    }
848
849
    /**
850
     * Put an item in the collection by key.
851
     *
852
     * @param mixed $key
853
     * @param mixed $value
854
     *
855
     * @return $this
856
     */
857
    public function put($key, $value): Collection
858
    {
859
        $this->offsetSet($key, $value);
860
861
        return $this;
862
    }
863
864
    /**
865
     * Get one or more items randomly from the collection.
866
     *
867
     * @param int $amount
868
     *
869
     * @throws \InvalidArgumentException
870
     *
871
     * @return mixed
872
     */
873 3
    public function random($amount = 1)
874
    {
875 3
        if ($amount > ($count = $this->count())) {
876 2
            throw new InvalidArgumentException(
877 2
                sprintf('You requested %s items, but there are only %s items in the collection', $amount, $count)
878
            );
879
        }
880
881 1
        $keys = array_rand($this->items, $amount);
882
883 1
        if ($amount == 1) {
884 1
            return $this->items[$keys];
885
        }
886
887 1
        return new static(array_intersect_key($this->items, array_flip($keys)));
888
    }
889
890
    /**
891
     * Reduce the collection to a single value.
892
     *
893
     * @param callable $callback
894
     * @param mixed    $initial
895
     *
896
     * @return mixed
897
     */
898 6
    public function reduce(callable $callback, $initial = null)
899
    {
900 6
        return array_reduce($this->items, $callback, $initial);
901
    }
902
903
    /**
904
     * Create a collection of all elements that do not pass a given truth test.
905
     *
906
     * @param mixed $callback
907
     *
908
     * @return static
909
     */
910 3
    public function reject($callback): Collection
911
    {
912 3
        if ($this->useAsCallable($callback)) {
913
            return $this->filter(function ($key, $value) use ($callback) {
914 3
                return ! $callback($value, $key);
915 3
            });
916
        }
917
918
        return $this->filter(function ($key, $item) use ($callback) {
919 1
            return $item != $callback;
920 1
        });
921
    }
922
923
    /**
924
     * Reverse items order.
925
     *
926
     * @return static
927
     */
928 1
    public function reverse(): Collection
929
    {
930 1
        return new static(array_reverse($this->items, true));
931
    }
932
933
    /**
934
     * Search the collection for a given value and return the corresponding key if successful.
935
     *
936
     * @param mixed $value
937
     * @param bool  $strict
938
     *
939
     * @return false|int|string
940
     */
941 2
    public function search($value, $strict = false)
942
    {
943 2
        if (! $this->useAsCallable($value)) {
944 2
            return array_search($value, $this->items, $strict);
945
        }
946 2
        foreach ($this->items as $key => $item) {
947 2
            if (call_user_func($value, $item, $key)) {
948 2
                return $key;
949
            }
950
        }
951
952 1
        return false;
953
    }
954
955
    /**
956
     * Get and remove the first item from the collection.
957
     *
958
     * @return mixed
959
     */
960 1
    public function shift()
961
    {
962 1
        return array_shift($this->items);
963
    }
964
965
    /**
966
     * Shuffle the items in the collection.
967
     *
968
     * @param null|int $seed
969
     *
970
     * @return static
971
     */
972
    public function shuffle(int $seed = null): Collection
973
    {
974
        $items = $this->items;
975
        if (is_null($seed)) {
976
            shuffle($items);
977
        } else {
978
            srand($seed);
979
            usort($items, function () {
980
                return rand(-1, 1);
981
            });
982
        }
983
984
        return new static($items);
985
    }
986
987
    /**
988
     * Slice the underlying collection array.
989
     *
990
     * @param int      $offset
991
     * @param null|int $length
992
     *
993
     * @return static
994
     */
995 9
    public function slice(int $offset, int $length = null): Collection
996
    {
997 9
        return new static(array_slice($this->items, $offset, $length, true));
998
    }
999
1000
    /**
1001
     * Split a collection into a certain number of groups.
1002
     *
1003
     * @param int $numberOfGroups
1004
     *
1005
     * @return static
1006
     */
1007 4
    public function split(int $numberOfGroups): Collection
1008
    {
1009 4
        if ($this->isEmpty()) {
1010 1
            return new static();
1011
        }
1012
1013 3
        $groupSize = ceil($this->count() / $numberOfGroups);
1014
1015 3
        return $this->chunk($groupSize);
1016
    }
1017
1018
    /**
1019
     * Chunk the underlying collection array.
1020
     *
1021
     * @param int|float $size
1022
     *
1023
     * @return static
1024
     */
1025 4
    public function chunk($size): Collection
1026
    {
1027 4
        $chunks = [];
1028
1029 4
        foreach (array_chunk($this->items, (int) $size, true) as $chunk) {
1030 4
            $chunks[] = new static($chunk);
1031
        }
1032
1033 4
        return new static($chunks);
1034
    }
1035
1036
    /**
1037
     * Sort through each item with a callback.
1038
     *
1039
     * @see http://stackoverflow.com/questions/4353739/preserve-key-order-stable-sort-when-sorting-with-phps-uasort
1040
     * @see http://en.wikipedia.org/wiki/Schwartzian_transform
1041
     *
1042
     * @param callable|null $callback
1043
     *
1044
     * @return static
1045
     */
1046 9
    public function sort(callable $callback = null): Collection
1047
    {
1048 9
        $items = $this->items;
1049
1050 9
        $callback
1051 1
            ? uasort($items, $callback)
1052 8
            : asort($items);
1053
1054 9
        return new static($items);
1055
    }
1056
1057
    /**
1058
     * Sort an array in reverse order and maintain index association.
1059
     *
1060
     * @param int $option
1061
     *
1062
     * @return static
1063
     */
1064 3 View Code Duplication
    public function arsort(int $option = SORT_REGULAR): Collection
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...
1065
    {
1066 3
        $index = 0;
1067 3
        $items = $this->items;
1068
1069 3
        foreach ($items as &$item) {
1070 3
            $item = [$index++, $item];
1071
        }
1072
1073
        uasort($items, function ($a, $b) use ($option) {
1074 3
            if ($a[1] === $b[1]) {
1075 1
                return $a[0] - $b[0];
1076
            }
1077
1078 3
            $set = [-1 => $b[1], 1 => $a[1]];
1079
1080 3
            asort($set, $option);
1081 3
            reset($set);
1082
1083 3
            return key($set);
1084 3
        });
1085
1086 3
        foreach ($items as &$item) {
1087 3
            $item = $item[1];
1088
        }
1089
1090 3
        return new static($items);
1091
    }
1092
1093
    /**
1094
     * Sort an array and maintain index association.
1095
     *
1096
     * @param int $option
1097
     *
1098
     * @return static
1099
     */
1100 3 View Code Duplication
    public function asort(int $option = SORT_REGULAR): Collection
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...
1101
    {
1102 3
        $index = 0;
1103 3
        $items = $this->items;
1104
1105 3
        foreach ($items as &$item) {
1106 3
            $item = [$index++, $item];
1107
        }
1108
1109
        uasort($items, function ($a, $b) use ($option) {
1110 3
            if ($a[1] === $b[1]) {
1111 1
                return $a[0] - $b[0];
1112
            }
1113
1114 3
            $set = [-1 => $a[1], 1 => $b[1]];
1115
1116 3
            asort($set, $option);
1117 3
            reset($set);
1118
1119 3
            return key($set);
1120 3
        });
1121
1122 3
        foreach ($items as &$item) {
1123 3
            $item = $item[1];
1124
        }
1125
1126 3
        return new static($items);
1127
    }
1128
1129
    /**
1130
     * Sort an array using a case insensitive "natural order" algorithm.
1131
     *
1132
     * @return static
1133
     */
1134 1 View Code Duplication
    public function natcasesort(): Collection
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...
1135
    {
1136 1
        $index = 0;
1137 1
        $items = $this->items;
1138
1139 1
        foreach ($items as &$item) {
1140 1
            $item = [$index++, $item];
1141
        }
1142
1143
        uasort($items, function ($a, $b) {
1144 1
            $result = strnatcasecmp($a[1], $b[1]);
1145
1146 1
            return $result === 0 ? $a[0] - $b[0] : $result;
1147 1
        });
1148
1149 1
        foreach ($items as &$item) {
1150 1
            $item = $item[1];
1151
        }
1152
1153 1
        return new static($items);
1154
    }
1155
1156
    /**
1157
     * Sort an array using a "natural order" algorithm.
1158
     *
1159
     * @return static
1160
     */
1161 1 View Code Duplication
    public function natsort(): Collection
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...
1162
    {
1163 1
        $index = 0;
1164 1
        $items = $this->items;
1165
1166 1
        foreach ($items as &$item) {
1167 1
            $item = [$index++, $item];
1168
        }
1169
1170
        uasort($items, function ($a, $b) {
1171 1
            $result = strnatcmp($a[1], $b[1]);
1172
1173 1
            return $result === 0 ? $a[0] - $b[0] : $result;
1174 1
        });
1175
1176 1
        foreach ($items as &$item) {
1177 1
            $item = $item[1];
1178
        }
1179
1180 1
        return new static($items);
1181
    }
1182
1183
    /**
1184
     * Sort an array with a user-defined comparison function and maintain index association.
1185
     *
1186
     * @param callable $callback
1187
     *
1188
     * @return static
1189
     */
1190 1 View Code Duplication
    public function uasort(callable $callback): Collection
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...
1191
    {
1192 1
        $index = 0;
1193 1
        $items = $this->items;
1194
1195 1
        foreach ($items as &$item) {
1196 1
            $item = [$index++, $item];
1197
        }
1198
1199
        uasort($items, function ($a, $b) use ($callback) {
1200 1
            $result = call_user_func($callback, $a[1], $b[1]);
1201
1202 1
            return $result === 0 ? $a[0] - $b[0] : $result;
1203 1
        });
1204
1205 1
        foreach ($items as &$item) {
1206 1
            $item = $item[1];
1207
        }
1208
1209 1
        return new static($items);
1210
    }
1211
1212
    /**
1213
     * Sort an array by keys using a user-defined comparison function.
1214
     *
1215
     * @param callable $callback
1216
     *
1217
     * @return static
1218
     */
1219 1
    public function uksort(callable $callback): Collection
1220
    {
1221 1
        $items = $this->items;
1222 1
        $keys = array_combine(array_keys($items), range(1, count($items)));
1223
1224
        uksort($items, function ($a, $b) use ($callback, $keys) {
1225 1
            $result = call_user_func($callback, $a, $b);
1226
1227 1
            return $result === 0 ? $keys[$a] - $keys[$b] : $result;
1228 1
        });
1229
1230 1
        return new static($items);
1231
    }
1232
1233
    /**
1234
     * Sort an array by values using a user-defined comparison function.
1235
     *
1236
     * @param callable $callback
1237
     *
1238
     * @return static
1239
     */
1240 1 View Code Duplication
    public function usort(callable $callback): Collection
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...
1241
    {
1242 1
        $index = 0;
1243 1
        $items = $this->items;
1244
1245 1
        foreach ($items as &$item) {
1246 1
            $item = [$index++, $item];
1247
        }
1248
1249
        usort($items, function ($a, $b) use ($callback) {
1250 1
            $result = call_user_func($callback, $a[1], $b[1]);
1251
1252 1
            return $result === 0 ? $a[0] - $b[0] : $result;
1253 1
        });
1254
1255 1
        foreach ($items as &$item) {
1256 1
            $item = $item[1];
1257
        }
1258
1259 1
        return new static($items);
1260
    }
1261
1262
    /**
1263
     * Sort the collection using the given callback.
1264
     *
1265
     * @param callable|string $callback
1266
     * @param int             $options
1267
     * @param bool            $descending
1268
     *
1269
     * @return static
1270
     */
1271 3
    public function sortBy($callback, int $options = SORT_REGULAR, bool $descending = false): Collection
1272
    {
1273 3
        $results = [];
1274 3
        $callback = $this->valueRetriever($callback);
1275
1276
        // First we will loop through the items and get the comparator from a callback
1277
        // function which we were given. Then, we will sort the returned values and
1278
        // and grab the corresponding values for the sorted keys from this array.
1279 3
        foreach ($this->items as $key => $value) {
1280 3
            $results[$key] = $callback($value, $key);
1281
        }
1282
1283 3
        $descending ? arsort($results, $options) : asort($results, $options);
1284
1285
        // Once we have sorted all of the keys in the array, we will loop through them
1286
        // and grab the corresponding model so we can set the underlying items list
1287
        // to the sorted version. Then we'll just return the collection instance.
1288 3
        foreach (array_keys($results) as $key) {
1289 3
            $results[$key] = $this->items[$key];
1290
        }
1291
1292 3
        return new static($results);
1293
    }
1294
1295
    /**
1296
     * Sort the collection in descending order using the given callback.
1297
     *
1298
     * @param callable|string $callback
1299
     * @param int             $options
1300
     *
1301
     * @return static
1302
     */
1303 1
    public function sortByDesc($callback, int $options = SORT_REGULAR): Collection
1304
    {
1305 1
        return $this->sortBy($callback, $options, true);
1306
    }
1307
1308
    /**
1309
     * Splice a portion of the underlying collection array.
1310
     *
1311
     * @param int      $offset
1312
     * @param int|null $length
1313
     * @param mixed    $replacement
1314
     *
1315
     * @return static
1316
     */
1317 1
    public function splice(int $offset, $length = null, $replacement = []): Collection
1318
    {
1319 1
        if (func_num_args() == 1) {
1320 1
            return new static(array_splice($this->items, $offset));
1321
        }
1322
1323 1
        return new static(array_splice($this->items, $offset, $length, $replacement));
1324
    }
1325
1326
    /**
1327
     * Get the sum of the given values.
1328
     *
1329
     * @param callable|string|null $callback
1330
     *
1331
     * @return mixed
1332
     */
1333 8
    public function sum($callback = null)
1334
    {
1335 8
        if (is_null($callback)) {
1336 6
            return array_sum($this->items);
1337
        }
1338 3
        $callback = $this->valueRetriever($callback);
1339
1340
        return $this->reduce(function ($result, $item) use ($callback) {
1341 2
            return $result + $callback($item);
1342 3
        }, 0);
1343
    }
1344
1345
    /**
1346
     * Take the first or last {$limit} items.
1347
     *
1348
     * @param int $limit
1349
     *
1350
     * @return static
1351
     */
1352 2
    public function take(int $limit): Collection
1353
    {
1354 2
        if ($limit < 0) {
1355 1
            return $this->slice($limit, abs($limit));
1356
        }
1357
1358 1
        return $this->slice(0, $limit);
1359
    }
1360
1361
    /**
1362
     * Transform each item in the collection using a callback.
1363
     *
1364
     * @param callable $callback
1365
     *
1366
     * @return $this
1367
     */
1368 1
    public function transform(callable $callback): Collection
1369
    {
1370 1
        $this->items = $this->map($callback)->all();
1371
1372 1
        return $this;
1373
    }
1374
1375
    /**
1376
     * Return only unique items from the collection array.
1377
     *
1378
     * @param string|callable|null $key
1379
     * @param bool                 $strict
1380
     *
1381
     * @return static
1382
     */
1383 4
    public function unique($key = null, bool $strict = false): Collection
1384
    {
1385 4
        if (is_null($key)) {
1386 2
            return new static(array_unique($this->items, SORT_REGULAR));
1387
        }
1388
1389 2
        $key = $this->valueRetriever($key);
1390 2
        $exists = [];
1391
1392
        return $this->reject(function ($item) use ($key, $strict, &$exists) {
1393 2
            if (in_array($id = $key($item), $exists, $strict)) {
1394 2
                return true;
1395
            }
1396
1397 2
            $exists[] = $id;
1398 2
        });
1399
    }
1400
1401
    /**
1402
     * Return only unique items from the collection array using strict comparison.
1403
     *
1404
     * @param string|callable|null $key
1405
     *
1406
     * @return static
1407
     */
1408 1
    public function uniqueStrict($key = null): Collection
1409
    {
1410 1
        return $this->unique($key, true);
1411
    }
1412
1413
    /**
1414
     * Zip the collection together with one or more arrays.
1415
     *
1416
     * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1417
     *      => [[1, 4], [2, 5], [3, 6]]
1418
     *
1419
     * @param  mixed ...$items
1420
     *
1421
     * @return static
1422
     */
1423 1
    public function zip($items): Collection
1424
    {
1425
        $arrayableItems = array_map(function ($items) {
1426 1
            return $this->getArrayableItems($items);
1427 1
        }, func_get_args());
1428
        $params = array_merge([function () {
1429 1
            return new static(func_get_args());
1430 1
        }, $this->items], $arrayableItems);
1431
1432 1
        return new static(call_user_func_array('array_map', $params));
1433
    }
1434
1435
    /**
1436
     * Collapse the collection of items into a single array.
1437
     *
1438
     * @return static
1439
     */
1440 4
    public function collapse(): Collection
1441
    {
1442 4
        $results = [];
1443
1444 4
        foreach ($this->items as $values) {
1445 4
            if ($values instanceof self) {
1446 1
                $values = $values->all();
1447 3
            } elseif (! is_array($values)) {
1448
                continue;
1449
            }
1450
1451 4
            $results = array_merge($results, $values);
1452
        }
1453
1454 4
        return new static($results);
1455
    }
1456
1457
    /**
1458
     * Get the keys of the collection items.
1459
     *
1460
     * @return static
1461
     */
1462 4
    public function keys(): Collection
1463
    {
1464 4
        return new static(array_keys($this->items));
1465
    }
1466
1467
    /**
1468
     * Get the instance as an array.
1469
     *
1470
     * @return array
1471
     */
1472 24
    public function toArray(): array
1473
    {
1474
        return array_map(function ($value) {
1475 23
            if (method_exists($value, 'toArray')) {
1476 7
                return $value->toArray();
1477
            }
1478
1479 22
            return $value;
1480 24
        }, $this->items);
1481
    }
1482
1483
    /**
1484
     * {@inheritdoc}
1485
     */
1486 2
    public function jsonSerialize()
1487
    {
1488
        return array_map(function ($value) {
1489 2
            if ($value instanceof JsonSerializable) {
0 ignored issues
show
Bug introduced by
The class JsonSerializable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
1490 2
                return $value->jsonSerialize();
1491 2
            } elseif (method_exists($value, 'toJson')) {
1492 1
                return json_decode($value->toJson(), true);
1493 2
            } elseif (method_exists($value, 'toArray')) {
1494 2
                return $value->toArray();
1495
            }
1496
1497 1
            return $value;
1498 2
        }, $this->items);
1499
    }
1500
1501
    /**
1502
     * Convert the object to its JSON representation.
1503
     *
1504
     * @param int $options
1505
     *
1506
     * @return string
1507
     */
1508 2
    public function toJson(int $options = 0): string
1509
    {
1510 2
        return json_encode($this->jsonSerialize(), $options);
1511
    }
1512
1513
    /**
1514
     * Get an iterator for the items.
1515
     *
1516
     * @return \ArrayIterator
1517
     */
1518 2
    public function getIterator()
1519
    {
1520 2
        return new ArrayIterator($this->items);
1521
    }
1522
1523
    /**
1524
     * Get a CachingIterator instance.
1525
     *
1526
     * @param int $flags
1527
     *
1528
     * @return \CachingIterator
1529
     */
1530 1
    public function getCachingIterator(int $flags = CachingIterator::CALL_TOSTRING): CachingIterator
1531
    {
1532 1
        return new CachingIterator($this->getIterator(), $flags);
1533
    }
1534
1535
    /**
1536
     * Count the number of items in the collection.
1537
     *
1538
     * @return int
1539
     */
1540 19
    public function count()
1541
    {
1542 19
        return count($this->items);
1543
    }
1544
1545
    /**
1546
     * {@inheritdoc}
1547
     */
1548
    public function serialize()
1549
    {
1550
        return serialize($this->toJson());
1551
    }
1552
1553
    /**
1554
     * Unserialize a string to a collection object.
1555
     *
1556
     * @param string $serialized
1557
     *
1558
     * @return static
1559
     */
1560
    public function unserialize($serialized)
1561
    {
1562
        return new static(unserialize($serialized));
1563
    }
1564
1565
    /**
1566
     * Determine if an item exists at an offset.
1567
     *
1568
     * @param mixed $key
1569
     *
1570
     * @return bool
1571
     */
1572 11
    public function offsetExists($key)
1573
    {
1574 11
        return array_key_exists($key, $this->items);
1575
    }
1576
1577
    /**
1578
     * Get an item at a given offset.
1579
     *
1580
     * @param mixed $key
1581
     *
1582
     * @return mixed
1583
     */
1584 10
    public function offsetGet($key)
1585
    {
1586 10
        return $this->items[$key];
1587
    }
1588
1589
    /**
1590
     * Set the item at a given offset.
1591
     *
1592
     * @param mixed $key
1593
     * @param mixed $value
1594
     */
1595 11
    public function offsetSet($key, $value)
1596
    {
1597 11
        if (is_null($key)) {
1598 5
            $this->items[] = $value;
1599
        } else {
1600 8
            $this->items[$key] = $value;
1601
        }
1602 11
    }
1603
1604
    /**
1605
     * Unset the item at a given offset.
1606
     *
1607
     * @param string $key
1608
     */
1609 4
    public function offsetUnset($key)
1610
    {
1611 4
        unset($this->items[$key]);
1612 4
    }
1613
1614
    /**
1615
     * Register a custom extensions.
1616
     *
1617
     * @param string   $name
1618
     * @param callable $callback
1619
     */
1620 3
    public static function extend(string $name, callable $callback)
1621
    {
1622 3
        static::$extensions[$name] = $callback;
1623 3
    }
1624
1625
    /**
1626
     * Checks if extensions is registered.
1627
     *
1628
     * @param string $name
1629
     *
1630
     * @return bool
1631
     */
1632 3
    public static function hasExtensions(string $name): bool
1633
    {
1634 3
        return isset(static::$extensions[$name]);
1635
    }
1636
1637
    /**
1638
     * Explode the "value" and "key" arguments passed to "pluck".
1639
     *
1640
     * @param string|array      $value
1641
     * @param string|array|null $key
1642
     *
1643
     * @return array
1644
     */
1645 8
    protected static function explodePluckParameters($value, $key): array
1646
    {
1647 8
        $value = is_string($value) ? explode('.', $value) : $value;
1648
1649 8
        $key = is_null($key) || is_array($key) ? $key : explode('.', $key);
1650
1651 8
        return [$value, $key];
1652
    }
1653
1654
    /**
1655
     * Get an operator checker callback.
1656
     *
1657
     * @param string $key
1658
     * @param string $operator
1659
     * @param mixed  $value
1660
     *
1661
     * @return \Closure
1662
     */
1663 2
    protected function operatorForWhere(string $key, $operator, $value)
1664
    {
1665
        return function ($itemKey, $item) use ($key, $operator, $value) {
1666 2
            $retrieved = self::dataGet($item, $key);
1667
1668
            switch ($operator) {
1669
                default:
1670 2
                case '=':
1671 2
                case '==':
1672 1
                    return $retrieved == $value;
1673 2
                case '!=':
1674 2
                case '<>':
1675 1
                    return $retrieved != $value;
1676 2
                case '<':
1677 1
                    return $retrieved < $value;
1678 2
                case '>':
1679 1
                    return $retrieved > $value;
1680 2
                case '<=':
1681 1
                    return $retrieved <= $value;
1682 2
                case '>=':
1683 1
                    return $retrieved >= $value;
1684 2
                case '===':
1685 2
                    return $retrieved === $value;
1686 1
                case '!==':
1687 1
                    return $retrieved !== $value;
1688
            }
1689 2
        };
1690
    }
1691
1692
    /**
1693
     * Get a value retrieving callback.
1694
     *
1695
     * @param mixed $value
1696
     *
1697
     * @return callable
1698
     */
1699 18
    protected function valueRetriever($value)
1700
    {
1701 18
        if ($this->useAsCallable($value)) {
1702 12
            return $value;
1703
        }
1704
1705
        return function ($item) use ($value) {
1706 11
            return self::dataGet($item, $value);
1707 12
        };
1708
    }
1709
1710
    /**
1711
     * Results array of items from Collection or Arrayable.
1712
     *
1713
     * @param callable|Closure|array|Traversable\Iterator|self|IteratorAggregate|JsonSerializable $items
1714
     *
1715
     * @return array
1716
     */
1717 154
    protected function getArrayableItems($items): array
1718
    {
1719 154
        if (is_array($items)) {
1720 148
            return $items;
1721 23
        } elseif (is_callable($items)) {
1722
            return call_user_func($items);
1723 23
        } elseif ($items instanceof self) {
1724 10
            return $items->all();
1725
        } elseif ($items instanceof Iterator) {
1726
            return $items;
1727
        } elseif ($items instanceof Traversable) {
1728 2
            return iterator_to_array($items);
1729
        } elseif ($items instanceof IteratorAggregate) {
1730
            return $items->getIterator();
1731
        } elseif ($items instanceof JsonSerializable) {
0 ignored issues
show
Bug introduced by
The class JsonSerializable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
1732 1
            return $items->jsonSerialize();
1733 12
        } elseif (method_exists($items, 'toJson')) {
1734 1
            return json_decode($items->toJson(), true);
1735 12
        } elseif (method_exists($items, 'toArray')) {
1736 1
            return $items->toArray();
1737
        }
1738
1739 11
        return (array) $items;
1740
    }
1741
1742
    /**
1743
     * Determine if the given value is callable, but not a string.
1744
     *
1745
     * @param mixed $value
1746
     *
1747
     * @return bool
1748
     */
1749 23
    protected function useAsCallable($value): bool
1750
    {
1751 23
        return ! is_string($value) && is_callable($value);
1752
    }
1753
1754
    /**
1755
     * Get an item from an array or object using "dot" notation.
1756
     *
1757
     * @param mixed        $target
1758
     * @param string|array $key
1759
     * @param mixed        $default
1760
     *
1761
     * @return mixed
1762
     */
1763 24
    protected static function dataGet($target, $key, $default = null)
1764
    {
1765 24
        if (is_null($key)) {
1766 2
            return $target;
1767
        }
1768
1769 24
        $key = is_array($key) ? $key : explode('.', $key);
1770
1771 24
        while (($segment = array_shift($key)) !== null) {
1772 24
            if ($segment === '*') {
1773
                if ($target instanceof self) {
1774
                    $target = $target->all();
1775
                } elseif (! is_array($target)) {
1776
                    return Arr::value($default);
1777
                }
1778
1779
                $result = $this->pluck($target, $key);
0 ignored issues
show
Bug introduced by
The variable $this does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1780
1781
                return in_array('*', $key) ? Arr::collapse($result) : $result;
0 ignored issues
show
Documentation introduced by
$result is of type this<Narrowspark\Collection\Collection>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1782
            }
1783
1784 24
            if (Arr::accessible($target) && Arr::exists($target, $segment)) {
1785 19
                $target = $target[$segment];
1786 10
            } elseif (is_object($target) && isset($target->{$segment})) {
1787 10
                $target = $target->{$segment};
1788
            } else {
1789
                return Arr::value($default);
1790
            }
1791
        }
1792
1793 24
        return $target;
1794
    }
1795
1796
    /**
1797
     * Flatten a multi-dimensional array into a single level.
1798
     *
1799
     * @param array|\Collection $array
1800
     * @param int|float|string  $depth
1801
     *
1802
     * @return array
1803
     */
1804 3
    private function flattenCallback($array, $depth = INF): array
1805
    {
1806 3
        $depth = (int) $depth;
1807
1808 3
        return array_reduce($array, function ($result, $item) use ($depth) {
1809 3
            $item = $item instanceof self ? $item->all() : $item;
1810
1811 3
            if (! is_array($item)) {
1812 3
                return array_merge($result, [$item]);
1813 3
            } elseif ($depth === 1) {
1814 2
                return array_merge($result, array_values($item));
1815
            }
1816
1817 3
            return array_merge($result, self::flattenCallback($item, $depth - 1));
1818 3
        }, []);
1819
    }
1820
}
1821