Completed
Push — master ( a7bdd4...c7897e )
by Antonio Carlos
03:18
created

Collection::keyBy()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

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