Completed
Push — master ( 0625ac...1a51b8 )
by Antonio Carlos
02:05
created

Collection::diff()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 1
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace IlluminateAgnostic\Collection\Support;
4
5
use stdClass;
6
use Countable;
7
use Exception;
8
use ArrayAccess;
9
use Traversable;
10
use ArrayIterator;
11
use CachingIterator;
12
use JsonSerializable;
13
use IteratorAggregate;
14
use IlluminateAgnostic\Collection\Support\Debug\Dumper;
15
use IlluminateAgnostic\Collection\Support\Traits\Macroable;
16
use IlluminateAgnostic\Collection\Contracts\Support\Jsonable;
17
use IlluminateAgnostic\Collection\Contracts\Support\Arrayable;
18
19
/**
20
 * @property-read HigherOrderCollectionProxy $average
21
 * @property-read HigherOrderCollectionProxy $avg
22
 * @property-read HigherOrderCollectionProxy $contains
23
 * @property-read HigherOrderCollectionProxy $each
24
 * @property-read HigherOrderCollectionProxy $every
25
 * @property-read HigherOrderCollectionProxy $filter
26
 * @property-read HigherOrderCollectionProxy $first
27
 * @property-read HigherOrderCollectionProxy $flatMap
28
 * @property-read HigherOrderCollectionProxy $groupBy
29
 * @property-read HigherOrderCollectionProxy $keyBy
30
 * @property-read HigherOrderCollectionProxy $map
31
 * @property-read HigherOrderCollectionProxy $max
32
 * @property-read HigherOrderCollectionProxy $min
33
 * @property-read HigherOrderCollectionProxy $partition
34
 * @property-read HigherOrderCollectionProxy $reject
35
 * @property-read HigherOrderCollectionProxy $sortBy
36
 * @property-read HigherOrderCollectionProxy $sortByDesc
37
 * @property-read HigherOrderCollectionProxy $sum
38
 * @property-read HigherOrderCollectionProxy $unique
39
 *
40
 * Class Collection
41
 */
42
class Collection implements ArrayAccess, Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable
43
{
44
    use Macroable;
45
46
    /**
47
     * The items contained in the collection.
48
     *
49
     * @var array
50
     */
51
    protected $items = [];
52
53
    /**
54
     * The methods that can be proxied.
55
     *
56
     * @var array
57
     */
58
    protected static $proxies = [
59
        'average', 'avg', 'contains', 'each', 'every', 'filter', 'first',
60
        'flatMap', 'groupBy', 'keyBy', 'map', 'max', 'min', 'partition',
61
        'reject', 'sortBy', 'sortByDesc', 'sum', 'unique',
62
    ];
63
64
    /**
65
     * Create a new collection.
66
     *
67
     * @param  mixed  $items
68
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
69
     */
70 221
    public function __construct($items = [])
71
    {
72 221
        $this->items = $this->getArrayableItems($items);
73 221
    }
74
75
    /**
76
     * Create a new collection instance if the value isn't one already.
77
     *
78
     * @param  mixed  $items
79
     * @return static
80
     */
81 10
    public static function make($items = [])
82
    {
83 10
        return new static($items);
84
    }
85
86
    /**
87
     * Wrap the given value in a collection if applicable.
88
     *
89
     * @param  mixed  $value
90
     * @return static
91
     */
92 7
    public static function wrap($value)
93
    {
94 7
        return $value instanceof self
95 2
            ? new static($value)
96 7
            : new static(Arr::wrap($value));
97
    }
98
99
    /**
100
     * Get the underlying items from the given collection if applicable.
101
     *
102
     * @param  array|static  $value
103
     * @return array
104
     */
105 3
    public static function unwrap($value)
106
    {
107 3
        return $value instanceof self ? $value->all() : $value;
108
    }
109
110
    /**
111
     * Create a new collection by invoking the callback a given amount of times.
112
     *
113
     * @param  int  $number
114
     * @param  callable  $callback
115
     * @return static
116
     */
117 1
    public static function times($number, callable $callback = null)
118
    {
119 1
        if ($number < 1) {
120 1
            return new static;
121
        }
122
123 1
        if (is_null($callback)) {
124 1
            return new static(range(1, $number));
125
        }
126
127 1
        return (new static(range(1, $number)))->map($callback);
128
    }
129
130
    /**
131
     * Get all of the items in the collection.
132
     *
133
     * @return array
134
     */
135 110
    public function all()
136
    {
137 110
        return $this->items;
138
    }
139
140
    /**
141
     * Get the average value of a given key.
142
     *
143
     * @param  callable|string|null  $callback
144
     * @return mixed
145
     */
146 4
    public function avg($callback = null)
147
    {
148 4
        if ($count = $this->count()) {
149
            return $this->sum($callback) / $count;
150
        }
151 4
    }
152
153 4
    /**
154 4
     * Alias for the "avg" method.
155
     *
156 4
     * @param  callable|string|null  $callback
157 4
     * @return mixed
158
     */
159 1
    public function average($callback = null)
160
    {
161
        return $this->avg($callback);
162
    }
163
164
    /**
165
     * Get the median of a given key.
166
     *
167 3
     * @param  null $key
168
     * @return mixed
169 3
     */
170
    public function median($key = null)
171
    {
172
        $count = $this->count();
173
174
        if ($count == 0) {
175
            return;
176
        }
177
178 6
        $values = (isset($key) ? $this->pluck($key) : $this)
179
                    ->sort()->values();
180 6
181
        $middle = (int) ($count / 2);
182 5
183 6
        if ($count % 2) {
184
            return $values->get($middle);
185 6
        }
186
187 6
        return (new static([
188 1
            $values->get($middle - 1), $values->get($middle),
189
        ]))->average();
190
    }
191 5
192
    /**
193 5
     * Get the mode of a given key.
194 2
     *
195
     * @param  mixed  $key
196
     * @return array|null
197 3
     */
198 3
    public function mode($key = null)
199 3
    {
200
        $count = $this->count();
201
202
        if ($count == 0) {
203
            return;
204
        }
205
206
        $collection = isset($key) ? $this->pluck($key) : $this;
207
208 4
        $counts = new self;
209
210 4
        $collection->each(function ($value) use ($counts) {
211
            $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1;
212 4
        });
213 1
214
        $sorted = $counts->sort();
215
216 3
        $highestValue = $sorted->last();
217
218 3
        return $sorted->filter(function ($value) use ($highestValue) {
219
            return $value == $highestValue;
220
        })->sort()->keys()->all();
221 3
    }
222 3
223
    /**
224 3
     * Collapse the collection of items into a single array.
225
     *
226 3
     * @return static
227
     */
228
    public function collapse()
229 3
    {
230 3
        return new static(Arr::collapse($this->items));
231
    }
232
233
    /**
234
     * Determine if an item exists in the collection.
235
     *
236
     * @param  mixed  $key
237
     * @param  mixed  $operator
238 3
     * @param  mixed  $value
239
     * @return bool
240 3
     */
241
    public function contains($key, $operator = null, $value = null)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
242
    {
243
        if (func_num_args() === 1) {
244
            if ($this->useAsCallable($key)) {
245
                $placeholder = new stdClass;
246
247
                return $this->first($key, $placeholder) !== $placeholder;
248
            }
249
250
            return in_array($key, $this->items);
251 3
        }
252
253 3
        return $this->contains($this->operatorForWhere(...func_get_args()));
0 ignored issues
show
Bug introduced by
The call to operatorForWhere() misses a required argument $operator.

This check looks for function calls that miss required arguments.

Loading history...
Documentation introduced by
func_get_args() is of type array, but the function expects a string.

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...
254 3
    }
255 3
256
    /**
257 3
     * Determine if an item exists in the collection using strict comparison.
258
     *
259
     * @param  mixed  $key
260 1
     * @param  mixed  $value
261
     * @return bool
262
     */
263 2
    public function containsStrict($key, $value = null)
264
    {
265
        if (func_num_args() === 2) {
266
            return $this->contains(function ($item) use ($key, $value) {
267
                return data_get($item, $key) === $value;
268
            });
269
        }
270
271
        if ($this->useAsCallable($key)) {
272
            return ! is_null($this->first($key));
273 1
        }
274
275 1
        return in_array($key, $this->items, true);
276
    }
277 1
278 1
    /**
279
     * Cross join with the given lists, returning all possible permutations.
280
     *
281 1
     * @param  mixed  ...$lists
282 1
     * @return static
283
     */
284
    public function crossJoin(...$lists)
285 1
    {
286
        return new static(Arr::crossJoin(
287
            $this->items, ...array_map([$this, 'getArrayableItems'], $lists)
288
        ));
289
    }
290
291
    /**
292
     * Dump the collection and end the script.
293
     *
294 1
     * @return void
295
     */
296 1
    public function dd(...$args)
297 1
    {
298
        call_user_func_array([$this, 'dump'], $args);
299
300
        die(1);
301
    }
302
303
    /**
304
     * Dump the collection.
305
     *
306
     * @return $this
307
     */
308
    public function dump()
309
    {
310
        (new static(func_get_args()))
311
            ->push($this)
312
            ->each(function ($item) {
313
                (new Dumper)->dump($item);
314
            });
315
316
        return $this;
317
    }
318
319
    /**
320
     * Get the items in the collection that are not present in the given items.
321
     *
322
     * @param  mixed  $items
323
     * @return static
324
     */
325
    public function diff($items)
326
    {
327
        return new static(array_diff($this->items, $this->getArrayableItems($items)));
328
    }
329
330
    /**
331
     * Get the items in the collection that are not present in the given items.
332
     *
333
     * @param  mixed  $items
334
     * @param  callable  $callback
335 3
     * @return static
336
     */
337 3
    public function diffUsing($items, callable $callback)
338
    {
339
        return new static(array_udiff($this->items, $this->getArrayableItems($items), $callback));
340
    }
341
342
    /**
343
     * Get the items in the collection whose keys and values are not present in the given items.
344
     *
345
     * @param  mixed  $items
346
     * @return static
347 2
     */
348
    public function diffAssoc($items)
349 2
    {
350
        return new static(array_diff_assoc($this->items, $this->getArrayableItems($items)));
351
    }
352
353
    /**
354
     * Get the items in the collection whose keys and values are not present in the given items.
355
     *
356
     * @param  mixed  $items
357
     * @param  callable  $callback
358 2
     * @return static
359
     */
360 2
    public function diffAssocUsing($items, callable $callback)
361
    {
362
        return new static(array_diff_uassoc($this->items, $this->getArrayableItems($items), $callback));
363
    }
364
365
    /**
366
     * Get the items in the collection whose keys are not present in the given items.
367
     *
368
     * @param  mixed  $items
369
     * @return static
370 1
     */
371
    public function diffKeys($items)
372 1
    {
373
        return new static(array_diff_key($this->items, $this->getArrayableItems($items)));
374
    }
375
376
    /**
377
     * Get the items in the collection whose keys are not present in the given items.
378
     *
379
     * @param  mixed   $items
380
     * @param  callable  $callback
381 2
     * @return static
382
     */
383 2
    public function diffKeysUsing($items, callable $callback)
384
    {
385
        return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback));
