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

src/Support/Collection.php (2 issues)

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