Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Support\Traits;
4
 
5
use CachingIterator;
6
use Closure;
7
use Exception;
8
use Illuminate\Contracts\Support\Arrayable;
9
use Illuminate\Contracts\Support\Jsonable;
10
use Illuminate\Support\Arr;
11
use Illuminate\Support\Collection;
12
use Illuminate\Support\Enumerable;
13
use Illuminate\Support\HigherOrderCollectionProxy;
14
use JsonSerializable;
15
use Symfony\Component\VarDumper\VarDumper;
16
use Traversable;
17
use UnexpectedValueException;
18
use UnitEnum;
19
 
20
/**
21
 * @template TKey of array-key
22
 * @template TValue
23
 *
24
 * @property-read HigherOrderCollectionProxy $average
25
 * @property-read HigherOrderCollectionProxy $avg
26
 * @property-read HigherOrderCollectionProxy $contains
27
 * @property-read HigherOrderCollectionProxy $doesntContain
28
 * @property-read HigherOrderCollectionProxy $each
29
 * @property-read HigherOrderCollectionProxy $every
30
 * @property-read HigherOrderCollectionProxy $filter
31
 * @property-read HigherOrderCollectionProxy $first
32
 * @property-read HigherOrderCollectionProxy $flatMap
33
 * @property-read HigherOrderCollectionProxy $groupBy
34
 * @property-read HigherOrderCollectionProxy $keyBy
35
 * @property-read HigherOrderCollectionProxy $map
36
 * @property-read HigherOrderCollectionProxy $max
37
 * @property-read HigherOrderCollectionProxy $min
38
 * @property-read HigherOrderCollectionProxy $partition
39
 * @property-read HigherOrderCollectionProxy $reject
40
 * @property-read HigherOrderCollectionProxy $skipUntil
41
 * @property-read HigherOrderCollectionProxy $skipWhile
42
 * @property-read HigherOrderCollectionProxy $some
43
 * @property-read HigherOrderCollectionProxy $sortBy
44
 * @property-read HigherOrderCollectionProxy $sortByDesc
45
 * @property-read HigherOrderCollectionProxy $sum
46
 * @property-read HigherOrderCollectionProxy $takeUntil
47
 * @property-read HigherOrderCollectionProxy $takeWhile
48
 * @property-read HigherOrderCollectionProxy $unique
49
 * @property-read HigherOrderCollectionProxy $unless
50
 * @property-read HigherOrderCollectionProxy $until
51
 * @property-read HigherOrderCollectionProxy $when
52
 */