386
    }
387
388
    /**
389
     * Execute a callback over each item.
390
     *
391
     * @param  callable  $callback
392
     * @return $this
393 1
     */
394
    public function each(callable $callback)
395 1
    {
396
        foreach ($this->items as $key => $item) {
397
            if ($callback($item, $key) === false) {
398
                break;
399
            }
400
        }
401
402
        return $this;
403
    }
404 7
405
    /**
406 7
     * Execute a callback over each nested chunk of items.
407 7
     *
408 7
     * @param  callable  $callback
409
     * @return static
410
     */
411
    public function eachSpread(callable $callback)
412 7
    {
413
        return $this->each(function ($chunk, $key) use ($callback) {
414
            $chunk[] = $key;
415
416
            return $callback(...$chunk);
417
        });
418
    }
419
420
    /**
421 1
     * Determine if all items in the collection pass the given test.
422
     *
423
     * @param  string|callable  $key
424 1
     * @param  mixed  $operator
425
     * @param  mixed  $value
426 1
     * @return bool
427 1
     */
428
    public function every($key, $operator = null, $value = null)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
429
    {
430
        if (func_num_args() === 1) {
431
            $callback = $this->valueRetriever($key);
0 ignored issues
show
Documentation introduced by
$key is of type callable, but the function expects a string.

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...
432
433
            foreach ($this->items as $k => $v) {
434
                if (! $callback($v, $k)) {
435
                    return false;
436
                }
437
            }
438 1
439
            return true;
440 1
        }
441 1
442
        return $this->every($this->operatorForWhere(...func_get_args()));
0 ignored issues
show
Bug introduced by
The call to operatorForWhere() misses a required argument $operator.

This check looks for function calls that miss required arguments.

Loading history...
Documentation introduced by
func_get_args() is of type array, but the function expects a string.

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...
443 1
    }
444 1
445 1
    /**
446
     * Get all items except for those with the specified keys.
447
     *
448
     * @param  \IlluminateAgnostic\Collection\Support\Collection|mixed  $keys
449 1
     * @return static
450
     */
451
    public function except($keys)
452 1
    {
453
        if ($keys instanceof self) {
454
            $keys = $keys->all();
455
        } elseif (! is_array($keys)) {
456
            $keys = func_get_args();
457
        }
458
459
        return new static(Arr::except($this->items, $keys));
460
    }
461 2
462
    /**
463 2
     * Run a filter over each of the items.
464 2
     *
465 1
     * @param  callable|null  $callback
466 1
     * @return static
467
     */
468
    public function filter(callable $callback = null)
