Completed
Push — master ( 1a51b8...a7bdd4 )
by Antonio Carlos
01:51
created

Collection::zip()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 12
ccs 6
cts 6
cp 1
crap 1
rs 9.8666
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 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
        $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
212 4
        if ($count == 0) {
213 1
            return;
214
        }
215
216 3
        $collection = isset($key) ? $this->pluck($key) : $this;
217
218 3
        $counts = new self;
219
220
        $collection->each(function ($value) use ($counts) {
221 3
            $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1;
222 3
        });
223
224 3
        $sorted = $counts->sort();
225
226 3
        $highestValue = $sorted->last();
227
228
        return $sorted->filter(function ($value) use ($highestValue) {
229 3
            return $value == $highestValue;
230 3
        })->sort()->keys()->all();
231
    }
232
233
    /**
234
     * Collapse the collection of items into a single array.
235
     *
236
     * @return static
237
     */
238 3
    public function collapse()
239
    {
240 3
        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
     * @return bool
250
     */
251 3
    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 3
        if (func_num_args() === 1) {
254 3
            if ($this->useAsCallable($key)) {
255 3
                $placeholder = new stdClass;
256
257 3
                return $this->first($key, $placeholder) !== $placeholder;
258
            }
259
260 1
            return in_array($key, $this->items);
261
        }
262
263 2
        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
    }
265
266
    /**
267
     * Determine if an item exists in the collection using strict comparison.
268
     *
269
     * @param  mixed  $key
270
     * @param  mixed  $value
271
     * @return bool
272
     */
273 1
    public function containsStrict($key, $value = null)
274
    {
275 1
        if (func_num_args() === 2) {
276
            return $this->contains(function ($item) use ($key, $value) {
277 1
                return data_get($item, $key) === $value;
278 1
            });
279
        }
280
281 1
        if ($this->useAsCallable($key)) {
282 1
            return ! is_null($this->first($key));
283
        }
284
285 1
        return in_array($key, $this->items, true);
286
    }
287
288
    /**
289
     * Cross join with the given lists, returning all possible permutations.
290
     *
291
     * @param  mixed  ...$lists
292
     * @return static
293
     */
294 1
    public function crossJoin(...$lists)
295
    {
296 1
        return new static(Arr::crossJoin(
297 1
            $this->items, ...array_map([$this, 'getArrayableItems'], $lists)
298
        ));
299
    }
300
301
    /**
302
     * Dump the collection and end the script.
303
     *
304
     * @return void
305
     */
306
    public function dd(...$args)