53
trait EnumeratesValues
54
{
55
    use Conditionable;
56
 
57
    /**
58
     * Indicates that the object's string representation should be escaped when __toString is invoked.
59
     *
60
     * @var bool
61
     */
62
    protected $escapeWhenCastingToString = false;
63
 
64
    /**
65
     * The methods that can be proxied.
66
     *
67
     * @var array<int, string>
68
     */
69
    protected static $proxies = [
70
        'average',
71
        'avg',
72
        'contains',
73
        'doesntContain',
74
        'each',
75
        'every',
76
        'filter',
77
        'first',
78
        'flatMap',
79
        'groupBy',
80
        'keyBy',
81
        'map',
82
        'max',
83
        'min',
84
        'partition',
85
        'reject',
86
        'skipUntil',
87
        'skipWhile',
88
        'some',
89
        'sortBy',
90
        'sortByDesc',
91
        'sum',
92
        'takeUntil',
93
        'takeWhile',
94
        'unique',
95
        'unless',
96
        'until',
97
        'when',
98
    ];
99
 
100
    /**
101
     * Create a new collection instance if the value isn't one already.
102
     *
103
     * @template TMakeKey of array-key
104
     * @template TMakeValue
105
     *
106
     * @param  \Illuminate\Contracts\Support\Arrayable<TMakeKey, TMakeValue>|iterable<TMakeKey, TMakeValue>|null  $items
107
     * @return static<TMakeKey, TMakeValue>
108
     */
109
    public static function make($items = [])
110
    {
111
        return new static($items);
112
    }
113
 
114
    /**
115
     * Wrap the given value in a collection if applicable.
116
     *
117
     * @template TWrapKey of array-key
118
     * @template TWrapValue
119
     *
120
     * @param  iterable<TWrapKey, TWrapValue>  $value
121
     * @return static<TWrapKey, TWrapValue>
122
     */
123
    public static function wrap($value)
124
    {
125
        return $value instanceof Enumerable
126
            ? new static($value)
127
            : new static(Arr::wrap($value));
128
    }
129
 
130
    /**
131
     * Get the underlying items from the given collection if applicable.
132
     *
133
     * @template TUnwrapKey of array-key
134
     * @template TUnwrapValue
135
     *
136
     * @param  array<TUnwrapKey, TUnwrapValue>|static<TUnwrapKey, TUnwrapValue>  $value
137
     * @return array<TUnwrapKey, TUnwrapValue>
138
     */
139
    public static function unwrap($value)
140
    {
141
        return $value instanceof Enumerable ? $value->all() : $value;
142
    }
143
 
144
    /**
145
     * Create a new instance with no items.
146
     *
147
     * @return static
148
     */
149
    public static function empty()
150
    {
151
        return new static([]);
152
    }
153
 
154
    /**
155
     * Create a new collection by invoking the callback a given amount of times.
156
     *
157
     * @template TTimesValue
158
     *
159
     * @param  int  $number
160
     * @param  (callable(int): TTimesValue)|null  $callback
161
     * @return static<int, TTimesValue>
162
     */
163
    public static function times($number, callable $callback = null)
164
    {
165
        if ($number < 1) {
166
            return new static;
167
        }
168
 
169
        return static::range(1, $number)
170
            ->unless($callback == null)
171
            ->map($callback);
172
    }
173
 
174
    /**
175
     * Alias for the "avg" method.
176
     *
177
     * @param  (callable(TValue): float|int)|string|null  $callback
178
     * @return float|int|null
179
     */
180
    public function average($callback = null)
181
    {
182
        return $this->avg($callback);
183
    }
184
 
185
    /**
186
     * Alias for the "contains" method.
187
     *
188
     * @param  (callable(TValue, TKey): bool)|TValue|string  $key
189
     * @param  mixed  $operator
190
     * @param  mixed  $value
191
     * @return bool
192
     */
193
    public function some($key, $operator = null, $value = null)
194
    {
195
        return $this->contains(...func_get_args());
196
    }
197
 
198
    /**
199
     * Dump the items and end the script.
200
     *
201
     * @param  mixed  ...$args
202
     * @return never
203
     */
204
    public function dd(...$args)
205
    {
206
        $this->dump(...$args);
207
 
208
        exit(1);
209
    }
210
 
211
    /**
212
     * Dump the items.
213
     *
214
     * @return $this
215
     */
216
    public function dump()
217
    {
218
        (new Collection(func_get_args()))
219
            ->push($this->all())
220
            ->each(function ($item) {
221
                VarDumper::dump($item);
222
            });
223
 
224
        return $this;
225
    }
226
 
227
    /**
228
     * Execute a callback over each item.
229
     *
230
     * @param  callable(TValue, TKey): mixed  $callback
231
     * @return $this
232
     */
233
    public function each(callable $callback)
234
    {
235
        foreach ($this as $key => $item) {
236
            if ($callback($item, $key) === false) {
237
                break;
238
            }
239
        }
240
 
241
        return $this;
242
    }
243
 
244
    /**
245
     * Execute a callback over each nested chunk of items.
246
     *
247
     * @param  callable(...mixed): mixed  $callback
248
     * @return static
249
     */
250
    public function eachSpread(callable $callback)
251
    {
252
        return $this->each(function ($chunk, $key) use ($callback) {
253
            $chunk[] = $key;
254
 
255
            return $callback(...$chunk);
256
        });
257
    }
258
 
259
    /**
260
     * Determine if all items pass the given truth test.
261
     *
262
     * @param  (callable(TValue, TKey): bool)|TValue|string  $key
263
     * @param  mixed  $operator
264
     * @param  mixed  $value
265
     * @return bool
266
     */
267
    public function every($key, $operator = null, $value = null)
268
    {
269
        if (func_num_args() === 1) {
270
            $callback = $this->valueRetriever($key);
271
 
272
            foreach ($this as $k => $v) {
273
                if (! $callback($v, $k)) {
274
                    return false;
275
                }
276
            }
277
 
278
            return true;
279
        }
280
 
281
        return $this->every($this->operatorForWhere(...func_get_args()));
282
    }
283
 
284
    /**
285
     * Get the first item by the given key value pair.
286
     *
287
     * @param  callable|string  $key
288
     * @param  mixed  $operator
289
     * @param  mixed  $value
290
     * @return TValue|null
291
     */
292
    public function firstWhere($key, $operator = null, $value = null)
293
    {
294
        return $this->first($this->operatorForWhere(...func_get_args()));
295
    }
296
 
297
    /**
298
     * Get a single key's value from the first matching item in the collection.
299
     *
300
     * @param  string  $key
301
     * @param  mixed  $default
302
     * @return mixed
303
     */
304
    public function value($key, $default = null)
305
    {
306
        if ($value = $this->firstWhere($key)) {
307
            return data_get($value, $key, $default);
308
        }
309
 
310
        return value($default);
311
    }
312
 
313
    /**
314
     * Determine if the collection is not empty.
315
     *
316
     * @return bool
317
     */
318
    public function isNotEmpty()
319
    {
320
        return ! $this->isEmpty();
321
    }
322
 
323
    /**
324
     * Run a map over each nested chunk of items.
325
     *
326
     * @template TMapSpreadValue
327
     *
328
     * @param  callable(mixed): TMapSpreadValue  $callback
329
     * @return static<TKey, TMapSpreadValue>
330
     */
331
    public function mapSpread(callable $callback)
332
    {
333
        return $this->map(function ($chunk, $key) use ($callback) {
334
            $chunk[] = $key;
335
 
336
            return $callback(...$chunk);
337
        });
338
    }
339
 
340
    /**
341
     * Run a grouping map over the items.
342
     *
343
     * The callback should return an associative array with a single key/value pair.
344
     *
345
     * @template TMapToGroupsKey of array-key
346
     * @template TMapToGroupsValue
347
     *
348
     * @param  callable(TValue, TKey): array<TMapToGroupsKey, TMapToGroupsValue>  $callback
349
     * @return static<TMapToGroupsKey, static<int, TMapToGroupsValue>>
350
     */
351
    public function mapToGroups(callable $callback)
352
    {
353
        $groups = $this->mapToDictionary($callback);
354
 
355
        return $groups->map([$this, 'make']);
356
    }
357
 
358
    /**
359
     * Map a collection and flatten the result by a single level.
360
     *
361
     * @template TFlatMapKey of array-key
362
     * @template TFlatMapValue
363
     *
364
     * @param  callable(TValue, TKey): (\Illuminate\Support\Collection<TFlatMapKey, TFlatMapValue>|array<TFlatMapKey, TFlatMapValue>)  $callback
365
     * @return static<TFlatMapKey, TFlatMapValue>
366
     */
367
    public function flatMap(callable $callback)
368
    {
369
        return $this->map($callback)->collapse();
370
    }
371
 
372
    /**
373
     * Map the values into a new class.
374
     *
375
     * @template TMapIntoValue
376
     *
377
     * @param  class-string<TMapIntoValue>  $class
378
     * @return static<TKey, TMapIntoValue>
379
     */
380
    public function mapInto($class)
381
    {
382
        return $this->map(fn ($value, $key) => new $class($value, $key));
383
    }
384
 
385
    /**
386
     * Get the min value of a given key.
387
     *
388
     * @param  (callable(TValue):mixed)|string|null  $callback
389
     * @return mixed
390
     */
391
    public function min($callback = null)
392
    {
393
        $callback = $this->valueRetriever($callback);
394
 
395
        return $this->map(fn ($value) => $callback($value))
396
            ->filter(fn ($value) => ! is_null($value))
397
            ->reduce(fn ($result, $value) => is_null($result) || $value < $result ? $value : $result);
398
    }
399
 
400
    /**
401
     * Get the max value of a given key.
402
     *
403
     * @param  (callable(TValue):mixed)|string|null  $callback
404
     * @return mixed
405
     */
406
    public function max($callback = null)
407
    {
408
        $callback = $this->valueRetriever($callback);
409
 
410
        return $this->filter(fn ($value) => ! is_null($value))->reduce(function ($result, $item) use ($callback) {
411
            $value = $callback($item);
412
 
413
            return is_null($result) || $value > $result ? $value : $result;
414
        });
415
    }
416
 
417
    /**
418
     * "Paginate" the collection by slicing it into a smaller collection.
419
     *
420
     * @param  int  $page
421
     * @param  int  $perPage
422
     * @return static
423
     */
424
    public function forPage($page, $perPage)
425
    {
426
        $offset = max(0, ($page - 1) * $perPage);
427
 
428
        return $this->slice($offset, $perPage);
429
    }
430
 
431
    /**
432
     * Partition the collection into two arrays using the given callback or key.
433
     *
434
     * @param  (callable(TValue, TKey): bool)|TValue|string  $key
435
     * @param  TValue|string|null  $operator
436
     * @param  TValue|null  $value
437
     * @return static<int<0, 1>, static<TKey, TValue>>
438
     */
439
    public function partition($key, $operator = null, $value = null)
440
    {
441
        $passed = [];
442
        $failed = [];
443
 
444
        $callback = func_num_args() === 1
445
                ? $this->valueRetriever($key)
446
                : $this->operatorForWhere(...func_get_args());
447
 
448
        foreach ($this as $key => $item) {
449
            if ($callback($item, $key)) {
450
                $passed[$key] = $item;
451
            } else {
452
                $failed[$key] = $item;
453
            }
454
        }
455
 
456
        return new static([new static($passed), new static($failed)]);
457
    }
458
 
459
    /**
460
     * Get the sum of the given values.
461
     *
462
     * @param  (callable(TValue): mixed)|string|null  $callback
463
     * @return mixed
464
     */
465
    public function sum($callback = null)
466
    {
467
        $callback = is_null($callback)
468
            ? $this->identity()
469
            : $this->valueRetriever($callback);
470
 
471
        return $this->reduce(fn ($result, $item) => $result + $callback($item), 0);
472
    }
473
 
474
    /**
475
     * Apply the callback if the collection is empty.
476
     *
477
     * @template TWhenEmptyReturnType
478
     *
479
     * @param  (callable($this): TWhenEmptyReturnType)  $callback
480
     * @param  (callable($this): TWhenEmptyReturnType)|null  $default
481
     * @return $this|TWhenEmptyReturnType
482
     */
483
    public function whenEmpty(callable $callback, callable $default = null)
484
    {
485
        return $this->when($this->isEmpty(), $callback, $default);
486
    }
487
 
488
    /**
489
     * Apply the callback if the collection is not empty.
490
     *
491
     * @template TWhenNotEmptyReturnType
492
     *
493
     * @param  callable($this): TWhenNotEmptyReturnType  $callback
494
     * @param  (callable($this): TWhenNotEmptyReturnType)|null  $default
495
     * @return $this|TWhenNotEmptyReturnType
496
     */
497
    public function whenNotEmpty(callable $callback, callable $default = null)
498
    {
499
        return $this->when($this->isNotEmpty(), $callback, $default);
500
    }
501
 
502
    /**
503
     * Apply the callback unless the collection is empty.
504
     *
505
     * @template TUnlessEmptyReturnType
506
     *
507
     * @param  callable($this): TUnlessEmptyReturnType  $callback
508
     * @param  (callable($this): TUnlessEmptyReturnType)|null  $default
509
     * @return $this|TUnlessEmptyReturnType
510
     */
511
    public function unlessEmpty(callable $callback, callable $default = null)
512
    {
513
        return $this->whenNotEmpty($callback, $default);
514
    }
515
 
516
    /**
517
     * Apply the callback unless the collection is not empty.
518
     *
519
     * @template TUnlessNotEmptyReturnType
520
     *
521
     * @param  callable($this): TUnlessNotEmptyReturnType  $callback
522
     * @param  (callable($this): TUnlessNotEmptyReturnType)|null  $default
523
     * @return $this|TUnlessNotEmptyReturnType
524
     */
525
    public function unlessNotEmpty(callable $callback, callable $default = null)
526
    {
527
        return $this->whenEmpty($callback, $default);
528
    }
529
 
530
    /**
531
     * Filter items by the given key value pair.
532
     *
533
     * @param  callable|string  $key
534
     * @param  mixed  $operator
535
     * @param  mixed  $value
536
     * @return static
537
     */
538
    public function where($key, $operator = null, $value = null)
539
    {
540
        return $this->filter($this->operatorForWhere(...func_get_args()));
541
    }
542
 
543
    /**
544
     * Filter items where the value for the given key is null.
545
     *
546
     * @param  string|null  $key
547
     * @return static
548
     */
549
    public function whereNull($key = null)
550
    {
551
        return $this->whereStrict($key, null);
552
    }
553
 
554
    /**
555
     * Filter items where the value for the given key is not null.
556
     *
557
     * @param  string|null  $key
558
     * @return static
559
     */
560
    public function whereNotNull($key = null)
561
    {
562
        return $this->where($key, '!==', null);
563
    }
564
 
565
    /**
566
     * Filter items by the given key value pair using strict comparison.
567
     *
568
     * @param  string  $key
569
     * @param  mixed  $value
570
     * @return static
571
     */
572
    public function whereStrict($key, $value)
573
    {
574
        return $this->where($key, '===', $value);
575
    }
576
 
577
    /**
578
     * Filter items by the given key value pair.
579
     *
580
     * @param  string  $key
581
     * @param  \Illuminate\Contracts\Support\Arrayable|iterable  $values
582
     * @param  bool  $strict
583
     * @return static
584
     */
585
    public function whereIn($key, $values, $strict = false)
586
    {
587
        $values = $this->getArrayableItems($values);
588
 
589
        return $this->filter(fn ($item) => in_array(data_get($item, $key), $values, $strict));
590
    }
591
 
592
    /**
593
     * Filter items by the given key value pair using strict comparison.
594
     *
595
     * @param  string  $key
596
     * @param  \Illuminate\Contracts\Support\Arrayable|iterable  $values
597
     * @return static
598
     */
599
    public function whereInStrict($key, $values)
600
    {
601
        return $this->whereIn($key, $values, true);
602
    }
603
 
604
    /**
605
     * Filter items such that the value of the given key is between the given values.
606
     *
607
     * @param  string  $key
608
     * @param  \Illuminate\Contracts\Support\Arrayable|iterable  $values
609
     * @return static
610
     */
611
    public function whereBetween($key, $values)
612
    {
613
        return $this->where($key, '>=', reset($values))->where($key, '<=', end($values));
614
    }
615
 
616
    /**
617
     * Filter items such that the value of the given key is not between the given values.
618
     *
619
     * @param  string  $key
620
     * @param  \Illuminate\Contracts\Support\Arrayable|iterable  $values
621
     * @return static
622
     */
623
    public function whereNotBetween($key, $values)
624
    {
625
        return $this->filter(
626
            fn ($item) => data_get($item, $key) < reset($values) || data_get($item, $key) > end($values)
627
        );
628
    }
629
 
630
    /**
631
     * Filter items by the given key value pair.
632
     *
633
     * @param  string  $key
634
     * @param  \Illuminate\Contracts\Support\Arrayable|iterable  $values
635
     * @param  bool  $strict
636
     * @return static
637
     */
638
    public function whereNotIn($key, $values, $strict = false)
639
    {
640
        $values = $this->getArrayableItems($values);
641
 
642
        return $this->reject(fn ($item) => in_array(data_get($item, $key), $values, $strict));
643
    }
644
 
645
    /**
646
     * Filter items by the given key value pair using strict comparison.
647
     *
648
     * @param  string  $key
649
     * @param  \Illuminate\Contracts\Support\Arrayable|iterable  $values
650
     * @return static
651
     */
652
    public function whereNotInStrict($key, $values)
653
    {
654
        return $this->whereNotIn($key, $values, true);
655
    }
656
 
657
    /**
658
     * Filter the items, removing any items that don't match the given type(s).
659
     *
660
     * @template TWhereInstanceOf
661
     *
662
     * @param  class-string<TWhereInstanceOf>|array<array-key, class-string<TWhereInstanceOf>>  $type
663
     * @return static<TKey, TWhereInstanceOf>
664
     */
665
    public function whereInstanceOf($type)
666
    {
667
        return $this->filter(function ($value) use ($type) {
668
            if (is_array($type)) {
669
                foreach ($type as $classType) {
670
                    if ($value instanceof $classType) {
671
                        return true;
672
                    }
673
                }
674
 
675
                return false;
676
            }
677
 
678
            return $value instanceof $type;
679
        });
680
    }
681
 
682
    /**
683
     * Pass the collection to the given callback and return the result.
684
     *
685
     * @template TPipeReturnType
686
     *
687
     * @param  callable($this): TPipeReturnType  $callback
688
     * @return TPipeReturnType
689
     */
690
    public function pipe(callable $callback)
691
    {
692
        return $callback($this);
693
    }
694
 
695
    /**
696
     * Pass the collection into a new class.
697
     *
698
     * @param  class-string  $class
699
     * @return mixed
700
     */
701
    public function pipeInto($class)
702
    {
703
        return new $class($this);
704
    }
705
 
706
    /**
707
     * Pass the collection through a series of callable pipes and return the result.
708
     *
709
     * @param  array<callable>  $callbacks
710
     * @return mixed
711
     */
712
    public function pipeThrough($callbacks)
713
    {
714
        return Collection::make($callbacks)->reduce(
715
            fn ($carry, $callback) => $callback($carry),
716
            $this,
717
        );
718
    }
719
 
720
    /**
721
     * Reduce the collection to a single value.
722
     *
723
     * @template TReduceInitial
724
     * @template TReduceReturnType
725
     *
726
     * @param  callable(TReduceInitial|TReduceReturnType, TValue, TKey): TReduceReturnType  $callback
727
     * @param  TReduceInitial  $initial
728
     * @return TReduceReturnType
729
     */
730
    public function reduce(callable $callback, $initial = null)
731
    {
732
        $result = $initial;
733
 
734
        foreach ($this as $key => $value) {
735
            $result = $callback($result, $value, $key);
736
        }
737
 
738
        return $result;
739
    }
740
 
741
    /**
742
     * Reduce the collection to multiple aggregate values.
743
     *
744
     * @param  callable  $callback
745
     * @param  mixed  ...$initial
746
     * @return array
747
     *
748
     * @throws \UnexpectedValueException
749
     */
750
    public function reduceSpread(callable $callback, ...$initial)
751
    {
752
        $result = $initial;
753
 
754
        foreach ($this as $key => $value) {
755
            $result = call_user_func_array($callback, array_merge($result, [$value, $key]));
756
 
757
            if (! is_array($result)) {
758
                throw new UnexpectedValueException(sprintf(
759
                    "%s::reduceSpread expects reducer to return an array, but got a '%s' instead.",
760
                    class_basename(static::class), gettype($result)
761
                ));
762
            }
763
        }
764
 
765
        return $result;
766
    }
767
 
768
    /**
769
     * Create a collection of all elements that do not pass a given truth test.
770
     *
771
     * @param  (callable(TValue, TKey): bool)|bool|TValue  $callback
772
     * @return static
773
     */
774
    public function reject($callback = true)
775
    {
776
        $useAsCallable = $this->useAsCallable($callback);
777
 
778
        return $this->filter(function ($value, $key) use ($callback, $useAsCallable) {
779
            return $useAsCallable
780
                ? ! $callback($value, $key)
781
                : $value != $callback;
782
        });
783
    }
784
 
785
    /**
786
     * Pass the collection to the given callback and then return it.
787
     *
788
     * @param  callable($this): mixed  $callback
789
     * @return $this
790
     */
791
    public function tap(callable $callback)
792
    {
793
        $callback($this);
794
 
795
        return $this;
796
    }
797
 
798
    /**
799
     * Return only unique items from the collection array.
800
     *
801
     * @param  (callable(TValue, TKey): mixed)|string|null  $key
802
     * @param  bool  $strict
803
     * @return static
804
     */
805
    public function unique($key = null, $strict = false)
806
    {
807
        $callback = $this->valueRetriever($key);
808
 
809
        $exists = [];
810
 
811
        return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) {
812
            if (in_array($id = $callback($item, $key), $exists, $strict)) {
813
                return true;
814
            }
815
 
816
            $exists[] = $id;
817
        });