469 2
    {
470
        if ($callback) {
471
            return new static(Arr::where($this->items, $callback));
472
        }
473
474
        return new static(array_filter($this->items));
475
    }
476
477
    /**
478 29
     * Apply the callback if the value is truthy.
479
     *
480 29
     * @param  bool  $value
481 29
     * @param  callable  $callback
482
     * @param  callable  $default
483
     * @return static|mixed
484 1
     */
485
    public function when($value, callable $callback, callable $default = null)
486
    {
487
        if ($value) {
488
            return $callback($this, $value);
489
        } elseif ($default) {
490
            return $default($this, $value);
491
        }
492
493
        return $this;
494
    }
495 4
496
    /**
497 4
     * Apply the callback if the value is falsy.
498 2
     *
499 4
     * @param  bool  $value
500 2
     * @param  callable  $callback
501
     * @param  callable  $default
502
     * @return static|mixed
503 2
     */
504
    public function unless($value, callable $callback, callable $default = null)
505
    {
506
        return $this->when(! $value, $callback, $default);
507
    }
508
509
    /**
510
     * Filter items by the given key value pair.
511
     *
512
     * @param  string  $key
513
     * @param  mixed  $operator
514 2
     * @param  mixed  $value
515
     * @return static
516 2
     */
517
    public function where($key, $operator, $value = null)
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
518
    {
519
        return $this->filter($this->operatorForWhere(...func_get_args()));
0 ignored issues
show
Bug introduced by
The call to operatorForWhere() misses a required argument $operator.

This check looks for function calls that miss required arguments.

Loading history...
Documentation introduced by
func_get_args() is of type array, but the function expects a string.

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...
520
    }
521
522
    /**
523
     * Get an operator checker callback.
524
     *
525
     * @param  string  $key
526
     * @param  string  $operator
527 2
     * @param  mixed  $value
528
     * @return \Closure
529 2
     */
530
    protected function operatorForWhere($key, $operator, $value = null)
531
    {
532
        if (func_num_args() === 2) {
533
            $value = $operator;
534
535
            $operator = '=';
536
        }
537
538
        return function ($item) use ($key, $operator, $value) {
539
            $retrieved = data_get($item, $key);
540 7
541
            $strings = array_filter([$retrieved, $value], function ($value) {
542 7
                return is_string($value) || (is_object($value) && method_exists($value, '__toString'));
543 1
            });
544
545 1
            if (count($strings) < 2 && count(array_filter([$retrieved, $value], 'is_object')) == 1) {
546
                return in_array($operator, ['!=', '<>', '!==']);
547
            }
548 7
549 5
            switch ($operator) {
550
                default:
551 5
                case '=':
552
                case '==':  return $retrieved == $value;
553
                case '!=':
554
                case '<>':  return $retrieved != $value;
555 7
                case '<':   return $retrieved < $value;
556
                case '>':   return $retrieved > $value;
557
                case '<=':  return $retrieved <= $value;
558 7
                case '>=':  return $retrieved >= $value;
559 7
                case '===': return $retrieved === $value;
560
                case '!==': return $retrieved !== $value;
561 7
            }
562 1
        };
563
    }
564
565 7
    /**
566
     * Filter items by the given key value pair using strict comparison.
567 7
     *
568 7
     * @param  string  $key
569 5
     * @param  mixed  $value
570 5
     * @return static
571 5
     */
572 5
    public function whereStrict($key, $value)
573 5
    {
574 5
        return $this->where($key, '===', $value);
575 3
    }
576 1
577
    /**
578 7
     * Filter items by the given key value pair.
579
     *
580
     * @param  string  $key
581
     * @param  mixed  $values
582
     * @param  bool  $strict
583
     * @return static
584
     */
585 View Code Duplication
    public function whereIn($key, $values, $strict = false)
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...
586
    {
587
        $values = $this->getArrayableItems($values);
588 1
589
        return $this->filter(function ($item) use ($key, $values, $strict) {
590 1
            return in_array(data_get($item, $key), $values, $strict);
591
        });
592
    }
593
594
    /**
595
     * Filter items by the given key value pair using strict comparison.
596
     *
597
     * @param  string  $key
598
     * @param  mixed  $values
599
     * @return static
600
     */
601 2
    public function whereInStrict($key, $values)
602
    {
603 2
        return $this->whereIn($key, $values, true);
604
    }
605
606 2
    /**
607 2
     * Filter items by the given key value pair.
608
     *
609
     * @param  string  $key
610
     * @param  mixed  $values
611
     * @param  bool  $strict
612
     * @return static
613
     */
614 View Code Duplication
    public function whereNotIn($key, $values, $strict = false)
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...
615
    {
616
        $values = $this->getArrayableItems($values);
617 1
618
        return $this->reject(function ($item) use ($key, $values, $strict) {
619 1
            return in_array(data_get($item, $key), $values, $strict);
620
        });
621
    }
622
623
    /**
624
     * Filter items by the given key value pair using strict comparison.
625
     *
626
     * @param  string  $key
627
     * @param  mixed  $values
628
     * @return static
629
     */
630 2
    public function whereNotInStrict($key, $values)
631
    {
632 2
        return $this->whereNotIn($key, $values, true);
633
    }
634
635 2
    /**
636 2
     * Filter the items, removing any items that don't match the given type.
637
     *
638
     * @param  string  $type
639
     * @return static
640
     */
641
    public function whereInstanceOf($type)
642
    {
643
        return $this->filter(function ($value) use ($type) {
644
            return $value instanceof $type;
645
        });
646 1
    }
647
648 1
    /**
649
     * Get the first item from the collection.
650
     *
651
     * @param  callable|null  $callback
652
     * @param  mixed  $default
653
     * @return mixed
654
     */
655
    public function first(callable $callback = null, $default = null)
656
    {
657 1
        return Arr::first($this->items, $callback, $default);
658
    }
659
660 1
    /**
661 1
     * Get the first item by the given key value pair.
662
     *
663
     * @param  string  $key
664
     * @param  mixed  $operator
665
     * @param  mixed  $value
666
     * @return static
667
     */
668
    public function firstWhere($key, $operator, $value = null)
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
669
    {
670
        return $this->first($this->operatorForWhere(...func_get_args()));
0 ignored issues
show
Bug introduced by
The call to operatorForWhere() misses a required argument $operator.

This check looks for function calls that miss required arguments.

Loading history...
Documentation introduced by
func_get_args() is of type array, but the function expects a string.

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...
671 11
    }
672
673 11
    /**
674
     * Get a flattened array of the items in the collection.
675
     *
676
     * @param  int  $depth
677
     * @return static
678
     */
679
    public function flatten($depth = INF)
680
    {
681
        return new static(Arr::flatten($this->items, $depth));
682
    }
683
684 1
    /**
685
     * Flip the items in the collection.
686 1
     *
687
     * @return static
688
     */
689
    public function flip()