307
    {
308
        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 3
    public function diff($items)
336
    {
337 3
        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 2
    public function diffUsing($items, callable $callback)
348
    {
349 2
        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 2
    public function diffAssoc($items)
359
    {
360 2
        return new static(array_diff_assoc($this->items, $this->getArrayableItems($items)));
361
    }
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 1
    public function diffAssocUsing($items, callable $callback)
371
    {
372 1
        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 2
    public function diffKeys($items)
382
    {
383 2
        return new static(array_diff_key($this->items, $this->getArrayableItems($items)));
384
    }
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 1
    public function diffKeysUsing($items, callable $callback)
394
    {
395 1
        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 7
    public function each(callable $callback)
405
    {
406 7
        foreach ($this->items as $key => $item) {
407 7
            if ($callback($item, $key) === false) {
408 7
                break;
409
            }
410
        }
411
412 7
        return $this;
413
    }
414
415
    /**
416
     * Execute a callback over each nested chunk of items.
417
     *
418
     * @param  callable  $callback
419
     * @return static
420
     */
421 1
    public function eachSpread(callable $callback)
422
    {
423
        return $this->each(function ($chunk, $key) use ($callback) {
424 1
            $chunk[] = $key;
425
426 1
            return $callback(...$chunk);
427 1
        });
428
    }
429
430
    /**
431
     * Determine if all items in the collection pass the given test.
432
     *
433
     * @param  string|callable  $key
434
     * @param  mixed  $operator
435
     * @param  mixed  $value
436
     * @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
    {
440 1
        if (func_num_args() === 1) {
441 1
            $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 1
            foreach ($this->items as $k => $v) {
444 1
                if (! $callback($v, $k)) {
445 1
                    return false;
446
                }
447
            }
448
449 1
            return true;
450
        }
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
    }
454
455
    /**
456
     * Get all items except for those with the specified keys.
457
     *
458
     * @param  \IlluminateAgnostic\Collection\Support\Collection|mixed  $keys
459
     * @return static
460
     */
461 2
    public function except($keys)
462
    {
463 2
        if ($keys instanceof self) {
464 2
            $keys = $keys->all();
465 1
        } elseif (! is_array($keys)) {
466 1
            $keys = func_get_args();
467
        }
468
469 2
        return new static(Arr::except($this->items, $keys));
470
    }
471
472
    /**
473
     * Run a filter over each of the items.
474
     *
475
     * @param  callable|null  $callback
476
     * @return static
477
     */
478 29
    public function filter(callable $callback = null)
479
    {
480 29
        if ($callback) {
481 29
            return new static(Arr::where($this->items, $callback));
482
        }
483
484 1
        return new static(array_filter($this->items));
485
    }
486
487
    /**
488
     * Apply the callback if the value is truthy.
489
     *
490
     * @param  bool  $value
491
     * @param  callable  $callback
492
     * @param  callable  $default
493
     * @return static|mixed
494
     */
495 4
    public function when($value, callable $callback, callable $default = null)
496
    {
497 4
        if ($value) {
498 2
            return $callback($this, $value);
499 4
        } elseif ($default) {
500 2
            return $default($this, $value);
501
        }
502
503 2
        return $this;
504
    }
505
506
    /**
507
     * Apply the callback if the value is falsy.
508
     *
509
     * @param  bool  $value
510
     * @param  callable  $callback
511
     * @param  callable  $default
512
     * @return static|mixed
513
     */
514 2
    public function unless($value, callable $callback, callable $default = null)
515
    {
516 2
        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
     * @return static
526
     */
527 2
    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 2
        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
     * @param  mixed  $value
538
     * @return \Closure
539
     */
540 7
    protected function operatorForWhere($key, $operator = null, $value = null)
541
    {
542 7
        if (func_num_args() === 1) {
543 1
            $value = true;
544
545 1
            $operator = '=';
546
        }
547
548 7
        if (func_num_args() === 2) {
549 5
            $value = $operator;
550
551 5
            $operator = '=';
552
        }
553
554
        return function ($item) use ($key, $operator, $value) {
555 7
            $retrieved = data_get($item, $key);
556
557
            $strings = array_filter([$retrieved, $value], function ($value) {
558 7
                return is_string($value) || (is_object($value) && method_exists($value, '__toString'));
559 7
            });
560
561 7
            if (count($strings) < 2 && count(array_filter([$retrieved, $value], 'is_object')) == 1) {
562 1
                return in_array($operator, ['!=', '<>', '!==']);
563
            }
564
565 7
            switch ($operator) {
566
                default:
567 7
                case '=':
568 7
                case '==':  return $retrieved == $value;
569 5
                case '!=':
570 5
                case '<>':  return $retrieved != $value;
571 5
                case '<':   return $retrieved < $value;
572 5
                case '>':   return $retrieved > $value;
573 5
                case '<=':  return $retrieved <= $value;
574 5
                case '>=':  return $retrieved >= $value;
575 3
                case '===': return $retrieved === $value;
576 1
                case '!==': return $retrieved !== $value;
577
            }
578 7
        };
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
     */
588 1
    public function whereStrict($key, $value)
589
    {
590 1
        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
     */
601 2 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
    {
603 2
        $values = $this->getArrayableItems($values);
604
605
        return $this->filter(function ($item) use ($key, $values, $strict) {
606 2
            return in_array(data_get($item, $key), $values, $strict);
607 2
        });
608
    }
609
610
    /**
611
     * Filter items by the given key value pair using strict comparison.
612
     *
613
     * @param  string  $key
614
     * @param  mixed  $values
615
     * @return static
616
     */
617 1
    public function whereInStrict($key, $values)
618
    {
619 1
        return $this->whereIn($key, $values, true);
620
    }
621
622
    /**
623
     * Filter items by the given key value pair.
624
     *
625
     * @param  string  $key
626
     * @param  mixed  $values
627
     * @param  bool  $strict
628
     * @return static
629
     */
630 2 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
    {
632 2
        $values = $this->getArrayableItems($values);
633
634
        return $this->reject(function ($item) use ($key, $values, $strict) {
635 2
            return in_array(data_get($item, $key), $values, $strict);
636 2
        });
637
    }
638
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 1
    public function whereNotInStrict($key, $values)
647
    {
648 1
        return $this->whereNotIn($key, $values, true);
649
    }
650
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 1
    public function whereInstanceOf($type)
658
    {
659
        return $this->filter(function ($value) use ($type) {
660 1
            return $value instanceof $type;
661 1
        });
662
    }
663
664
    /**
665
     * Get the first item from the collection.
666
     *
667
     * @param  callable|null  $callback
668
     * @param  mixed  $default
669
     * @return mixed
670
     */
671 11
    public function first(callable $callback = null, $default = null)
672
    {
673 11
        return Arr::first($this->items, $callback, $default);
674
    }
675
676
    /**
677
     * Get the first item by the given key value pair.
678
     *
679
     * @param  string  $key
680
     * @param  mixed  $operator
681
     * @param  mixed  $value
682
     * @return static
683
     */
684 1
    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 1
        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
    /**
690
     * Get a flattened array of the items in the collection.
691
     *
692
     * @param  int  $depth
693
     * @return static
694
     */
695 3
    public function flatten($depth = INF)
696
    {
697 3
        return new static(Arr::flatten($this->items, $depth));
698
    }
699
700
    /**
701
     * Flip the items in the collection.
702
     *
703
     * @return static
704
     */
705 1
    public function flip()
706
    {
707 1
        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 2
            $this->offsetUnset($key);
720
        }
721
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 6
    public function get($key, $default = null)
733
    {
734 6
        if ($this->offsetExists($key)) {
735 5
            return $this->items[$key];
736
        }
737
738 1
        return value($default);
739
    }
740
741
    /**
742
     * Group an associative array by a field or using a callback.
743
     *
744
     * @param  callable|string  $groupBy
745
     * @param  bool  $preserveKeys
746
     * @return static
747
     */
748 8
    public function groupBy($groupBy, $preserveKeys = false)
749
    {
750 8
        if (is_array($groupBy)) {
751 1
            $nextGroups = $groupBy;
752
753 1
            $groupBy = array_shift($nextGroups);
754
        }
755
756 8
        $groupBy = $this->valueRetriever($groupBy);
757
758 8
        $results = [];
759
760 8
        foreach ($this->items as $key => $value) {
761 8
            $groupKeys = $groupBy($value, $key);
762
763 8
            if (! is_array($groupKeys)) {
764 6
                $groupKeys = [$groupKeys];
765
            }
766
767 8
            foreach ($groupKeys as $groupKey) {
768 8
                $groupKey = is_bool($groupKey) ? (int) $groupKey : $groupKey;
769
770 8
                if (! array_key_exists($groupKey, $results)) {
771 8
                    $results[$groupKey] = new static;
772
                }
773
774 8
                $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);
775
            }
776
        }
777
778 8
        $result = new static($results);
779
780 8
        if (! empty($nextGroups)) {
781 1
            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
784 8
        return $result;
785
    }
786
787
    /**
788
     * Key an associative array by a field or using a callback.
789
     *
790
     * @param  callable|string  $keyBy
791
     * @return static
792
     */
793 3
    public function keyBy($keyBy)
794
    {
795 3
        $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 3
        $results = [];
798
799 3
        foreach ($this->items as $key => $item) {
800 3
            $resolvedKey = $keyBy($item, $key);
801
802 3
            if (is_object($resolvedKey)) {
803
                $resolvedKey = (string) $resolvedKey;
804
            }
805
806 3
            $results[$resolvedKey] = $item;
807
        }
808
809 3
        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 2
    public function has($key)
819
    {
820 2
        $keys = is_array($key) ? $key : func_get_args();
821
822 2
        foreach ($keys as $value) {
823 2
            if (! $this->offsetExists($value)) {
824 2
                return false;
825
            }
826
        }
827
828 2
        return true;
829
    }
830
831
    /**
832
     * Concatenate values of a given key as a string.
833
     *
834
     * @param  string  $value
835
     * @param  string  $glue
836
     * @return string
837
     */
838 1
    public function implode($value, $glue = null)
839
    {
840 1
        $first = $this->first();
841
842 1
        if (is_array($first) || is_object($first)) {
843 1
            return implode($glue, $this->pluck($value)->all());
844
        }
845
846 1
        return implode($value, $this->items);
847
    }
848
849
    /**
850
     * Intersect the collection with the given items.
851
     *
852
     * @param  mixed  $items
853
     * @return static
854
     */
855 2
    public function intersect($items)
856
    {
857 2
        return new static(array_intersect($this->items, $this->getArrayableItems($items)));
858
    }
859
860
    /**
861
     * Intersect the collection with the given items by key.
862
     *
863
     * @param  mixed  $items
864
     * @return static
865
     */
866 2
    public function intersectByKeys($items)
867
    {
868 2
        return new static(array_intersect_key(
869 2
            $this->items, $this->getArrayableItems($items)
870
        ));
871
    }
872
873
    /**
874
     * Determine if the collection is empty or not.
875
     *
876
     * @return bool
877
     */
878 10
    public function isEmpty()
879
    {
880 10
        return empty($this->items);
881
    }
882
883
    /**
884
     * Determine if the collection is not empty.
885
     *
886
     * @return bool
887
     */
888 1
    public function isNotEmpty()
889
    {
890 1
        return ! $this->isEmpty();
891
    }
892
893
    /**
894
     * Determine if the given value is callable, but not a string.
895
     *
896
     * @param  mixed  $value
897
     * @return bool
898
     */
899 44
    protected function useAsCallable($value)
900
    {
901 44
        return ! is_string($value) && is_callable($value);
902
    }
903
904
    /**
905
     * Get the keys of the collection items.
906
     *
907
     * @return static
908
     */
909 6
    public function keys()
910
    {
911 6
        return new static(array_keys($this->items));
912
    }
913
914
    /**
915
     * Get the last item from the collection.
916
     *
917
     * @param  callable|null  $callback
918
     * @param  mixed  $default
919
     * @return mixed
920
     */
921 7
    public function last(callable $callback = null, $default = null)
922
    {
923 7
        return Arr::last($this->items, $callback, $default);
924
    }
925
926
    /**
927
     * Get the values of a given key.
928
     *
929
     * @param  string|array  $value
930
     * @param  string|null  $key
931
     * @return static
932
     */
933 10
    public function pluck($value, $key = null)
934
    {
935 10
        return new static(Arr::pluck($this->items, $value, $key));
936
    }
937
938
    /**
939
     * Run a map over each of the items.
940
     *
941
     * @param  callable  $callback
942
     * @return static
943
     */
944 24
    public function map(callable $callback)
945
    {
946 24
        $keys = array_keys($this->items);
947
948 24
        $items = array_map($callback, $this->items, $keys);
949
950 24
        return new static(array_combine($keys, $items));
951
    }
952
953
    /**
954
     * Run a map over each nested chunk of items.
955
     *
956
     * @param  callable  $callback
957
     * @return static
958
     */
959 1
    public function mapSpread(callable $callback)
960
    {
961
        return $this->map(function ($chunk, $key) use ($callback) {
962 1
            $chunk[] = $key;
963
964 1
            return $callback(...$chunk);
965 1
        });
966
    }
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
     * @return static
975
     */
976 4
    public function mapToDictionary(callable $callback)
977
    {
978 4
        $dictionary = [];
979
980 4
        foreach ($this->items as $key => $item) {
981 4
            $pair = $callback($item, $key);
982
983 4
            $key = key($pair);
984
985 4
            $value = reset($pair);
986
987 4
            if (! isset($dictionary[$key])) {
988 4
                $dictionary[$key] = [];
989
            }
990
991 4
            $dictionary[$key][] = $value;
992
        }
993
994 4
        return new static($dictionary);
995
    }
996
997
    /**
998
     * Run a grouping map over the items.
999
     *
1000
     * The callback should return an associative array with a single key/value pair.
1001
     *
1002
     * @param  callable  $callback
1003
     * @return static
1004
     */
1005 2
    public function mapToGroups(callable $callback)
1006
    {
1007 2
        $groups = $this->mapToDictionary($callback);
1008
1009 2
        return $groups->map([$this, 'make']);
1010
    }
1011
1012
    /**
1013
     * Run an associative map over each of the items.
1014
     *
1015
     * The callback should return an associative array with a single key/value pair.
1016
     *
1017
     * @param  callable  $callback
1018
     * @return static
1019
     */
1020 5
    public function mapWithKeys(callable $callback)
1021
    {
1022 5
        $result = [];
1023
1024 5
        foreach ($this->items as $key => $value) {
1025 5
            $assoc = $callback($value, $key);
1026
1027 5
            foreach ($assoc as $mapKey => $mapValue) {
1028 5
                $result[$mapKey] = $mapValue;
1029
            }
1030
        }
1031
1032 5
        return new static($result);
1033
    }
1034
1035
    /**
1036
     * Map a collection and flatten the result by a single level.
1037
     *
1038
     * @param  callable  $callback
1039
     * @return static
1040
     */
1041 1
    public function flatMap(callable $callback)
1042
    {
1043 1
        return $this->map($callback)->collapse();
1044
    }
1045
1046
    /**
1047
     * Map the values into a new class.
1048
     *
1049
     * @param  string  $class
1050
     * @return static
1051
     */
1052 1
    public function mapInto($class)
1053
    {
1054
        return $this->map(function ($value, $key) use ($class) {
1055 1
            return new $class($value, $key);
1056 1
        });
1057
    }
1058
1059
    /**
1060
     * Get the max value of a given key.
1061
     *
1062
     * @param  callable|string|null  $callback
1063
     * @return mixed
1064
     */
1065 1
    public function max($callback = null)
1066
    {
1067 1
        $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 1
            return ! is_null($value);
1071
        })->reduce(function ($result, $item) use ($callback) {
1072 1
            $value = $callback($item);
1073
1074 1
            return is_null($result) || $value > $result ? $value : $result;
1075 1
        });
1076
    }
1077
1078
    /**
1079
     * Merge the collection with the given items.
1080
     *
1081
     * @param  mixed  $items
1082
     * @return static
1083
     */
1084 3
    public function merge($items)
1085
    {
1086 3
        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
     * @param  mixed  $values
1093
     * @return static
1094
     */
1095 2
    public function combine($values)
1096
    {
1097 2
        return new static(array_combine($this->all(), $this->getArrayableItems($values)));
1098
    }
1099
1100
    /**
1101
     * Union the collection with the given items.
1102
     *
1103
     * @param  mixed  $items
1104
     * @return static
1105
     */
1106 3
    public function union($items)
1107
    {
1108 3
        return new static($this->items + $this->getArrayableItems($items));
1109
    }
1110
1111
    /**
1112
     * Get the min value of a given key.
1113
     *
1114
     * @param  callable|string|null  $callback
1115
     * @return mixed
1116
     */
1117 1
    public function min($callback = null)
1118
    {
1119 1
        $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
        return $this->map(function ($value) use ($callback) {
1122 1
            return $callback($value);
1123
        })->filter(function ($value) {
1124 1
            return ! is_null($value);
1125
        })->reduce(function ($result, $value) {
1126 1
            return is_null($result) || $value < $result ? $value : $result;
1127 1
        });
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
     */
1137 1
    public function nth($step, $offset = 0)
1138
    {
1139 1
        $new = [];
1140
1141 1
        $position = 0;
1142
1143 1
        foreach ($this->items as $item) {
1144 1
            if ($position % $step === $offset) {
1145 1
                $new[] = $item;
1146
            }
1147
1148 1
            $position++;
1149
        }
1150
1151 1
        return new static($new);
1152
    }
1153
1154
    /**
1155
     * Get the items with the specified keys.
1156
     *
1157
     * @param  mixed  $keys
1158
     * @return static
1159
     */
1160 1
    public function only($keys)
1161
    {
1162 1
        if (is_null($keys)) {
1163 1
            return new static($this->items);
1164
        }
1165
1166 1
        if ($keys instanceof self) {
1167 1
            $keys = $keys->all();
1168
        }
1169
1170 1
        $keys = is_array($keys) ? $keys : func_get_args();
1171
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
     */
1182 1
    public function forPage($page, $perPage)
1183
    {
1184 1
        $offset = max(0, ($page - 1) * $perPage);
1185
1186 1
        return $this->slice($offset, $perPage);
1187
    }
1188
1189
    /**
1190
     * Partition the collection into two arrays using the given callback or key.
1191
     *
1192
     * @param  callable|string  $key
1193
     * @param  mixed  $operator
1194
     * @param  mixed  $value
1195
     * @return static
1196
     */
1197 7
    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 7
        $partitions = [new static, new static];
1200
1201 7
        $callback = func_num_args() === 1
1202 6
                ? $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 7
                : $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 7
        foreach ($this->items as $key => $item) {
1206 6
            $partitions[(int) ! $callback($item, $key)][$key] = $item;
1207
        }
1208
1209 7
        return new static($partitions);
1210
    }
1211
1212
    /**
1213
     * Pass the collection to the given callback and return the result.
1214
     *
1215
     * @param  callable $callback
1216
     * @return mixed
1217
     */
1218 1
    public function pipe(callable $callback)
1219
    {
1220 1
        return $callback($this);
1221
    }
1222
1223
    /**
1224
     * Get and remove the last item from the collection.
1225
     *
1226
     * @return mixed
1227
     */
1228 1
    public function pop()
1229
    {
1230 1
        return array_pop($this->items);
1231
    }
1232
1233
    /**
1234
     * Push an item onto the beginning of the collection.
1235
     *
1236
     * @param  mixed  $value
1237
     * @param  mixed  $key
1238
     * @return $this
1239
     */
1240 1
    public function prepend($value, $key = null)
1241
    {
1242 1
        $this->items = Arr::prepend($this->items, $value, $key);
1243
1244 1
        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 13
    public function push($value)
1254
    {
1255 13
        $this->offsetSet(null, $value);
1256
1257 13
        return $this;
1258
    }
1259
1260
    /**
1261
     * Push all of the given items onto the collection.
1262
     *
1263
     * @param  \Traversable|array  $source
1264
     * @return static
1265
     */
1266 2
    public function concat($source)
1267
    {
1268 2
        $result = new static($this);
1269
1270 2
        foreach ($source as $item) {
1271 2
            $result->push($item);
1272
        }
1273
1274 2
        return $result;
1275
    }
1276
1277
    /**
1278
     * Get and remove an item from the collection.
1279
     *
1280
     * @param  mixed  $key
1281
     * @param  mixed  $default
1282
     * @return mixed
1283
     */
1284 3
    public function pull($key, $default = null)
1285
    {
1286 3
        return Arr::pull($this->items, $key, $default);
1287
    }
1288
1289
    /**
1290
     * Put an item in the collection by key.
1291
     *
1292
     * @param  mixed  $key
1293
     * @param  mixed  $value
1294
     * @return $this
1295
     */
1296 3
    public function put($key, $value)
1297
    {
1298 3
        $this->offsetSet($key, $value);
1299
1300 3
        return $this;
1301
    }
1302
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 3
    public function random($number = null)
1312
    {
1313 3
        if (is_null($number)) {
1314 1
            return Arr::random($this->items);
1315
        }
1316
1317 3
        return new static(Arr::random($this->items, $number));
1318
    }
1319
1320
    /**
1321
     * Reduce the collection to a single value.
1322
     *
1323
     * @param  callable  $callback
1324
     * @param  mixed  $initial
1325
     * @return mixed
1326
     */
1327 5
    public function reduce(callable $callback, $initial = null)
1328
    {
1329 5
        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
     *
1335
     * @param  callable|mixed  $callback
1336
     * @return static
1337
     */
1338 8
    public function reject($callback)
1339
    {
1340 8
        if ($this->useAsCallable($callback)) {
1341
            return $this->filter(function ($value, $key) use ($callback) {
1342 8
                return ! $callback($value, $key);
1343 8
            });
1344
        }
1345
1346
        return $this->filter(function ($item) use ($callback) {
1347 1
            return $item != $callback;
1348 1
        });
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
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 2
    public function search($value, $strict = false)
1369
    {
1370 2
        if (! $this->useAsCallable($value)) {
1371 2
            return array_search($value, $this->items, $strict);
1372
        }
1373
1374 2
        foreach ($this->items as $key => $item) {
1375 2
            if (call_user_func($value, $item, $key)) {
1376 2
                return $key;
1377
            }
1378
        }
1379
1380 1
        return false;
1381
    }
1382
1383
    /**
1384
     * Get and remove the first item from the collection.
1385
     *
1386
     * @return mixed
1387
     */
1388 1
    public function shift()
1389
    {
1390 1
        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 1
    public function shuffle($seed = null)
1400
    {
1401 1
        return new static(Arr::shuffle($this->items, $seed));
1402
    }
1403
1404
    /**
1405
     * Slice the underlying collection array.
1406
     *
1407
     * @param  int  $offset
1408
     * @param  int  $length
1409
     * @return static
1410
     */
1411 10
    public function slice($offset, $length = null)
1412
    {
1413 10
        return new static(array_slice($this->items, $offset, $length, true));
1414
    }
1415
1416
    /**
1417
     * Split a collection into a certain number of groups.
1418
     *
1419
     * @param  int  $numberOfGroups
1420
     * @return static
1421
     */
1422 7
    public function split($numberOfGroups)
1423
    {
1424 7
        if ($this->isEmpty()) {
1425 1
            return new static;
1426
        }
1427
1428 6
        $groups = new static;
1429
1430 6
        $groupSize = floor($this->count() / $numberOfGroups);
1431
1432 6
        $remain = $this->count() % $numberOfGroups;
1433
1434 6
        $start = 0;
1435
1436 6
        for ($i = 0; $i < $numberOfGroups; $i++) {
1437 6
            $size = $groupSize;
1438
1439 6
            if ($i < $remain) {
1440 5
                $size++;
1441
            }
1442
1443 6
            if ($size) {
1444 6
                $groups->push(new static(array_slice($this->items, $start, $size)));
1445
1446 6
                $start += $size;
1447
            }
1448
        }
1449
1450 6
        return $groups;
1451
    }
1452
1453
    /**
1454
     * Chunk the underlying collection array.
1455
     *
1456
     * @param  int  $size
1457
     * @return static
1458
     */
1459 3
    public function chunk($size)
1460
    {
1461 3
        if ($size <= 0) {
1462 2
            return new static;
1463
        }
1464
1465 1
        $chunks = [];
1466
1467 1
        foreach (array_chunk($this->items, $size, true) as $chunk) {
1468 1
            $chunks[] = new static($chunk);
1469
        }
1470
1471 1
        return new static($chunks);
1472
    }
1473
1474
    /**
1475
     * Sort through each item with a callback.
1476
     *
1477
     * @param  callable|null  $callback
1478
     * @return static
1479
     */
1480 11
    public function sort(callable $callback = null)
1481
    {
1482 11
        $items = $this->items;
1483
1484 11
        $callback
1485 1
            ? uasort($items, $callback)
1486 10
            : asort($items);
1487
1488 11
        return new static($items);
1489
    }
1490
1491
    /**
1492
     * Sort the collection using the given callback.
1493
     *
1494
     * @param  callable|string  $callback
1495
     * @param  int  $options
1496
     * @param  bool  $descending
1497
     * @return static
1498
     */
1499 5
    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
1500
    {
1501 5
        $results = [];
1502
1503 5
        $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
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 5
        foreach ($this->items as $key => $value) {
1509 5
            $results[$key] = $callback($value, $key);
1510
        }
1511
1512 5
        $descending ? arsort($results, $options)
1513 5
            : asort($results, $options);
1514
1515
        // 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 5
        foreach (array_keys($results) as $key) {
1519 5
            $results[$key] = $this->items[$key];
1520
        }
1521
1522 5
        return new static($results);
1523
    }
1524
1525
    /**
1526
     * Sort the collection in descending order using the given callback.
1527
     *
1528
     * @param  callable|string  $callback
1529
     * @param  int  $options
1530
     * @return static
1531
     */
1532 1
    public function sortByDesc($callback, $options = SORT_REGULAR)
1533
    {
1534 1
        return $this->sortBy($callback, $options, true);
1535
    }
1536
1537
    /**
1538
     * Sort the collection keys.
1539
     *
1540
     * @param  int  $options
1541
     * @param  bool  $descending
1542
     * @return static
1543
     */
1544 2
    public function sortKeys($options = SORT_REGULAR, $descending = false)
1545
    {
1546 2
        $items = $this->items;
1547
1548 2
        $descending ? krsort($items, $options) : ksort($items, $options);
1549
1550 2
        return new static($items);
1551
    }
1552
1553
    /**
1554
     * Sort the collection keys in descending order.
1555
     *
1556
     * @param  int $options
1557
     * @return static
1558
     */
1559
    public function sortKeysDesc($options = SORT_REGULAR)
1560
    {
1561
        return $this->sortKeys($options, true);
1562
    }
1563
1564
    /**
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 1
    public function splice($offset, $length = null, $replacement = [])
1573
    {
1574 1
        if (func_num_args() === 1) {
1575 1
            return new static(array_splice($this->items, $offset));
1576
        }
1577
1578 1
        return new static(array_splice($this->items, $offset, $length, $replacement));
1579
    }
1580
1581
    /**
1582
     * Get the sum of the given values.
1583
     *
1584
     * @param  callable|string|null  $callback
1585
     * @return mixed
1586
     */
1587 8
    public function sum($callback = null)
1588
    {
1589 8
        if (is_null($callback)) {
1590 6
            return array_sum($this->items);
1591
        }
1592
1593 2
        $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
1595
        return $this->reduce(function ($result, $item) use ($callback) {
1596 1
            return $result + $callback($item);
1597 2
        }, 0);
1598
    }
1599
1600
    /**
1601
     * Take the first or last {$limit} items.
1602
     *
1603
     * @param  int  $limit
1604
     * @return static
1605
     */
1606 2
    public function take($limit)
1607
    {
1608 2
        if ($limit < 0) {
1609 1
            return $this->slice($limit, abs($limit));
1610
        }
1611
1612 1
        return $this->slice(0, $limit);
1613
    }
1614
1615
    /**
1616
     * Pass the collection to the given callback and then return it.
1617
     *
1618
     * @param  callable  $callback
1619
     * @return $this
1620
     */
1621 1
    public function tap(callable $callback)
1622
    {
1623 1
        $callback(new static($this->items));
1624
1625 1
        return $this;
1626
    }
1627
1628
    /**
1629
     * Transform each item in the collection using a callback.
1630
     *
1631
     * @param  callable  $callback
1632
     * @return $this
1633
     */
1634 1
    public function transform(callable $callback)
1635
    {
1636 1
        $this->items = $this->map($callback)->all();
1637
1638 1
        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
     * @return static
1647
     */
1648 5
    public function unique($key = null, $strict = false)
1649
    {
1650 5
        $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 5
        $exists = [];
1653
1654
        return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) {
1655 5
            if (in_array($id = $callback($item, $key), $exists, $strict)) {
1656 5
                return true;
1657
            }
1658
1659 5
            $exists[] = $id;
1660 5
        });
1661
    }
1662
1663
    /**
1664
     * Return only unique items from the collection array using strict comparison.
1665
     *
1666
     * @param  string|callable|null  $key
1667
     * @return static
1668
     */
1669 1
    public function uniqueStrict($key = null)
1670
    {
1671 1
        return $this->unique($key, true);
1672
    }
1673
1674
    /**
1675
     * Reset the keys on the underlying array.
1676
     *
1677
     * @return static
1678
     */
1679 37
    public function values()
1680
    {
1681 37
        return new static(array_values($this->items));
1682
    }
1683
1684
    /**
1685
     * Get a value retrieving callback.
1686
     *
1687
     * @param  string  $value
1688
     * @return callable
1689
     */
1690 36
    protected function valueRetriever($value)
1691
    {
1692 36
        if ($this->useAsCallable($value)) {
1693 23
            return $value;
1694
        }
1695
1696
        return function ($item) use ($value) {
1697 21
            return data_get($item, $value);
1698 22
        };
1699
    }
1700
1701
    /**
1702
     * Zip the collection together with one or more arrays.
1703
     *
1704
     * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1705
     *      => [[1, 4], [2, 5], [3, 6]]
1706
     *
1707
     * @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
    {
1712
        $arrayableItems = array_map(function ($items) {
1713 1
            return $this->getArrayableItems($items);
1714 1
        }, func_get_args());
1715
1716
        $params = array_merge([function () {
1717 1
            return new static(func_get_args());
1718 1
        }, $this->items], $arrayableItems);
1719
1720 1
        return new static(call_user_func_array('array_map', $params));
1721
    }
1722
1723
    /**
1724
     * Pad collection to the specified length with a value.
1725
     *
1726
     * @param  int  $size
1727
     * @param  mixed  $value
1728
     * @return static
1729
     */
1730 1
    public function pad($size, $value)
1731
    {
1732 1
        return new static(array_pad($this->items, $size, $value));
1733
    }
1734
1735
    /**
1736
     * Get the collection of items as a plain array.
1737
     *
1738
     * @return array
1739
     */
1740 52
    public function toArray()
1741
    {
1742
        return array_map(function ($value) {
1743 49
            return $value instanceof Arrayable ? $value->toArray() : $value;
1744 52
        }, $this->items);
1745
    }
1746
1747
    /**
1748
     * Convert the object into something JSON serializable.
1749
     *
1750
     * @return array
1751
     */
1752 2
    public function jsonSerialize()
1753
    {
1754
        return array_map(function ($value) {
1755 2
            if ($value instanceof JsonSerializable) {
1756 2
                return $value->jsonSerialize();
1757 2
            } elseif ($value instanceof Jsonable) {
1758 1
                return json_decode($value->toJson(), true);
1759 2
            } elseif ($value instanceof Arrayable) {
1760 2
                return $value->toArray();
1761
            }
1762
1763 1
            return $value;
1764 2
        }, $this->items);
1765
    }
1766
1767
    /**
1768
     * Get the collection of items as JSON.
1769
     *
1770
     * @param  int  $options
1771
     * @return string
1772
     */
1773 2
    public function toJson($options = 0)
1774
    {
1775 2
        return json_encode($this->jsonSerialize(), $options);
1776
    }
1777
1778
    /**
1779
     * Get an iterator for the items.
1780
     *
1781
     * @return \ArrayIterator
1782
     */
1783 5
    public function getIterator()
1784
    {
1785 5
        return new ArrayIterator($this->items);
1786
    }
1787
1788
    /**
1789
     * Get a CachingIterator instance.
1790
     *
1791
     * @param  int  $flags
1792
     * @return \CachingIterator
1793
     */
1794 1
    public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
1795
    {
1796 1
        return new CachingIterator($this->getIterator(), $flags);
1797
    }
1798
1799
    /**
1800
     * Count the number of items in the collection.
1801
     *
1802
     * @return int
1803
     */
1804 26
    public function count()
1805
    {
1806 26
        return count($this->items);
1807
    }
1808
1809
    /**
1810
     * Get a base Support collection instance from this collection.
1811
     *
1812
     * @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
     */
1825 17
    public function offsetExists($key)
1826
    {
1827 17
        return array_key_exists($key, $this->items);
1828
    }
1829
1830
    /**
1831
     * Get an item at a given offset.
1832
     *
1833
     * @param  mixed  $key
1834
     * @return mixed
1835
     */
1836 18
    public function offsetGet($key)
1837
    {
1838 18
        return $this->items[$key];
1839
    }
1840
1841
    /**
1842
     * Set the item at a given offset.
1843
     *
1844
     * @param  mixed  $key
1845
     * @param  mixed  $value
1846
     * @return void
1847
     */
1848 37
    public function offsetSet($key, $value)
1849
    {
1850 37
        if (is_null($key)) {
1851 22
            $this->items[] = $value;
1852
        } else {
1853 17
            $this->items[$key] = $value;
1854
        }
1855 37
    }
1856
1857
    /**
1858
     * Unset the item at a given offset.
1859
     *
1860
     * @param  string  $key
1861
     * @return void
1862
     */
1863 4
    public function offsetUnset($key)
1864
    {
1865 4
        unset($this->items[$key]);
1866 4
    }
1867
1868
    /**
1869
     * Convert the collection to its string representation.
1870
     *
1871
     * @return string
1872
     */
1873 1
    public function __toString()
1874
    {
1875 1
        return $this->toJson();
1876
    }
1877
1878
    /**
1879
     * Results array of items from Collection or Arrayable.
1880
     *
1881
     * @param  mixed  $items
1882
     * @return array
1883
     */
1884 221
    protected function getArrayableItems($items)
1885
    {
1886 221
        if (is_array($items)) {
1887 215
            return $items;
1888 35
        } elseif ($items instanceof self) {
1889 20
            return $items->all();
1890 16
        } elseif ($items instanceof Arrayable) {
1891 1
            return $items->toArray();
1892 16
        } elseif ($items instanceof Jsonable) {
1893 1
            return json_decode($items->toJson(), true);
1894 16
        } elseif ($items instanceof JsonSerializable) {
1895 1
            return $items->jsonSerialize();
1896 15
        } elseif ($items instanceof Traversable) {
1897 2
            return iterator_to_array($items);
1898
        }
1899
1900 13
        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
     */
1909 1
    public static function proxy($method)
1910
    {
1911 1
        static::$proxies[] = $method;
1912 1
    }
1913
1914
    /**
1915
     * Dynamically access collection proxies.
1916
     *
1917
     * @param  string  $key
1918
     * @return mixed
1919
     *
1920
     * @throws \Exception
1921
     */
1922 15
    public function __get($key)
1923
    {
1924 15
        if (! in_array($key, static::$proxies)) {
1925 1
            throw new Exception("Property [{$key}] does not exist on this collection instance.");
1926
        }
1927
1928 14
        return new HigherOrderCollectionProxy($this, $key);
1929
    }
1930
}
1931