Completed
Push — master ( c7b24f...7511ca )
by Antonio Carlos
02:10
created

src/Support/Collection.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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