690
    {
691
        return new static(array_flip($this->items));
692
    }
693
694
    /**
695 3
     * Remove an item from the collection by key.
696
     *
697 3
     * @param  string|array  $keys
698
     * @return $this
699
     */
700
    public function forget($keys)
701
    {
702
        foreach ((array) $keys as $key) {
703
            $this->offsetUnset($key);
704
        }
705 1
706
        return $this;
707 1
    }
708
709
    /**
710
     * Get an item from the collection by key.
711
     *
712
     * @param  mixed  $key
713
     * @param  mixed  $default
714
     * @return mixed
715
     */
716 2
    public function get($key, $default = null)
717
    {
718 2
        if ($this->offsetExists($key)) {
719 2
            return $this->items[$key];
720
        }
721
722 2
        return value($default);
723
    }
724
725
    /**
726
     * Group an associative array by a field or using a callback.
727
     *
728
     * @param  callable|string  $groupBy
729
     * @param  bool  $preserveKeys
730
     * @return static
731
     */
732 6
    public function groupBy($groupBy, $preserveKeys = false)
733
    {
734 6
        if (is_array($groupBy)) {
735 5
            $nextGroups = $groupBy;
736
737
            $groupBy = array_shift($nextGroups);
738 1
        }
739
740
        $groupBy = $this->valueRetriever($groupBy);
741
742
        $results = [];
743
744
        foreach ($this->items as $key => $value) {
745
            $groupKeys = $groupBy($value, $key);
746
747
            if (! is_array($groupKeys)) {
748 8
                $groupKeys = [$groupKeys];
749
            }
750 8
751 1
            foreach ($groupKeys as $groupKey) {
752
                $groupKey = is_bool($groupKey) ? (int) $groupKey : $groupKey;
753 1
754
                if (! array_key_exists($groupKey, $results)) {
755
                    $results[$groupKey] = new static;
756 8
                }
757
758 8
                $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);
759
            }
760 8
        }
761 8
762
        $result = new static($results);
763 8
764 6
        if (! empty($nextGroups)) {
765
            return $result->map->groupBy($nextGroups, $preserveKeys);
0 ignored issues
show
Documentation Bug introduced by
The method groupBy does not exist on object<IlluminateAgnosti...erOrderCollectionProxy>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
766
        }
767 8
768 8
        return $result;
769
    }
770 8
771 8
    /**
772
     * Key an associative array by a field or using a callback.
773
     *
774 8
     * @param  callable|string  $keyBy
775
     * @return static
776
     */
777
    public function keyBy($keyBy)
778 8
    {
779
        $keyBy = $this->valueRetriever($keyBy);
0 ignored issues
show
Documentation introduced by
$keyBy is of type callable, but the function expects a string.

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...
780 8
781 1
        $results = [];
782
783
        foreach ($this->items as $key => $item) {
784 8
            $resolvedKey = $keyBy($item, $key);
785
786
            if (is_object($resolvedKey)) {
787
                $resolvedKey = (string) $resolvedKey;
788
            }
789
790
            $results[$resolvedKey] = $item;
791
        }
792
793 3
        return new static($results);
794
    }
795 3
796
    /**
797 3
     * Determine if an item exists in the collection by key.
798
     *
799 3
     * @param  mixed  $key
800 3
     * @return bool
801
     */
802 3
    public function has($key)
803
    {
804
        $keys = is_array($key) ? $key : func_get_args();
805
806 3
        foreach ($keys as $value) {
807
            if (! $this->offsetExists($value)) {
808
                return false;
809 3
            }
810
        }
811
812
        return true;
813
    }
814
815
    /**
816
     * Concatenate values of a given key as a string.
817
     *
818 2
     * @param  string  $value
819
     * @param  string  $glue
820 2
     * @return string
821
     */
822 2
    public function implode($value, $glue = null)
823 2
    {
824 2
        $first = $this->first();
825
826
        if (is_array($first) || is_object($first)) {
827
            return implode($glue, $this->pluck($value)->all());
828 2
        }
829
830
        return implode($value, $this->items);
831
    }
832
833
    /**
834
     * Intersect the collection with the given items.
835
     *
836
     * @param  mixed  $items
837
     * @return static
838 1
     */
839
    public function intersect($items)
840 1
    {
841
        return new static(array_intersect($this->items, $this->getArrayableItems($items)));
842 1
    }
843 1
844
    /**
845
     * Intersect the collection with the given items by key.
846 1
     *
847
     * @param  mixed  $items
848
     * @return static
849
     */
850
    public function intersectByKeys($items)
851
    {
852
        return new static(array_intersect_key(
853
            $this->items, $this->getArrayableItems($items)
854
        ));
855 2
    }
856
857 2
    /**
858
     * Determine if the collection is empty or not.
859
     *
860
     * @return bool
861
     */
862
    public function isEmpty()
863
    {
864
        return empty($this->items);
865
    }
866 2
867
    /**
868 2
     * Determine if the collection is not empty.
869 2
     *
870
     * @return bool
871
     */
872
    public function isNotEmpty()
873
    {
874
        return ! $this->isEmpty();
875
    }
876
877
    /**
878 10
     * Determine if the given value is callable, but not a string.
879
     *
880 10
     * @param  mixed  $value
881
     * @return bool
882
     */
883
    protected function useAsCallable($value)
884
    {
885
        return ! is_string($value) && is_callable($value);
886
    }
887
888 1
    /**
889
     * Get the keys of the collection items.
890 1
     *
891
     * @return static
892
     */
893
    public function keys()
894
    {
895
        return new static(array_keys($this->items));
896
    }
897
898
    /**
899 44
     * Get the last item from the collection.
900
     *
901 44
     * @param  callable|null  $callback
902
     * @param  mixed  $default
903
     * @return mixed
904
     */
905
    public function last(callable $callback = null, $default = null)
906
    {
907
        return Arr::last($this->items, $callback, $default);
908
    }
909 6
910
    /**
911 6
     * Get the values of a given key.
912
     *
913
     * @param  string|array  $value
914
     * @param  string|null  $key
915
     * @return static
916
     */
917
    public function pluck($value, $key = null)
918
    {
919
        return new static(Arr::pluck($this->items, $value, $key));
920
    }
921 7
922
    /**
923 7
     * Run a map over each of the items.
924
     *
925
     * @param  callable  $callback
926
     * @return static
927
     */
928
    public function map(callable $callback)
929
    {
930
        $keys = array_keys($this->items);
931
932
        $items = array_map($callback, $this->items, $keys);
933 10
934
        return new static(array_combine($keys, $items));
935 10
    }
936
937
    /**
938
     * Run a map over each nested chunk of items.
939
     *
940
     * @param  callable  $callback
941
     * @return static
942
     */
943
    public function mapSpread(callable $callback)
944 24
    {
945
        return $this->map(function ($chunk, $key) use ($callback) {
946 24
            $chunk[] = $key;
947
948 24
            return $callback(...$chunk);
949
        });
950 24
    }