818
    }
819
 
820
    /**
821
     * Return only unique items from the collection array using strict comparison.
822
     *
823
     * @param  (callable(TValue, TKey): mixed)|string|null  $key
824
     * @return static
825
     */
826
    public function uniqueStrict($key = null)
827
    {
828
        return $this->unique($key, true);
829
    }
830
 
831
    /**
832
     * Collect the values into a collection.
833
     *
834
     * @return \Illuminate\Support\Collection<TKey, TValue>
835
     */
836
    public function collect()
837
    {
838
        return new Collection($this->all());
839
    }
840
 
841
    /**
842
     * Get the collection of items as a plain array.
843
     *
844
     * @return array<TKey, mixed>
845
     */
846
    public function toArray()
847
    {
848
        return $this->map(fn ($value) => $value instanceof Arrayable ? $value->toArray() : $value)->all();
849
    }
850
 
851
    /**
852
     * Convert the object into something JSON serializable.
853
     *
854
     * @return array<TKey, mixed>
855
     */
856
    public function jsonSerialize(): array
857
    {
858
        return array_map(function ($value) {
859
            if ($value instanceof JsonSerializable) {
860
                return $value->jsonSerialize();
861
            } elseif ($value instanceof Jsonable) {
862
                return json_decode($value->toJson(), true);
863
            } elseif ($value instanceof Arrayable) {
864
                return $value->toArray();
865
            }
866
 
867
            return $value;
868
        }, $this->all());
869
    }
