Subversion-Projekte lars-tiefland.laravel_shop

Revision

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