951
952
    /**
953
     * Run a dictionary map over the items.
954
     *
955
     * The callback should return an associative array with a single key/value pair.
956
     *
957
     * @param  callable  $callback
958
     * @return static
959 1
     */
960
    public function mapToDictionary(callable $callback)
961
    {
962 1
        $dictionary = [];
963
964 1
        foreach ($this->items as $key => $item) {
965 1
            $pair = $callback($item, $key);
966
967
            $key = key($pair);
968
969
            $value = reset($pair);
970
971
            if (! isset($dictionary[$key])) {
972
                $dictionary[$key] = [];
973
            }
974
975
            $dictionary[$key][] = $value;
976 4
        }
977
978 4
        return new static($dictionary);
979
    }
980 4
981 4
    /**
982
     * Run a grouping map over the items.
983 4
     *
984
     * The callback should return an associative array with a single key/value pair.
985 4
     *
986
     * @param  callable  $callback
987 4
     * @return static
988 4
     */
989
    public function mapToGroups(callable $callback)
990
    {
991 4
        $groups = $this->mapToDictionary($callback);
992
993
        return $groups->map([$this, 'make']);
994 4
    }
995
996
    /**
997
     * Run an associative map over each of the items.
998
     *
999
     * The callback should return an associative array with a single key/value pair.
1000
     *
1001
     * @param  callable  $callback
1002
     * @return static
1003
     */
1004
    public function mapWithKeys(callable $callback)
1005 2
    {
1006
        $result = [];
1007 2
1008
        foreach ($this->items as $key => $value) {
1009 2
            $assoc = $callback($value, $key);
1010
1011
            foreach ($assoc as $mapKey => $mapValue) {
1012
                $result[$mapKey] = $mapValue;
1013
            }
1014
        }
1015
1016
        return new static($result);
1017
    }
1018
1019
    /**
1020 5
     * Map a collection and flatten the result by a single level.
1021
     *
1022 5
     * @param  callable  $callback
1023
     * @return static
1024 5
     */
1025 5
    public function flatMap(callable $callback)
1026
    {
1027 5
        return $this->map($callback)->collapse();
1028 5
    }
1029
1030
    /**
1031
     * Map the values into a new class.
1032 5
     *
1033
     * @param  string  $class
1034
     * @return static
1035
     */
1036
    public function mapInto($class)
1037
    {
1038
        return $this->map(function ($value, $key) use ($class) {
1039
            return new $class($value, $key);
1040
        });
1041 1
    }
1042
1043 1
    /**
1044
     * Get the max value of a given key.
1045
     *
1046
     * @param  callable|string|null  $callback
1047
     * @return mixed
1048
     */
1049 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...
1050
    {
1051
        $callback = $this->valueRetriever($callback);
0 ignored issues
show
Documentation introduced by
$callback is of type callable|null, but the function expects a string.

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...
1052 1
1053
        return $this->filter(function ($value) {
1054
            return ! is_null($value);
1055 1
        })->reduce(function ($result, $item) use ($callback) {
1056 1
            $value = $callback($item);
1057
1058
            return is_null($result) || $value > $result ? $value : $result;
1059
        });
1060
    }
1061
1062
    /**
1063
     * Merge the collection with the given items.
1064
     *
1065 1
     * @param  mixed  $items
1066
     * @return static
1067 1
     */
1068
    public function merge($items)
1069
    {
1070 1
        return new static(array_merge($this->items, $this->getArrayableItems($items)));
1071
    }
1072 1
1073
    /**
1074 1
     * Create a collection by using this collection for keys and another for its values.
1075 1
     *
1076
     * @param  mixed  $values
1077
     * @return static
1078
     */
1079
    public function combine($values)
1080
    {
1081
        return new static(array_combine($this->all(), $this->getArrayableItems($values)));
1082
    }
1083
1084 3
    /**
1085
     * Union the collection with the given items.
1086 3
     *
1087
     * @param  mixed  $items
1088
     * @return static
1089
     */
1090
    public function union($items)
1091
    {
1092
        return new static($this->items + $this->getArrayableItems($items));
1093
    }
1094
1095 2
    /**
1096
     * Get the min value of a given key.
1097 2
     *
1098
     * @param  callable|string|null  $callback
1099
     * @return mixed
1100
     */
1101 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...
1102
    {
1103
        $callback = $this->valueRetriever($callback);
0 ignored issues
show
Documentation introduced by
$callback is of type callable|null, but the function expects a string.

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...
1104
1105
        return $this->filter(function ($value) {
1106 3
            return ! is_null($value);
1107
        })->reduce(function ($result, $item) use ($callback) {
1108 3
            $value = $callback($item);
1109
1110
            return is_null($result) || $value < $result ? $value : $result;
1111
        });
1112
    }
1113
1114
    /**
1115
     * Create a new collection consisting of every n-th element.
1116
     *
1117 1
     * @param  int  $step
1118
     * @param  int  $offset
1119 1
     * @return static
1120
     */
1121
    public function nth($step, $offset = 0)
1122 1
    {
1123
        $new = [];
1124 1
1125
        $position = 0;
1126 1
1127 1
        foreach ($this->items as $item) {
1128
            if ($position % $step === $offset) {
1129
                $new[] = $item;
1130
            }
1131
1132
            $position++;
1133
        }
1134
1135
        return new static($new);
1136
    }
1137 1
1138
    /**
1139 1
     * Get the items with the specified keys.
1140
     *
1141 1
     * @param  mixed  $keys
1142
     * @return static
1143 1
     */
1144 1
    public function only($keys)
1145 1
    {
1146
        if (is_null($keys)) {
1147
            return new static($this->items);
1148 1
        }
1149
1150
        if ($keys instanceof self) {
1151 1
            $keys = $keys->all();
1152
        }
1153
1154
        $keys = is_array($keys) ? $keys : func_get_args();
1155
1156
        return new static(Arr::only($this->items, $keys));
1157
    }
1158
1159
    /**
1160 1
     * "Paginate" the collection by slicing it into a smaller collection.
1161
     *
1162 1
     * @param  int  $page
1163 1
     * @param  int  $perPage
1164
     * @return static
1165
     */
1166 1
    public function forPage($page, $perPage)
1167 1
    {
1168
        $offset = max(0, ($page - 1) * $perPage);
1169
1170 1
        return $this->slice($offset, $perPage);
1171
    }
1172 1
1173
    /**
1174
     * Partition the collection into two arrays using the given callback or key.
1175
     *
1176
     * @param  callable|string  $key
1177
     * @param  mixed  $operator
1178
     * @param  mixed  $value
1179
     * @return static
1180
     */