870
 
871
    /**
872
     * Get the collection of items as JSON.
873
     *
874
     * @param  int  $options
875
     * @return string
876
     */
877
    public function toJson($options = 0)
878
    {
879
        return json_encode($this->jsonSerialize(), $options);
880
    }
881
 
882
    /**
883
     * Get a CachingIterator instance.
884
     *
885
     * @param  int  $flags
886
     * @return \CachingIterator
887
     */
888
    public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
889
    {
890
        return new CachingIterator($this->getIterator(), $flags);
891
    }
892
 
893
    /**
894
     * Convert the collection to its string representation.
895
     *
896
     * @return string
897
     */
898
    public function __toString()
899
    {
900
        return $this->escapeWhenCastingToString
901
                    ? e($this->toJson())
902
                    : $this->toJson();
903
    }
904
 
905
    /**
906
     * Indicate that the model's string representation should be escaped when __toString is invoked.
907
     *
908
     * @param  bool  $escape
909
     * @return $this
910
     */
911
    public function escapeWhenCastingToString($escape = true)
912
    {
913
        $this->escapeWhenCastingToString = $escape;
914
 
915
        return $this;
916
    }
917
 
918
    /**
919
     * Add a method to the list of proxied methods.
920
     *
921
     * @param  string  $method
922
     * @return void
923
     */
924
    public static function proxy($method)
925
    {
926
        static::$proxies[] = $method;
927
    }
928
 
929
    /**
930
     * Dynamically access collection proxies.
931
     *
932
     * @param  string  $key
933
     * @return mixed
934
     *
935
     * @throws \Exception
936
     */
937
    public function __get($key)
938
    {
939
        if (! in_array($key, static::$proxies)) {
940
            throw new Exception("Property [{$key}] does not exist on this collection instance.");
941
        }
942
 
943
        return new HigherOrderCollectionProxy($this, $key);
944
    }
945
 
946
    /**
947
     * Results array of items from Collection or Arrayable.
948
     *
949
     * @param  mixed  $items
950
     * @return array<TKey, TValue>
951
     */
952
    protected function getArrayableItems($items)
953
    {
954
        if (is_array($items)) {
955
            return $items;
956
        } elseif ($items instanceof Enumerable) {
957
            return $items->all();
958
        } elseif ($items instanceof Arrayable) {
959
            return $items->toArray();
960
        } elseif ($items instanceof Traversable) {
961
            return iterator_to_array($items);
962
        } elseif ($items instanceof Jsonable) {
963
            return json_decode($items->toJson(), true);
964
        } elseif ($items instanceof JsonSerializable) {
965
            return (array) $items->jsonSerialize();
966
        } elseif ($items instanceof UnitEnum) {
967
            return [$items];
968
        }
969
 
970
        return (array) $items;
971
    }