1181
    public function partition($key, $operator = null, $value = null)
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1182 1
    {
1183
        $partitions = [new static, new static];
1184 1
1185
        $callback = func_num_args() === 1
1186 1
                ? $this->valueRetriever($key)
0 ignored issues
show
Documentation introduced by
$key is of type callable, but the function expects a string.

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...
1187
                : $this->operatorForWhere(...func_get_args());
0 ignored issues
show
Bug introduced by
The call to operatorForWhere() misses a required argument $operator.

This check looks for function calls that miss required arguments.

Loading history...
Documentation introduced by
func_get_args() is of type array, but the function expects a string.

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...
1188
1189
        foreach ($this->items as $key => $item) {
1190
            $partitions[(int) ! $callback($item, $key)][$key] = $item;
1191
        }
1192
1193
        return new static($partitions);
1194
    }
1195
1196
    /**
1197 7
     * Pass the collection to the given callback and return the result.
1198
     *
1199 7
     * @param  callable $callback
1200
     * @return mixed
1201 7
     */
1202 6
    public function pipe(callable $callback)
1203 7
    {
1204
        return $callback($this);
1205 7
    }
1206 6
1207
    /**
1208
     * Get and remove the last item from the collection.
1209 7
     *
1210
     * @return mixed
1211
     */
1212
    public function pop()
1213
    {
1214
        return array_pop($this->items);
1215
    }
1216
1217
    /**
1218 1
     * Push an item onto the beginning of the collection.
1219
     *
1220 1
     * @param  mixed  $value
1221
     * @param  mixed  $key
1222
     * @return $this
1223
     */
1224
    public function prepend($value, $key = null)
1225
    {
1226
        $this->items = Arr::prepend($this->items, $value, $key);
1227
1228 1
        return $this;
1229
    }
1230 1
1231
    /**
1232
     * Push an item onto the end of the collection.
1233
     *
1234
     * @param  mixed  $value
1235
     * @return $this
1236
     */
1237
    public function push($value)
1238
    {
1239
        $this->offsetSet(null, $value);
1240 1
1241
        return $this;
1242 1
    }
1243
1244 1
    /**
1245
     * Push all of the given items onto the collection.
1246
     *
1247
     * @param  \Traversable|array  $source
1248
     * @return static
1249
     */
1250
    public function concat($source)
1251
    {
1252
        $result = new static($this);
1253 13
1254
        foreach ($source as $item) {
1255 13
            $result->push($item);
1256
        }
1257 13
1258
        return $result;
1259
    }
1260
1261
    /**
1262
     * Get and remove an item from the collection.
1263
     *
1264
     * @param  mixed  $key
1265
     * @param  mixed  $default
1266 2
     * @return mixed
1267
     */
1268 2
    public function pull($key, $default = null)
1269
    {
1270 2
        return Arr::pull($this->items, $key, $default);
1271 2
    }
1272
1273
    /**
1274 2
     * Put an item in the collection by key.
1275
     *
1276
     * @param  mixed  $key
1277
     * @param  mixed  $value
1278
     * @return $this
1279
     */
1280
    public function put($key, $value)
1281
    {
1282
        $this->offsetSet($key, $value);
1283
1284 3
        return $this;
1285
    }
1286 3
1287
    /**
1288
     * Get one or a specified number of items randomly from the collection.
1289
     *
1290
     * @param  int|null  $number
1291
     * @return static|mixed
1292
     *
1293
     * @throws \InvalidArgumentException
1294
     */
1295
    public function random($number = null)
1296 3
    {
1297
        if (is_null($number)) {
1298 3
            return Arr::random($this->items);
1299
        }
1300 3
1301
        return new static(Arr::random($this->items, $number));
1302
    }
1303
1304
    /**
1305
     * Reduce the collection to a single value.
1306
     *
1307
     * @param  callable  $callback
1308
     * @param  mixed  $initial
1309
     * @return mixed
1310
     */
1311 3
    public function reduce(callable $callback, $initial = null)
1312
    {
1313 3
        return array_reduce($this->items, $callback, $initial);
1314 1
    }
1315
1316
    /**
1317 3
     * Create a collection of all elements that do not pass a given truth test.
1318
     *
1319
     * @param  callable|mixed  $callback
1320
     * @return static
1321
     */
1322
    public function reject($callback)
1323
    {
1324
        if ($this->useAsCallable($callback)) {
1325
            return $this->filter(function ($value, $key) use ($callback) {
1326
                return ! $callback($value, $key);
1327 5
            });
1328
        }
1329 5
1330
        return $this->filter(function ($item) use ($callback) {
1331
            return $item != $callback;
1332
        });
1333
    }
1334
1335
    /**
1336
     * Reverse items order.
1337
     *
1338 8
     * @return static
1339
     */
1340 8
    public function reverse()
1341
    {
1342 8
        return new static(array_reverse($this->items, true));
1343 8
    }
1344
1345
    /**
1346
     * Search the collection for a given value and return the corresponding key if successful.
1347 1
     *
1348 1
     * @param  mixed  $value
1349
     * @param  bool  $strict
1350
     * @return mixed
1351
     */
1352
    public function search($value, $strict = false)
1353
    {
1354
        if (! $this->useAsCallable($value)) {
1355
            return array_search($value, $this->items, $strict);
1356 1
        }
1357
1358 1
        foreach ($this->items as $key => $item) {
1359
            if (call_user_func($value, $item, $key)) {
1360
                return $key;
1361
            }
1362
        }
1363
1364
        return false;
1365
    }
1366
1367
    /**
1368 2
     * Get and remove the first item from the collection.
1369
     *
1370 2
     * @return mixed
1371 2
     */
1372
    public function shift()
1373
    {
1374 2
        return array_shift($this->items);
1375 2
    }
1376 2
1377
    /**
1378
     * Shuffle the items in the collection.
1379
     *
1380 1
     * @param  int  $seed
1381
     * @return static
1382
     */
1383
    public function shuffle($seed = null)
1384
    {
1385
        return new static(Arr::shuffle($this->items, $seed));
1386
    }
1387
1388 1
    /**
1389
     * Slice the underlying collection array.
1390 1
     *
1391
     * @param  int  $offset
1392
     * @param  int  $length
1393
     * @return static
1394
     */
1395
    public function slice($offset, $length = null)
1396
    {
1397
        return new static(array_slice($this->items, $offset, $length, true));
1398
    }
1399 1
1400
    /**
1401 1
     * Split a collection into a certain number of groups.
1402
     *
1403
     * @param  int  $numberOfGroups
1404
     * @return static
1405
     */
1406
    public function split($numberOfGroups)
1407
    {
1408
        if ($this->isEmpty()) {
1409
            return new static;
1410
        }
1411 10
1412
        $groupSize = ceil($this->count() / $numberOfGroups);
1413 10
1414
        return $this->chunk($groupSize);
1415
    }
1416
1417
    /**
1418
     * Chunk the underlying collection array.
1419
     *
1420
     * @param  int  $size
1421
     * @return static
1422 7
     */
1423
    public function chunk($size)
1424 7
    {
1425 1
        if ($size <= 0) {
1426
            return new static;
1427
        }
1428 6
1429
        $chunks = [];
1430 6
1431
        foreach (array_chunk($this->items, $size, true) as $chunk) {
1432 6
            $chunks[] = new static($chunk);
1433
        }
1434 6
1435
        return new static($chunks);
1436 6
    }
1437 6
1438
    /**
1439 6
     * Sort through each item with a callback.
1440 5
     *
1441
     * @param  callable|null  $callback
1442
     * @return static
1443 6
     */
1444 6
    public function sort(callable $callback = null)
1445
    {
1446 6
        $items = $this->items;
1447
1448
        $callback
1449
            ? uasort($items, $callback)
1450 6
            : asort($items);
1451
1452
        return new static($items);
1453
    }
1454
1455
    /**
1456
     * Sort the collection using the given callback.
1457
     *
1458
     * @param  callable|string  $callback
1459 3
     * @param  int  $options
1460
     * @param  bool  $descending
1461 3
     * @return static
1462 2
     */
1463
    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
1464
    {
1465 1
        $results = [];
1466
1467 1
        $callback = $this->valueRetriever($callback);
0 ignored issues
show
Documentation introduced by
$callback is of type callable, but the function expects a string.

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...
1468 1
1469
        // First we will loop through the items and get the comparator from a callback
1470
        // function which we were given. Then, we will sort the returned values and
1471 1
        // and grab the corresponding values for the sorted keys from this array.
1472
        foreach ($this->items as $key => $value) {
1473
            $results[$key] = $callback($value, $key);
1474
        }
1475
1476
        $descending ? arsort($results, $options)
1477
            : asort($results, $options);
1478
1479
        // Once we have sorted all of the keys in the array, we will loop through them
1480 11
        // and grab the corresponding model so we can set the underlying items list
1481
        // to the sorted version. Then we'll just return the collection instance.
1482 11
        foreach (array_keys($results) as $key) {
1483
            $results[$key] = $this->items[$key];
1484 11
        }
1485 1
1486 10
        return new static($results);
1487
    }
1488 11
1489
    /**
1490
     * Sort the collection in descending order using the given callback.
1491
     *
1492
     * @param  callable|string  $callback
1493
     * @param  int  $options
1494
     * @return static
1495
     */
1496
    public function sortByDesc($callback, $options = SORT_REGULAR)
1497
    {
1498
        return $this->sortBy($callback, $options, true);
1499 5
    }
1500
1501 5
    /**
1502
     * Sort the collection keys.
1503 5
     *
1504
     * @param  int  $options
1505
     * @param  bool  $descending
1506
     * @return static
1507
     */
1508 5
    public function sortKeys($options = SORT_REGULAR, $descending = false)
1509 5
    {
1510
        $items = $this->items;
1511
1512 5
        $descending ? krsort($items, $options) : ksort($items, $options);
1513 5
1514
        return new static($items);
1515
    }
1516
1517
    /**
1518 5
     * Sort the collection keys in descending order.
1519 5
     *
1520
     * @param  int $options
1521
     * @return static
1522 5
     */
1523
    public function sortKeysDesc($options = SORT_REGULAR)
1524
    {
1525
        return $this->sortKeys($options, true);
1526
    }
1527
1528
    /**
1529
     * Splice a portion of the underlying collection array.
1530
     *
1531
     * @param  int  $offset
1532 1
     * @param  int|null  $length
1533
     * @param  mixed  $replacement
1534 1
     * @return static
1535
     */
1536
    public function splice($offset, $length = null, $replacement = [])
1537
    {
1538
        if (func_num_args() === 1) {
1539
            return new static(array_splice($this->items, $offset));
1540
        }
1541
1542
        return new static(array_splice($this->items, $offset, $length, $replacement));
1543
    }
1544 2
1545
    /**
1546 2
     * Get the sum of the given values.
1547
     *
1548 2
     * @param  callable|string|null  $callback
1549
     * @return mixed
1550 2
     */
1551
    public function sum($callback = null)
1552
    {
1553
        if (is_null($callback)) {
1554
            return array_sum($this->items);
1555
        }
1556
1557
        $callback = $this->valueRetriever($callback);
0 ignored issues
show
Documentation introduced by
$callback is of type callable, but the function expects a string.

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...
1558
1559
        return $this->reduce(function ($result, $item) use ($callback) {
1560
            return $result + $callback($item);
1561
        }, 0);
1562
    }
1563
1564
    /**
1565
     * Take the first or last {$limit} items.
1566
     *
1567
     * @param  int  $limit
1568
     * @return static
1569
     */
1570
    public function take($limit)
1571
    {
1572 1
        if ($limit < 0) {
1573
            return $this->slice($limit, abs($limit));
1574 1
        }
1575 1
1576
        return $this->slice(0, $limit);
1577
    }
1578 1
1579
    /**
1580
     * Pass the collection to the given callback and then return it.
1581
     *
1582
     * @param  callable  $callback
1583
     * @return $this
1584
     */
1585
    public function tap(callable $callback)
1586
    {
1587 8
        $callback(new static($this->items));
1588
1589 8
        return $this;
1590 6
    }
1591
1592
    /**
1593 2
     * Transform each item in the collection using a callback.
1594
     *
1595
     * @param  callable  $callback
1596 1
     * @return $this
1597 2
     */
1598
    public function transform(callable $callback)
1599
    {
1600
        $this->items = $this->map($callback)->all();
1601
1602
        return $this;
1603
    }
1604
1605
    /**
1606 2
     * Return only unique items from the collection array.
1607
     *
1608 2
     * @param  string|callable|null  $key
1609 1
     * @param  bool  $strict
1610
     * @return static
1611
     */
1612 1
    public function unique($key = null, $strict = false)
1613
    {
1614
        $callback = $this->valueRetriever($key);
0 ignored issues
show
Documentation introduced by
$key is of type callable|null, but the function expects a string.

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...
1615
1616
        $exists = [];
1617
1618
        return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) {
1619
            if (in_array($id = $callback($item, $key), $exists, $strict)) {
1620
                return true;
1621 1
            }
1622
1623 1
            $exists[] = $id;
1624
        });
1625 1
    }
1626
1627
    /**
1628
     * Return only unique items from the collection array using strict comparison.
1629
     *
1630
     * @param  string|callable|null  $key
1631
     * @return static
1632
     */
1633
    public function uniqueStrict($key = null)
1634 1
    {
1635
        return $this->unique($key, true);
1636 1
    }
1637
1638 1
    /**
1639
     * Reset the keys on the underlying array.
1640
     *
1641
     * @return static
1642
     */
1643
    public function values()
1644
    {
1645
        return new static(array_values($this->items));
1646
    }
1647
1648 5
    /**
1649
     * Get a value retrieving callback.
1650 5
     *
1651
     * @param  string  $value
1652 5
     * @return callable
1653
     */