972
 
973
    /**
974
     * Get an operator checker callback.
975
     *
976
     * @param  callable|string  $key
977
     * @param  string|null  $operator
978
     * @param  mixed  $value
979
     * @return \Closure
980
     */
981
    protected function operatorForWhere($key, $operator = null, $value = null)
982
    {
983
        if ($this->useAsCallable($key)) {
984
            return $key;
985
        }
986
 
987
        if (func_num_args() === 1) {
988
            $value = true;
989
 
990
            $operator = '=';
991
        }
992
 
993
        if (func_num_args() === 2) {
994
            $value = $operator;
995
 
996
            $operator = '=';
997
        }
998
 
999
        return function ($item) use ($key, $operator, $value) {
1000
            $retrieved = data_get($item, $key);
1001
 
1002
            $strings = array_filter([$retrieved, $value], function ($value) {
1003
                return is_string($value) || (is_object($value) && method_exists($value, '__toString'));
1004
            });
1005
 
1006
            if (count($strings) < 2 && count(array_filter([$retrieved, $value], 'is_object')) == 1) {
1007
                return in_array($operator, ['!=', '<>', '!==']);
1008
            }
1009
 
1010
            switch ($operator) {
1011
                default:
1012
                case '=':
1013
                case '==':  return $retrieved == $value;
1014
                case '!=':
1015
                case '<>':  return $retrieved != $value;
1016
                case '<':   return $retrieved < $value;
1017
                case '>':   return $retrieved > $value;
1018
                case '<=':  return $retrieved <= $value;
1019
                case '>=':  return $retrieved >= $value;
1020
                case '===': return $retrieved === $value;
1021
                case '!==': return $retrieved !== $value;
1022
                case '<=>': return $retrieved <=> $value;
1023
            }
1024
        };
1025
    }