1654
    protected function valueRetriever($value)
1655 5
    {
1656 5
        if ($this->useAsCallable($value)) {
1657
            return $value;
1658
        }
1659 5
1660 5
        return function ($item) use ($value) {
1661
            return data_get($item, $value);
1662
        };
1663
    }
1664
1665
    /**
1666
     * Zip the collection together with one or more arrays.
1667
     *
1668
     * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1669 1
     *      => [[1, 4], [2, 5], [3, 6]]
1670
     *
1671 1
     * @param  mixed ...$items
1672
     * @return static
1673
     */
1674
    public function zip($items)
0 ignored issues
show
Unused Code introduced by
The parameter $items is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1675
    {
1676
        $arrayableItems = array_map(function ($items) {
1677
            return $this->getArrayableItems($items);
1678
        }, func_get_args());
1679 37
1680
        $params = array_merge([function () {
1681 37
            return new static(func_get_args());
1682
        }, $this->items], $arrayableItems);
1683
1684
        return new static(call_user_func_array('array_map', $params));
1685
    }
1686
1687
    /**
1688
     * Pad collection to the specified length with a value.
1689
     *
1690 36
     * @param  int  $size
1691
     * @param  mixed  $value
1692 36
     * @return static
1693 23
     */
1694
    public function pad($size, $value)
1695
    {
1696
        return new static(array_pad($this->items, $size, $value));
1697 21
    }
1698 22
1699
    /**
1700
     * Get the collection of items as a plain array.
1701
     *
1702
     * @return array
1703
     */
1704
    public function toArray()
1705
    {
1706
        return array_map(function ($value) {
1707
            return $value instanceof Arrayable ? $value->toArray() : $value;
1708
        }, $this->items);
1709
    }
1710 1
1711
    /**
1712
     * Convert the object into something JSON serializable.
1713 1
     *
1714 1
     * @return array
1715
     */
1716
    public function jsonSerialize()
1717 1
    {
1718 1
        return array_map(function ($value) {
1719
            if ($value instanceof JsonSerializable) {
1720 1
                return $value->jsonSerialize();
1721
            } elseif ($value instanceof Jsonable) {
1722
                return json_decode($value->toJson(), true);
1723
            } elseif ($value instanceof Arrayable) {
1724
                return $value->toArray();
1725
            }
1726
1727
            return $value;
1728
        }, $this->items);
1729
    }
1730 1
1731
    /**
1732 1
     * Get the collection of items as JSON.
1733
     *
1734
     * @param  int  $options
1735
     * @return string
1736
     */
1737
    public function toJson($options = 0)
1738
    {
1739
        return json_encode($this->jsonSerialize(), $options);
1740 52
    }
1741
1742
    /**
1743 49
     * Get an iterator for the items.
1744 52
     *
1745
     * @return \ArrayIterator
1746
     */
1747
    public function getIterator()
1748
    {
1749
        return new ArrayIterator($this->items);
1750
    }
1751
1752 2
    /**
1753
     * Get a CachingIterator instance.
1754
     *
1755 2
     * @param  int  $flags
1756 2
     * @return \CachingIterator
1757 2
     */
1758 1
    public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
1759 2
    {
1760 2
        return new CachingIterator($this->getIterator(), $flags);
1761
    }
1762
1763 1
    /**
1764 2
     * Count the number of items in the collection.
1765
     *
1766
     * @return int
1767
     */
1768
    public function count()
1769
    {
1770
        return count($this->items);
1771
    }
1772
1773 2
    /**
1774
     * Get a base Support collection instance from this collection.
1775 2
     *
1776
     * @return \IlluminateAgnostic\Collection\Support\Collection
1777
     */
1778
    public function toBase()
1779
    {
1780
        return new self($this);
1781
    }
1782
1783 5
    /**
1784
     * Determine if an item exists at an offset.
1785 5
     *
1786
     * @param  mixed  $key
1787
     * @return bool
1788
     */
1789
    public function offsetExists($key)
1790
    {
1791
        return array_key_exists($key, $this->items);
1792
    }
1793
1794 1
    /**
1795
     * Get an item at a given offset.
1796 1
     *
1797
     * @param  mixed  $key
1798
     * @return mixed
1799
     */
1800
    public function offsetGet($key)
1801
    {
1802
        return $this->items[$key];
1803
    }
1804 26
1805
    /**
1806 26
     * Set the item at a given offset.
1807
     *
1808
     * @param  mixed  $key
1809
     * @param  mixed  $value
1810
     * @return void
1811
     */
1812
    public function offsetSet($key, $value)
1813
    {
1814
        if (is_null($key)) {
1815
            $this->items[] = $value;
1816
        } else {
1817
            $this->items[$key] = $value;
1818
        }
1819
    }
1820
1821
    /**
1822
     * Unset the item at a given offset.
1823
     *
1824
     * @param  string  $key
1825 17
     * @return void
1826
     */
1827 17
    public function offsetUnset($key)
1828
    {
1829
        unset($this->items[$key]);
1830
    }
1831
1832
    /**
1833
     * Convert the collection to its string representation.
1834
     *
1835
     * @return string
1836 18
     */
1837
    public function __toString()
1838 18
    {
1839
        return $this->toJson();
1840
    }
1841
1842
    /**
1843
     * Results array of items from Collection or Arrayable.
1844
     *
1845
     * @param  mixed  $items
1846
     * @return array
1847
     */
1848 37
    protected function getArrayableItems($items)
1849
    {
1850 37
        if (is_array($items)) {
1851 22
            return $items;
1852
        } elseif ($items instanceof self) {
1853 17
            return $items->all();
1854
        } elseif ($items instanceof Arrayable) {
1855 37
            return $items->toArray();
1856
        } elseif ($items instanceof Jsonable) {
1857
            return json_decode($items->toJson(), true);
1858
        } elseif ($items instanceof JsonSerializable) {
1859
            return $items->jsonSerialize();
1860
        } elseif ($items instanceof Traversable) {
1861
            return iterator_to_array($items);
1862
        }
1863 4
1864
        return (array) $items;
1865 4
    }
1866 4
1867
    /**
1868
     * Add a method to the list of proxied methods.
1869
     *
1870
     * @param  string  $method
1871
     * @return void
1872
     */
1873 1
    public static function proxy($method)
1874
    {
1875 1
        static::$proxies[] = $method;
1876
    }
1877
1878
    /**
1879
     * Dynamically access collection proxies.
1880
     *
1881
     * @param  string  $key
1882
     * @return mixed
1883
     *
1884 221
     * @throws \Exception
1885
     */
1886 221
    public function __get($key)
1887 215
    {
1888 35
        if (! in_array($key, static::$proxies)) {
1889 20
            throw new Exception("Property [{$key}] does not exist on this collection instance.");
1890 16
        }
1891 1
1892 16
        return new HigherOrderCollectionProxy($this, $key);
1893 1
    }
1894
}
1895