1026
 
1027
    /**
1028
     * Determine if the given value is callable, but not a string.
1029
     *
1030
     * @param  mixed  $value
1031
     * @return bool
1032
     */
1033
    protected function useAsCallable($value)
1034
    {
1035
        return ! is_string($value) && is_callable($value);
1036
    }
1037
 
1038
    /**
1039
     * Get a value retrieving callback.
1040
     *
1041
     * @param  callable|string|null  $value
1042
     * @return callable
1043
     */
1044
    protected function valueRetriever($value)
1045
    {
1046
        if ($this->useAsCallable($value)) {
1047
            return $value;
1048
        }
1049
 
1050
        return fn ($item) => data_get($item, $value);
1051
    }
1052
 
1053
    /**
1054
     * Make a function to check an item's equality.
1055
     *
1056
     * @param  mixed  $value
1057
     * @return \Closure(mixed): bool
1058
     */
1059
    protected function equality($value)
1060
    {
1061
        return fn ($item) => $item === $value;
1062
    }
1063
 
1064
    /**
1065
     * Make a function using another function, by negating its result.
1066
     *
1067
     * @param  \Closure  $callback
1068
     * @return \Closure
1069
     */
1070
    protected function negate(Closure $callback)
1071
    {
1072
        return fn (...$params) => ! $callback(...$params);
1073
    }
1074
 
1075
    /**
1076
     * Make a function that returns what's passed to it.
1077
     *
1078
     * @return \Closure(TValue): TValue
1079
     */
1080
    protected function identity()
1081
    {
1082
        return fn ($value) => $value;
1083
    }
1084
}