Completed
Push — master ( 29c7dc...1875a0 )
by Antonio Carlos
02:00
created

Collection::__get()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
ccs 4
cts 4
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
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\Debug\Dumper;
15
use IlluminateAgnostic\Arr\Support\Traits\Macroable;
16
use IlluminateAgnostic\Arr\Contracts\Support\Jsonable;
17
use IlluminateAgnostic\Arr\Contracts\Support\Arrayable;
18
19
class Collection implements ArrayAccess, Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable
20
{
21
    use Macroable;
22
23
    /**
24
     * The items contained in the collection.
25
     *
26
     * @var array
27
     */
28
    protected $items = [];
29
30
    /**
31
     * The methods that can be proxied.
32
     *
33
     * @var array
34
     */
35
    protected static $proxies = [
36
        'average', 'avg', 'contains', 'each', 'every', 'filter', 'first', 'flatMap',
37
        'keyBy', 'map', 'partition', 'reject', 'sortBy', 'sortByDesc', 'sum', 'unique',
38
    ];
39
40
    /**
41
     * Create a new collection.
42
     *
43
     * @param  mixed  $items
44
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
45
     */
46 208
    public function __construct($items = [])
47
    {
48 208
        $this->items = $this->getArrayableItems($items);
49 208
    }
50
51
    /**
52
     * Create a new collection instance if the value isn't one already.
53
     *
54
     * @param  mixed  $items
55
     * @return static
56
     */
57 10
    public static function make($items = [])
58
    {
59 10
        return new static($items);
60
    }
61
62
    /**
63
     * Wrap the given value in a collection if applicable.
64
     *
65
     * @param  mixed  $value
66
     * @return static
67
     */
68 7
    public static function wrap($value)
69
    {
70 7
        return $value instanceof self
71 2
            ? new static($value)
72 7
            : new static(Arr::wrap($value));
73
    }
74
75
    /**
76
     * Get the underlying items from the given collection if applicable.
77
     *
78
     * @param  array|static  $value
79
     * @return array
80
     */
81 3
    public static function unwrap($value)
82
    {
83 3
        return $value instanceof self ? $value->all() : $value;
84
    }
85
86
    /**
87
     * Create a new collection by invoking the callback a given amount of times.
88
     *
89
     * @param  int  $number
90
     * @param  callable  $callback
91
     * @return static
92
     */
93 1
    public static function times($number, callable $callback = null)
94
    {
95 1
        if ($number < 1) {
96 1
            return new static;
97
        }
98
99 1
        if (is_null($callback)) {
100 1
            return new static(range(1, $number));
101
        }
102
103 1
        return (new static(range(1, $number)))->map($callback);
104
    }
105
106
    /**
107
     * Get all of the items in the collection.
108
     *
109
     * @return array
110
     */
111 104
    public function all()
112
    {
113 104
        return $this->items;
114
    }
115
116
    /**
117
     * Get the average value of a given key.
118
     *
119
     * @param  callable|string|null  $callback
120
     * @return mixed
121
     */
122 4
    public function avg($callback = null)
123
    {
124 4
        if ($count = $this->count()) {
125 4
            return $this->sum($callback) / $count;
126
        }
127 1
    }
128
129
    /**
130
     * Alias for the "avg" method.
131
     *
132
     * @param  callable|string|null  $callback
133
     * @return mixed
134
     */
135 3
    public function average($callback = null)
136
    {
137 3
        return $this->avg($callback);
138
    }
139
140
    /**
141
     * Get the median of a given key.
142
     *
143
     * @param  null $key
144
     * @return mixed
145
     */
146 5
    public function median($key = null)
147
    {
148 5
        $count = $this->count();
149
150 5
        if ($count == 0) {
151 1
            return;
152
        }
153
154 4
        $values = (isset($key) ? $this->pluck($key) : $this)
155 4
                    ->sort()->values();
156
157 4
        $middle = (int) ($count / 2);
158
159 4
        if ($count % 2) {
160 1
            return $values->get($middle);
161
        }
162
163 3
        return (new static([
164 3
            $values->get($middle - 1), $values->get($middle),
165 3
        ]))->average();
166
    }
167
168
    /**
169
     * Get the mode of a given key.
170
     *
171
     * @param  mixed  $key
172
     * @return array|null
173
     */
174 4
    public function mode($key = null)
175
    {
176 4
        $count = $this->count();
177
178 4
        if ($count == 0) {
179 1
            return;
180
        }
181
182 3
        $collection = isset($key) ? $this->pluck($key) : $this;
183
184 3
        $counts = new self;
185
186 3
        $collection->each(function ($value) use ($counts) {
187 3
            $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1;
188 3
        });
189
190 3
        $sorted = $counts->sort();
191
192 3
        $highestValue = $sorted->last();
193
194 3
        return $sorted->filter(function ($value) use ($highestValue) {
195 3
            return $value == $highestValue;
196 3
        })->sort()->keys()->all();
197
    }
198
199
    /**
200
     * Collapse the collection of items into a single array.
201
     *
202
     * @return static
203
     */
204 3
    public function collapse()
205
    {
206 3
        return new static(Arr::collapse($this->items));
207
    }
208
209
    /**
210
     * Determine if an item exists in the collection.
211
     *
212
     * @param  mixed  $key
213
     * @param  mixed  $operator
214
     * @param  mixed  $value
215
     * @return bool
216
     */
217 3
    public function contains($key, $operator = null, $value = null)
218
    {
219 3
        if (func_num_args() == 1) {
220 3
            if ($this->useAsCallable($key)) {
221 3
                $placeholder = new stdClass;
222
223 3
                return $this->first($key, $placeholder) !== $placeholder;
224
            }
225
226 1
            return in_array($key, $this->items);
227
        }
228
229 2
        return $this->contains($this->operatorForWhere(...func_get_args()));
230
    }
231
232
    /**
233
     * Determine if an item exists in the collection using strict comparison.
234
     *
235
     * @param  mixed  $key
236
     * @param  mixed  $value
237
     * @return bool
238
     */
239 1
    public function containsStrict($key, $value = null)
240
    {
241 1
        if (func_num_args() == 2) {
242 1
            return $this->contains(function ($item) use ($key, $value) {
243 1
                return data_get($item, $key) === $value;
244 1
            });
245
        }
246
247 1
        if ($this->useAsCallable($key)) {
248 1
            return ! is_null($this->first($key));
249
        }
250
251 1
        return in_array($key, $this->items, true);
252
    }
253
254
    /**
255
     * Cross join with the given lists, returning all possible permutations.
256
     *
257
     * @param  mixed  ...$lists
258
     * @return static
259
     */
260 1
    public function crossJoin(...$lists)
261
    {
262 1
        return new static(Arr::crossJoin(
263 1
            $this->items, ...array_map([$this, 'getArrayableItems'], $lists)
264
        ));
265
    }
266
267
    /**
268
     * Dump the collection and end the script.
269
     *
270
     * @return void
271
     */
272
    public function dd(...$args)
273
    {
274
        http_response_code(500);
275
276
        call_user_func_array([$this, 'dump'], $args);
277
278
        die(1);
279
    }
280
281
    /**
282
     * Dump the collection.
283
     *
284
     * @return $this
285
     */
286
    public function dump()
287
    {
288
        (new static(func_get_args()))
289
            ->push($this)
290
            ->each(function ($item) {
291
                (new Dumper)->dump($item);
292
            });
293
294
        return $this;
295
    }
296
297
    /**
298
     * Get the items in the collection that are not present in the given items.
299
     *
300
     * @param  mixed  $items
301
     * @return static
302
     */
303 2
    public function diff($items)
304
    {
305 2
        return new static(array_diff($this->items, $this->getArrayableItems($items)));
306
    }
307
308
    /**
309
     * Get the items in the collection whose keys and values are not present in the given items.
310
     *
311
     * @param  mixed  $items
312
     * @return static
313
     */
314 1
    public function diffAssoc($items)
315
    {
316 1
        return new static(array_diff_assoc($this->items, $this->getArrayableItems($items)));
317
    }
318
319
    /**
320
     * Get the items in the collection whose keys are not present in the given items.
321
     *
322
     * @param  mixed  $items
323
     * @return static
324
     */
325 1
    public function diffKeys($items)
326
    {
327 1
        return new static(array_diff_key($this->items, $this->getArrayableItems($items)));
328
    }
329
330
    /**
331
     * Execute a callback over each item.
332
     *
333
     * @param  callable  $callback
334
     * @return $this
335
     */
336 7
    public function each(callable $callback)
337
    {
338 7
        foreach ($this->items as $key => $item) {
339 7
            if ($callback($item, $key) === false) {
340 7
                break;
341
            }
342
        }
343
344 7
        return $this;
345
    }
346
347
    /**
348
     * Execute a callback over each nested chunk of items.
349
     *
350
     * @param  callable  $callback
351
     * @return static
352
     */
353
    public function eachSpread(callable $callback)
354
    {
355 1
        return $this->each(function ($chunk, $key) use ($callback) {
356 1
            $chunk[] = $key;
357
358 1
            return $callback(...$chunk);
359 1
        });
360
    }
361
362
    /**
363
     * Determine if all items in the collection pass the given test.
364
     *
365
     * @param  string|callable  $key
366
     * @param  mixed  $operator
367
     * @param  mixed  $value
368
     * @return bool
369
     */
370 1
    public function every($key, $operator = null, $value = null)
371
    {
372 1
        if (func_num_args() == 1) {
373 1
            $callback = $this->valueRetriever($key);
374
375 1
            foreach ($this->items as $k => $v) {
376 1
                if (! $callback($v, $k)) {
377 1
                    return false;
378
                }
379
            }
380
381 1
            return true;
382
        }
383
384 1
        return $this->every($this->operatorForWhere(...func_get_args()));
385
    }
386
387
    /**
388
     * Get all items except for those with the specified keys.
389
     *
390
     * @param  \IlluminateAgnostic\Arr\Support\Collection|mixed  $keys
391
     * @return static
392
     */
393 2
    public function except($keys)
394
    {
395 2
        if ($keys instanceof self) {
396 2
            $keys = $keys->all();
397 1
        } elseif (! is_array($keys)) {
398 1
            $keys = func_get_args();
399
        }
400
401 2
        return new static(Arr::except($this->items, $keys));
402
    }
403
404
    /**
405
     * Run a filter over each of the items.
406
     *
407
     * @param  callable|null  $callback
408
     * @return static
409
     */
410 21
    public function filter(callable $callback = null)
411
    {
412 21
        if ($callback) {
413 21
            return new static(Arr::where($this->items, $callback));
414
        }
415
416 1
        return new static(array_filter($this->items));
417
    }
418
419
    /**
420
     * Apply the callback if the value is truthy.
421
     *
422
     * @param  bool  $value
423
     * @param  callable  $callback
424
     * @param  callable  $default
425
     * @return mixed
426
     */
427 4
    public function when($value, callable $callback, callable $default = null)
428
    {
429 4
        if ($value) {
430 2
            return $callback($this, $value);
431 4
        } elseif ($default) {
432 2
            return $default($this, $value);
433
        }
434
435 2
        return $this;
436
    }
437
438
    /**
439
     * Apply the callback if the value is falsy.
440
     *
441
     * @param  bool  $value
442
     * @param  callable  $callback
443
     * @param  callable  $default
444
     * @return mixed
445
     */
446 2
    public function unless($value, callable $callback, callable $default = null)
447
    {
448 2
        return $this->when(! $value, $callback, $default);
449
    }
450
451
    /**
452
     * Filter items by the given key value pair.
453
     *
454
     * @param  string  $key
455
     * @param  mixed  $operator
456
     * @param  mixed  $value
457
     * @return static
458
     */
459 2
    public function where($key, $operator, $value = null)
460
    {
461 2
        return $this->filter($this->operatorForWhere(...func_get_args()));
462
    }
463
464
    /**
465
     * Get an operator checker callback.
466
     *
467
     * @param  string  $key
468
     * @param  string  $operator
469
     * @param  mixed  $value
470
     * @return \Closure
471
     */
472 7
    protected function operatorForWhere($key, $operator, $value = null)
473
    {
474 7
        if (func_num_args() == 2) {
475 5
            $value = $operator;
476
477 5
            $operator = '=';
478
        }
479
480 7
        return function ($item) use ($key, $operator, $value) {
481 7
            $retrieved = data_get($item, $key);
482
483 7
            $strings = array_filter([$retrieved, $value], function ($value) {
484 7
                return is_string($value) || (is_object($value) && method_exists($value, '__toString'));
485 7
            });
486
487 7
            if (count($strings) < 2 && count(array_filter([$retrieved, $value], 'is_object')) == 1) {
488 1
                return in_array($operator, ['!=', '<>', '!==']);
489
            }
490
491 7
            switch ($operator) {
492
                default:
493
                case '=':
494 6
                case '==':  return $retrieved == $value;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
495
                case '!=':
496 1
                case '<>':  return $retrieved != $value;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
497 1
                case '<':   return $retrieved < $value;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
498 2
                case '>':   return $retrieved > $value;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
499 1
                case '<=':  return $retrieved <= $value;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
500 3
                case '>=':  return $retrieved >= $value;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
501 3
                case '===': return $retrieved === $value;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
502 1
                case '!==': return $retrieved !== $value;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
503
            }
504 7
        };
505
    }
506
507
    /**
508
     * Filter items by the given key value pair using strict comparison.
509
     *
510
     * @param  string  $key
511
     * @param  mixed  $value
512
     * @return static
513
     */
514 1
    public function whereStrict($key, $value)
515
    {
516 1
        return $this->where($key, '===', $value);
517
    }
518
519
    /**
520
     * Filter items by the given key value pair.
521
     *
522
     * @param  string  $key
523
     * @param  mixed  $values
524
     * @param  bool  $strict
525
     * @return static
526
     */
527 2 View Code Duplication
    public function whereIn($key, $values, $strict = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
528
    {
529 2
        $values = $this->getArrayableItems($values);
530
531 2
        return $this->filter(function ($item) use ($key, $values, $strict) {
532 2
            return in_array(data_get($item, $key), $values, $strict);
533 2
        });
534
    }
535
536
    /**
537
     * Filter items by the given key value pair using strict comparison.
538
     *
539
     * @param  string  $key
540
     * @param  mixed  $values
541
     * @return static
542
     */
543 1
    public function whereInStrict($key, $values)
544
    {
545 1
        return $this->whereIn($key, $values, true);
546
    }
547
548
    /**
549
     * Filter items by the given key value pair.
550
     *
551
     * @param  string  $key
552
     * @param  mixed  $values
553
     * @param  bool  $strict
554
     * @return static
555
     */
556 2 View Code Duplication
    public function whereNotIn($key, $values, $strict = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
557
    {
558 2
        $values = $this->getArrayableItems($values);
559
560 2
        return $this->reject(function ($item) use ($key, $values, $strict) {
561 2
            return in_array(data_get($item, $key), $values, $strict);
562 2
        });
563
    }
564
565
    /**
566
     * Filter items by the given key value pair using strict comparison.
567
     *
568
     * @param  string  $key
569
     * @param  mixed  $values
570
     * @return static
571
     */
572 1
    public function whereNotInStrict($key, $values)
573
    {
574 1
        return $this->whereNotIn($key, $values, true);
575
    }
576
577
    /**
578
     * Get the first item from the collection.
579
     *
580
     * @param  callable|null  $callback
581
     * @param  mixed  $default
582
     * @return mixed
583
     */
584 11
    public function first(callable $callback = null, $default = null)
585
    {
586 11
        return Arr::first($this->items, $callback, $default);
587
    }
588
589
    /**
590
     * Get the first item by the given key value pair.
591
     *
592
     * @param  string  $key
593
     * @param  mixed  $operator
594
     * @param  mixed  $value
595
     * @return static
596
     */
597 1
    public function firstWhere($key, $operator, $value = null)
598
    {
599 1
        return $this->first($this->operatorForWhere(...func_get_args()));
600
    }
601
602
    /**
603
     * Get a flattened array of the items in the collection.
604
     *
605
     * @param  int  $depth
606
     * @return static
607
     */
608 3
    public function flatten($depth = INF)
609
    {
610 3
        return new static(Arr::flatten($this->items, $depth));
611
    }
612
613
    /**
614
     * Flip the items in the collection.
615
     *
616
     * @return static
617
     */
618 1
    public function flip()
619
    {
620 1
        return new static(array_flip($this->items));
621
    }
622
623
    /**
624
     * Remove an item from the collection by key.
625
     *
626
     * @param  string|array  $keys
627
     * @return $this
628
     */
629 2
    public function forget($keys)
630
    {
631 2
        foreach ((array) $keys as $key) {
632 2
            $this->offsetUnset($key);
633
        }
634
635 2
        return $this;
636
    }
637
638
    /**
639
     * Get an item from the collection by key.
640
     *
641
     * @param  mixed  $key
642
     * @param  mixed  $default
643
     * @return mixed
644
     */
645 5
    public function get($key, $default = null)
646
    {
647 5
        if ($this->offsetExists($key)) {
648 4
            return $this->items[$key];
649
        }
650
651 1
        return value($default);
652
    }
653
654
    /**
655
     * Group an associative array by a field or using a callback.
656
     *
657
     * @param  callable|string  $groupBy
658
     * @param  bool  $preserveKeys
659
     * @return static
660
     */
661 7
    public function groupBy($groupBy, $preserveKeys = false)
662
    {
663 7
        if (is_array($groupBy)) {
664 1
            $nextGroups = $groupBy;
665
666 1
            $groupBy = array_shift($nextGroups);
667
        }
668
669 7
        $groupBy = $this->valueRetriever($groupBy);
670
671 7
        $results = [];
672
673 7
        foreach ($this->items as $key => $value) {
674 7
            $groupKeys = $groupBy($value, $key);
675
676 7
            if (! is_array($groupKeys)) {
677 5
                $groupKeys = [$groupKeys];
678
            }
679
680 7
            foreach ($groupKeys as $groupKey) {
681 7
                $groupKey = is_bool($groupKey) ? (int) $groupKey : $groupKey;
682
683 7
                if (! array_key_exists($groupKey, $results)) {
684 7
                    $results[$groupKey] = new static;
685
                }
686
687 7
                $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);
688
            }
689
        }
690
691 7
        $result = new static($results);
692
693 7
        if (! empty($nextGroups)) {
694 1
            return $result->map->groupBy($nextGroups, $preserveKeys);
695
        }
696
697 7
        return $result;
698
    }
699
700
    /**
701
     * Key an associative array by a field or using a callback.
702
     *
703
     * @param  callable|string  $keyBy
704
     * @return static
705
     */
706 3
    public function keyBy($keyBy)
707
    {
708 3
        $keyBy = $this->valueRetriever($keyBy);
709
710 3
        $results = [];
711
712 3
        foreach ($this->items as $key => $item) {
713 3
            $resolvedKey = $keyBy($item, $key);
714
715 3
            if (is_object($resolvedKey)) {
716
                $resolvedKey = (string) $resolvedKey;
717
            }
718
719 3
            $results[$resolvedKey] = $item;
720
        }
721
722 3
        return new static($results);
723
    }
724
725
    /**
726
     * Determine if an item exists in the collection by key.
727
     *
728
     * @param  mixed  $key
729
     * @return bool
730
     */
731 2
    public function has($key)
732
    {
733 2
        $keys = is_array($key) ? $key : func_get_args();
734
735 2
        foreach ($keys as $value) {
736 2
            if (! $this->offsetExists($value)) {
737 2
                return false;
738
            }
739
        }
740
741 2
        return true;
742
    }
743
744
    /**
745
     * Concatenate values of a given key as a string.
746
     *
747
     * @param  string  $value
748
     * @param  string  $glue
749
     * @return string
750
     */
751 1
    public function implode($value, $glue = null)
752
    {
753 1
        $first = $this->first();
754
755 1
        if (is_array($first) || is_object($first)) {
756 1
            return implode($glue, $this->pluck($value)->all());
757
        }
758
759 1
        return implode($value, $this->items);
760
    }
761
762
    /**
763
     * Intersect the collection with the given items.
764
     *
765
     * @param  mixed  $items
766
     * @return static
767
     */
768 2
    public function intersect($items)
769
    {
770 2
        return new static(array_intersect($this->items, $this->getArrayableItems($items)));
771
    }
772
773
    /**
774
     * Intersect the collection with the given items by key.
775
     *
776
     * @param  mixed  $items
777
     * @return static
778
     */
779 2
    public function intersectByKeys($items)
780
    {
781 2
        return new static(array_intersect_key(
782 2
            $this->items, $this->getArrayableItems($items)
783
        ));
784
    }
785
786
    /**
787
     * Determine if the collection is empty or not.
788
     *
789
     * @return bool
790
     */
791 7
    public function isEmpty()
792
    {
793 7
        return empty($this->items);
794
    }
795
796
    /**
797
     * Determine if the collection is not empty.
798
     *
799
     * @return bool
800
     */
801 1
    public function isNotEmpty()
802
    {
803 1
        return ! $this->isEmpty();
804
    }
805
806
    /**
807
     * Determine if the given value is callable, but not a string.
808
     *
809
     * @param  mixed  $value
810
     * @return bool
811
     */
812 40
    protected function useAsCallable($value)
813
    {
814 40
        return ! is_string($value) && is_callable($value);
815
    }
816
817
    /**
818
     * Get the keys of the collection items.
819
     *
820
     * @return static
821
     */
822 6
    public function keys()
823
    {
824 6
        return new static(array_keys($this->items));
825
    }
826
827
    /**
828
     * Get the last item from the collection.
829
     *
830
     * @param  callable|null  $callback
831
     * @param  mixed  $default
832
     * @return mixed
833
     */
834 7
    public function last(callable $callback = null, $default = null)
835
    {
836 7
        return Arr::last($this->items, $callback, $default);
837
    }
838
839
    /**
840
     * Get the values of a given key.
841
     *
842
     * @param  string|array  $value
843
     * @param  string|null  $key
844
     * @return static
845
     */
846 9
    public function pluck($value, $key = null)
847
    {
848 9
        return new static(Arr::pluck($this->items, $value, $key));
849
    }
850
851
    /**
852
     * Run a map over each of the items.
853
     *
854
     * @param  callable  $callback
855
     * @return static
856
     */
857 16
    public function map(callable $callback)
858
    {
859 16
        $keys = array_keys($this->items);
860
861 16
        $items = array_map($callback, $this->items, $keys);
862
863 16
        return new static(array_combine($keys, $items));
864
    }
865
866
    /**
867
     * Run a map over each nested chunk of items.
868
     *
869
     * @param  callable  $callback
870
     * @return static
871
     */
872
    public function mapSpread(callable $callback)
873
    {
874 1
        return $this->map(function ($chunk, $key) use ($callback) {
875 1
            $chunk[] = $key;
876
877 1
            return $callback(...$chunk);
878 1
        });
879
    }
880
881
    /**
882
     * Run a dictionary map over the items.
883
     *
884
     * The callback should return an associative array with a single key/value pair.
885
     *
886
     * @param  callable  $callback
887
     * @return static
888
     */
889 4
    public function mapToDictionary(callable $callback)
890
    {
891 4
        $dictionary = [];
892
893 4
        foreach ($this->items as $key => $item) {
894 4
            $pair = $callback($item, $key);
895
896 4
            $key = key($pair);
897
898 4
            $value = reset($pair);
899
900 4
            if (! isset($dictionary[$key])) {
901 4
                $dictionary[$key] = [];
902
            }
903
904 4
            $dictionary[$key][] = $value;
905
        }
906
907 4
        return new static($dictionary);
908
    }
909
910
    /**
911
     * Run a grouping map over the items.
912
     *
913
     * The callback should return an associative array with a single key/value pair.
914
     *
915
     * @param  callable  $callback
916
     * @return static
917
     */
918 2
    public function mapToGroups(callable $callback)
919
    {
920 2
        $groups = $this->mapToDictionary($callback);
921
922 2
        return $groups->map([$this, 'make']);
923
    }
924
925
    /**
926
     * Run an associative map over each of the items.
927
     *
928
     * The callback should return an associative array with a single key/value pair.
929
     *
930
     * @param  callable  $callback
931
     * @return static
932
     */
933 4
    public function mapWithKeys(callable $callback)
934
    {
935 4
        $result = [];
936
937 4
        foreach ($this->items as $key => $value) {
938 4
            $assoc = $callback($value, $key);
939
940 4
            foreach ($assoc as $mapKey => $mapValue) {
941 4
                $result[$mapKey] = $mapValue;
942
            }
943
        }
944
945 4
        return new static($result);
946
    }
947
948
    /**
949
     * Map a collection and flatten the result by a single level.
950
     *
951
     * @param  callable  $callback
952
     * @return static
953
     */
954 1
    public function flatMap(callable $callback)
955
    {
956 1
        return $this->map($callback)->collapse();
957
    }
958
959
    /**
960
     * Map the values into a new class.
961
     *
962
     * @param  string  $class
963
     * @return static
964
     */
965
    public function mapInto($class)
966
    {
967 1
        return $this->map(function ($value, $key) use ($class) {
968 1
            return new $class($value, $key);
969 1
        });
970
    }
971
972
    /**
973
     * Get the max value of a given key.
974
     *
975
     * @param  callable|string|null  $callback
976
     * @return mixed
977
     */
978 1 View Code Duplication
    public function max($callback = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
979
    {
980 1
        $callback = $this->valueRetriever($callback);
981
982 1
        return $this->filter(function ($value) {
983 1
            return ! is_null($value);
984
        })->reduce(function ($result, $item) use ($callback) {
985 1
            $value = $callback($item);
986
987 1
            return is_null($result) || $value > $result ? $value : $result;
988 1
        });
989
    }
990
991
    /**
992
     * Merge the collection with the given items.
993
     *
994
     * @param  mixed  $items
995
     * @return static
996
     */
997 3
    public function merge($items)
998
    {
999 3
        return new static(array_merge($this->items, $this->getArrayableItems($items)));
1000
    }
1001
1002
    /**
1003
     * Create a collection by using this collection for keys and another for its values.
1004
     *
1005
     * @param  mixed  $values
1006
     * @return static
1007
     */
1008 2
    public function combine($values)
1009
    {
1010 2
        return new static(array_combine($this->all(), $this->getArrayableItems($values)));
1011
    }
1012
1013
    /**
1014
     * Union the collection with the given items.
1015
     *
1016
     * @param  mixed  $items
1017
     * @return static
1018
     */
1019 3
    public function union($items)
1020
    {
1021 3
        return new static($this->items + $this->getArrayableItems($items));
1022
    }
1023
1024
    /**
1025
     * Get the min value of a given key.
1026
     *
1027
     * @param  callable|string|null  $callback
1028
     * @return mixed
1029
     */
1030 1 View Code Duplication
    public function min($callback = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1031
    {
1032 1
        $callback = $this->valueRetriever($callback);
1033
1034 1
        return $this->filter(function ($value) {
1035 1
            return ! is_null($value);
1036
        })->reduce(function ($result, $item) use ($callback) {
1037 1
            $value = $callback($item);
1038
1039 1
            return is_null($result) || $value < $result ? $value : $result;
1040 1
        });
1041
    }
1042
1043
    /**
1044
     * Create a new collection consisting of every n-th element.
1045
     *
1046
     * @param  int  $step
1047
     * @param  int  $offset
1048
     * @return static
1049
     */
1050 1
    public function nth($step, $offset = 0)
1051
    {
1052 1
        $new = [];
1053
1054 1
        $position = 0;
1055
1056 1
        foreach ($this->items as $item) {
1057 1
            if ($position % $step === $offset) {
1058 1
                $new[] = $item;
1059
            }
1060
1061 1
            $position++;
1062
        }
1063
1064 1
        return new static($new);
1065
    }
1066
1067
    /**
1068
     * Get the items with the specified keys.
1069
     *
1070
     * @param  mixed  $keys
1071
     * @return static
1072
     */
1073 1
    public function only($keys)
1074
    {
1075 1
        if (is_null($keys)) {
1076 1
            return new static($this->items);
1077
        }
1078
1079 1
        if ($keys instanceof self) {
1080 1
            $keys = $keys->all();
1081
        }
1082
1083 1
        $keys = is_array($keys) ? $keys : func_get_args();
1084
1085 1
        return new static(Arr::only($this->items, $keys));
1086
    }
1087
1088
    /**
1089
     * "Paginate" the collection by slicing it into a smaller collection.
1090
     *
1091
     * @param  int  $page
1092
     * @param  int  $perPage
1093
     * @return static
1094
     */
1095 1
    public function forPage($page, $perPage)
1096
    {
1097 1
        $offset = max(0, ($page - 1) * $perPage);
1098
1099 1
        return $this->slice($offset, $perPage);
1100
    }
1101
1102
    /**
1103
     * Partition the collection into two arrays using the given callback or key.
1104
     *
1105
     * @param  callable|string  $key
1106
     * @param  mixed  $operator
1107
     * @param  mixed  $value
1108
     * @return static
1109
     */
1110 7
    public function partition($key, $operator = null, $value = null)
1111
    {
1112 7
        $partitions = [new static, new static];
1113
1114 7
        $callback = func_num_args() == 1
1115 6
                ? $this->valueRetriever($key)
1116 7
                : $this->operatorForWhere(...func_get_args());
1117
1118 7
        foreach ($this->items as $key => $item) {
1119 6
            $partitions[(int) ! $callback($item, $key)][$key] = $item;
1120
        }
1121
1122 7
        return new static($partitions);
1123
    }
1124
1125
    /**
1126
     * Pass the collection to the given callback and return the result.
1127
     *
1128
     * @param  callable $callback
1129
     * @return mixed
1130
     */
1131 1
    public function pipe(callable $callback)
1132
    {
1133 1
        return $callback($this);
1134
    }
1135
1136
    /**
1137
     * Get and remove the last item from the collection.
1138
     *
1139
     * @return mixed
1140
     */
1141 1
    public function pop()
1142
    {
1143 1
        return array_pop($this->items);
1144
    }
1145
1146
    /**
1147
     * Push an item onto the beginning of the collection.
1148
     *
1149
     * @param  mixed  $value
1150
     * @param  mixed  $key
1151
     * @return $this
1152
     */
1153 1
    public function prepend($value, $key = null)
1154
    {
1155 1
        $this->items = Arr::prepend($this->items, $value, $key);
1156
1157 1
        return $this;
1158
    }
1159
1160
    /**
1161
     * Push an item onto the end of the collection.
1162
     *
1163
     * @param  mixed  $value
1164
     * @return $this
1165
     */
1166 7
    public function push($value)
1167
    {
1168 7
        $this->offsetSet(null, $value);
1169
1170 7
        return $this;
1171
    }
1172
1173
    /**
1174
     * Push all of the given items onto the collection.
1175
     *
1176
     * @param  \Traversable  $source
1177
     * @return $this
1178
     */
1179 2
    public function concat($source)
1180
    {
1181 2
        $result = new static($this);
1182
1183 2
        foreach ($source as $item) {
1184 2
            $result->push($item);
1185
        }
1186
1187 2
        return $result;
1188
    }
1189
1190
    /**
1191
     * Get and remove an item from the collection.
1192
     *
1193
     * @param  mixed  $key
1194
     * @param  mixed  $default
1195
     * @return mixed
1196
     */
1197 3
    public function pull($key, $default = null)
1198
    {
1199 3
        return Arr::pull($this->items, $key, $default);
1200
    }
1201
1202
    /**
1203
     * Put an item in the collection by key.
1204
     *
1205
     * @param  mixed  $key
1206
     * @param  mixed  $value
1207
     * @return $this
1208
     */
1209 3
    public function put($key, $value)
1210
    {
1211 3
        $this->offsetSet($key, $value);
1212
1213 3
        return $this;
1214
    }
1215
1216
    /**
1217
     * Get one or a specified number of items randomly from the collection.
1218
     *
1219
     * @param  int|null  $number
1220
     * @return mixed
1221
     *
1222
     * @throws \InvalidArgumentException
1223
     */
1224 3
    public function random($number = null)
1225
    {
1226 3
        if (is_null($number)) {
1227 1
            return Arr::random($this->items);
1228
        }
1229
1230 3
        return new static(Arr::random($this->items, $number));
1231
    }
1232
1233
    /**
1234
     * Reduce the collection to a single value.
1235
     *
1236
     * @param  callable  $callback
1237
     * @param  mixed  $initial
1238
     * @return mixed
1239
     */
1240 6
    public function reduce(callable $callback, $initial = null)
1241
    {
1242 6
        return array_reduce($this->items, $callback, $initial);
1243
    }
1244
1245
    /**
1246
     * Create a collection of all elements that do not pass a given truth test.
1247
     *
1248
     * @param  callable|mixed  $callback
1249
     * @return static
1250
     */
1251 8
    public function reject($callback)
1252
    {
1253 8
        if ($this->useAsCallable($callback)) {
1254 8
            return $this->filter(function ($value, $key) use ($callback) {
1255 8
                return ! $callback($value, $key);
1256 8
            });
1257
        }
1258
1259 1
        return $this->filter(function ($item) use ($callback) {
1260 1
            return $item != $callback;
1261 1
        });
1262
    }
1263
1264
    /**
1265
     * Reverse items order.
1266
     *
1267
     * @return static
1268
     */
1269 1
    public function reverse()
1270
    {
1271 1
        return new static(array_reverse($this->items, true));
1272
    }
1273
1274
    /**
1275
     * Search the collection for a given value and return the corresponding key if successful.
1276
     *
1277
     * @param  mixed  $value
1278
     * @param  bool  $strict
1279
     * @return mixed
1280
     */
1281 2
    public function search($value, $strict = false)
1282
    {
1283 2
        if (! $this->useAsCallable($value)) {
1284 2
            return array_search($value, $this->items, $strict);
1285
        }
1286
1287 2
        foreach ($this->items as $key => $item) {
1288 2
            if (call_user_func($value, $item, $key)) {
1289 2
                return $key;
1290
            }
1291
        }
1292
1293 1
        return false;
1294
    }
1295
1296
    /**
1297
     * Get and remove the first item from the collection.
1298
     *
1299
     * @return mixed
1300
     */
1301 1
    public function shift()
1302
    {
1303 1
        return array_shift($this->items);
1304
    }
1305
1306
    /**
1307
     * Shuffle the items in the collection.
1308
     *
1309
     * @param  int  $seed
1310
     * @return static
1311
     */
1312 1
    public function shuffle($seed = null)
1313
    {
1314 1
        $items = $this->items;
1315
1316 1
        if (is_null($seed)) {
1317
            shuffle($items);
1318
        } else {
1319 1
            srand($seed);
1320
1321 1
            usort($items, function () {
1322 1
                return rand(-1, 1);
1323 1
            });
1324
        }
1325
1326 1
        return new static($items);
1327
    }
1328
1329
    /**
1330
     * Slice the underlying collection array.
1331
     *
1332
     * @param  int  $offset
1333
     * @param  int  $length
1334
     * @return static
1335
     */
1336 10
    public function slice($offset, $length = null)
1337
    {
1338 10
        return new static(array_slice($this->items, $offset, $length, true));
1339
    }
1340
1341
    /**
1342
     * Split a collection into a certain number of groups.
1343
     *
1344
     * @param  int  $numberOfGroups
1345
     * @return static
1346
     */
1347 4
    public function split($numberOfGroups)
1348
    {
1349 4
        if ($this->isEmpty()) {
1350 1
            return new static;
1351
        }
1352
1353 3
        $groupSize = ceil($this->count() / $numberOfGroups);
1354
1355 3
        return $this->chunk($groupSize);
1356
    }
1357
1358
    /**
1359
     * Chunk the underlying collection array.
1360
     *
1361
     * @param  int  $size
1362
     * @return static
1363
     */
1364 6
    public function chunk($size)
1365
    {
1366 6
        if ($size <= 0) {
1367 2
            return new static;
1368
        }
1369
1370 4
        $chunks = [];
1371
1372 4
        foreach (array_chunk($this->items, $size, true) as $chunk) {
1373 4
            $chunks[] = new static($chunk);
1374
        }
1375
1376 4
        return new static($chunks);
1377
    }
1378
1379
    /**
1380
     * Sort through each item with a callback.
1381
     *
1382
     * @param  callable|null  $callback
1383
     * @return static
1384
     */
1385 9
    public function sort(callable $callback = null)
1386
    {
1387 9
        $items = $this->items;
1388
1389 9
        $callback
1390 1
            ? uasort($items, $callback)
1391 8
            : asort($items);
1392
1393 9
        return new static($items);
1394
    }
1395
1396
    /**
1397
     * Sort the collection using the given callback.
1398
     *
1399
     * @param  callable|string  $callback
1400
     * @param  int  $options
1401
     * @param  bool  $descending
1402
     * @return static
1403
     */
1404 5
    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
1405
    {
1406 5
        $results = [];
1407
1408 5
        $callback = $this->valueRetriever($callback);
1409
1410
        // First we will loop through the items and get the comparator from a callback
1411
        // function which we were given. Then, we will sort the returned values and
1412
        // and grab the corresponding values for the sorted keys from this array.
1413 5
        foreach ($this->items as $key => $value) {
1414 5
            $results[$key] = $callback($value, $key);
1415
        }
1416
1417 5
        $descending ? arsort($results, $options)
1418 5
            : asort($results, $options);
1419
1420
        // Once we have sorted all of the keys in the array, we will loop through them
1421
        // and grab the corresponding model so we can set the underlying items list
1422
        // to the sorted version. Then we'll just return the collection instance.
1423 5
        foreach (array_keys($results) as $key) {
1424 5
            $results[$key] = $this->items[$key];
1425
        }
1426
1427 5
        return new static($results);
1428
    }
1429
1430
    /**
1431
     * Sort the collection in descending order using the given callback.
1432
     *
1433
     * @param  callable|string  $callback
1434
     * @param  int  $options
1435
     * @return static
1436
     */
1437 1
    public function sortByDesc($callback, $options = SORT_REGULAR)
1438
    {
1439 1
        return $this->sortBy($callback, $options, true);
1440
    }
1441
1442
    /**
1443
     * Splice a portion of the underlying collection array.
1444
     *
1445
     * @param  int  $offset
1446
     * @param  int|null  $length
1447
     * @param  mixed  $replacement
1448
     * @return static
1449
     */
1450 1
    public function splice($offset, $length = null, $replacement = [])
1451
    {
1452 1
        if (func_num_args() == 1) {
1453 1
            return new static(array_splice($this->items, $offset));
1454
        }
1455
1456 1
        return new static(array_splice($this->items, $offset, $length, $replacement));
1457
    }
1458
1459
    /**
1460
     * Get the sum of the given values.
1461
     *
1462
     * @param  callable|string|null  $callback
1463
     * @return mixed
1464
     */
1465 8
    public function sum($callback = null)
1466
    {
1467 8
        if (is_null($callback)) {
1468 6
            return array_sum($this->items);
1469
        }
1470
1471 3
        $callback = $this->valueRetriever($callback);
1472
1473 3
        return $this->reduce(function ($result, $item) use ($callback) {
1474 2
            return $result + $callback($item);
1475 3
        }, 0);
1476
    }
1477
1478
    /**
1479
     * Take the first or last {$limit} items.
1480
     *
1481
     * @param  int  $limit
1482
     * @return static
1483
     */
1484 2
    public function take($limit)
1485
    {
1486 2
        if ($limit < 0) {
1487 1
            return $this->slice($limit, abs($limit));
1488
        }
1489
1490 1
        return $this->slice(0, $limit);
1491
    }
1492
1493
    /**
1494
     * Pass the collection to the given callback and then return it.
1495
     *
1496
     * @param  callable  $callback
1497
     * @return $this
1498
     */
1499 1
    public function tap(callable $callback)
1500
    {
1501 1
        $callback(new static($this->items));
1502
1503 1
        return $this;
1504
    }
1505
1506
    /**
1507
     * Transform each item in the collection using a callback.
1508
     *
1509
     * @param  callable  $callback
1510
     * @return $this
1511
     */
1512 1
    public function transform(callable $callback)
1513
    {
1514 1
        $this->items = $this->map($callback)->all();
1515
1516 1
        return $this;
1517
    }
1518
1519
    /**
1520
     * Return only unique items from the collection array.
1521
     *
1522
     * @param  string|callable|null  $key
1523
     * @param  bool  $strict
1524
     * @return static
1525
     */
1526 5
    public function unique($key = null, $strict = false)
1527
    {
1528 5
        $callback = $this->valueRetriever($key);
1529
1530 5
        $exists = [];
1531
1532 5
        return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) {
1533 5
            if (in_array($id = $callback($item, $key), $exists, $strict)) {
1534 5
                return true;
1535
            }
1536
1537 5
            $exists[] = $id;
1538 5
        });
1539
    }
1540
1541
    /**
1542
     * Return only unique items from the collection array using strict comparison.
1543
     *
1544
     * @param  string|callable|null  $key
1545
     * @return static
1546
     */
1547 1
    public function uniqueStrict($key = null)
1548
    {
1549 1
        return $this->unique($key, true);
1550
    }
1551
1552
    /**
1553
     * Reset the keys on the underlying array.
1554
     *
1555
     * @return static
1556
     */
1557 30
    public function values()
1558
    {
1559 30
        return new static(array_values($this->items));
1560
    }
1561
1562
    /**
1563
     * Get a value retrieving callback.
1564
     *
1565
     * @param  string  $value
1566
     * @return callable
1567
     */
1568 32
    protected function valueRetriever($value)
1569
    {
1570 32
        if ($this->useAsCallable($value)) {
1571 22
            return $value;
1572
        }
1573
1574 19
        return function ($item) use ($value) {
1575 18
            return data_get($item, $value);
1576 19
        };
1577
    }
1578
1579
    /**
1580
     * Zip the collection together with one or more arrays.
1581
     *
1582
     * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1583
     *      => [[1, 4], [2, 5], [3, 6]]
1584
     *
1585
     * @param  mixed ...$items
1586
     * @return static
1587
     */
1588
    public function zip($items)
1589
    {
1590 1
        $arrayableItems = array_map(function ($items) {
1591 1
            return $this->getArrayableItems($items);
1592 1
        }, func_get_args());
1593
1594 1
        $params = array_merge([function () {
1595 1
            return new static(func_get_args());
1596 1
        }, $this->items], $arrayableItems);
1597
1598 1
        return new static(call_user_func_array('array_map', $params));
1599
    }
1600
1601
    /**
1602
     * Pad collection to the specified length with a value.
1603
     *
1604
     * @param  int  $size
1605
     * @param  mixed  $value
1606
     * @return static
1607
     */
1608 1
    public function pad($size, $value)
1609
    {
1610 1
        return new static(array_pad($this->items, $size, $value));
1611
    }
1612
1613
    /**
1614
     * Get the collection of items as a plain array.
1615
     *
1616
     * @return array
1617
     */
1618
    public function toArray()
1619
    {
1620 46
        return array_map(function ($value) {
1621 43
            return $value instanceof Arrayable ? $value->toArray() : $value;
1622 46
        }, $this->items);
1623
    }
1624
1625
    /**
1626
     * Convert the object into something JSON serializable.
1627
     *
1628
     * @return array
1629
     */
1630
    public function jsonSerialize()
1631
    {
1632 2
        return array_map(function ($value) {
1633 2
            if ($value instanceof JsonSerializable) {
0 ignored issues
show
Bug introduced by
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...
1634 2
                return $value->jsonSerialize();
1635 2
            } elseif ($value instanceof Jsonable) {
1636 1
                return json_decode($value->toJson(), true);
1637 2
            } elseif ($value instanceof Arrayable) {
1638 2
                return $value->toArray();
1639
            }
1640
1641 1
            return $value;
1642 2
        }, $this->items);
1643
    }
1644
1645
    /**
1646
     * Get the collection of items as JSON.
1647
     *
1648
     * @param  int  $options
1649
     * @return string
1650
     */
1651 2
    public function toJson($options = 0)
1652
    {
1653 2
        return json_encode($this->jsonSerialize(), $options);
1654
    }
1655
1656
    /**
1657
     * Get an iterator for the items.
1658
     *
1659
     * @return \ArrayIterator
1660
     */
1661 5
    public function getIterator()
1662
    {
1663 5
        return new ArrayIterator($this->items);
1664
    }
1665
1666
    /**
1667
     * Get a CachingIterator instance.
1668
     *
1669
     * @param  int  $flags
1670
     * @return \CachingIterator
1671
     */
1672 1
    public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
1673
    {
1674 1
        return new CachingIterator($this->getIterator(), $flags);
1675
    }
1676
1677
    /**
1678
     * Count the number of items in the collection.
1679
     *
1680
     * @return int
1681
     */
1682 21
    public function count()
1683
    {
1684 21
        return count($this->items);
1685
    }
1686
1687
    /**
1688
     * Get a base Support collection instance from this collection.
1689
     *
1690
     * @return \IlluminateAgnostic\Arr\Support\Collection
1691
     */
1692
    public function toBase()
1693
    {
1694
        return new self($this);
1695
    }
1696
1697
    /**
1698
     * Determine if an item exists at an offset.
1699
     *
1700
     * @param  mixed  $key
1701
     * @return bool
1702
     */
1703 16
    public function offsetExists($key)
1704
    {
1705 16
        return array_key_exists($key, $this->items);
1706
    }
1707
1708
    /**
1709
     * Get an item at a given offset.
1710
     *
1711
     * @param  mixed  $key
1712
     * @return mixed
1713
     */
1714 17
    public function offsetGet($key)
1715
    {
1716 17
        return $this->items[$key];
1717
    }
1718
1719
    /**
1720
     * Set the item at a given offset.
1721
     *
1722
     * @param  mixed  $key
1723
     * @param  mixed  $value
1724
     * @return void
1725
     */
1726 30
    public function offsetSet($key, $value)
1727
    {
1728 30
        if (is_null($key)) {
1729 15
            $this->items[] = $value;
1730
        } else {
1731 17
            $this->items[$key] = $value;
1732
        }
1733 30
    }
1734
1735
    /**
1736
     * Unset the item at a given offset.
1737
     *
1738
     * @param  string  $key
1739
     * @return void
1740
     */
1741 4
    public function offsetUnset($key)
1742
    {
1743 4
        unset($this->items[$key]);
1744 4
    }
1745
1746
    /**
1747
     * Convert the collection to its string representation.
1748
     *
1749
     * @return string
1750
     */
1751 1
    public function __toString()
1752
    {
1753 1
        return $this->toJson();
1754
    }
1755
1756
    /**
1757
     * Results array of items from Collection or Arrayable.
1758
     *
1759
     * @param  mixed  $items
1760
     * @return array
1761
     */
1762 208
    protected function getArrayableItems($items)
1763
    {
1764 208
        if (is_array($items)) {
1765 202
            return $items;
1766 31
        } elseif ($items instanceof self) {
1767 17
            return $items->all();
1768 15
        } elseif ($items instanceof Arrayable) {
1769 1
            return $items->toArray();
1770 15
        } elseif ($items instanceof Jsonable) {
1771 1
            return json_decode($items->toJson(), true);
1772 15
        } elseif ($items instanceof JsonSerializable) {
0 ignored issues
show
Bug introduced by
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...
1773 1
            return $items->jsonSerialize();
1774 14
        } elseif ($items instanceof Traversable) {
1775 2
            return iterator_to_array($items);
1776
        }
1777
1778 12
        return (array) $items;
1779
    }
1780
1781
    /**
1782
     * Add a method to the list of proxied methods.
1783
     *
1784
     * @param  string  $method
1785
     * @return void
1786
     */
1787 1
    public static function proxy($method)
1788
    {
1789 1
        static::$proxies[] = $method;
1790 1
    }
1791
1792
    /**
1793
     * Dynamically access collection proxies.
1794
     *
1795
     * @param  string  $key
1796
     * @return mixed
1797
     *
1798
     * @throws \Exception
1799
     */
1800 12
    public function __get($key)
1801
    {
1802 12
        if (! in_array($key, static::$proxies)) {
1803 1
            throw new Exception("Property [{$key}] does not exist on this collection instance.");
1804
        }
1805
1806 11
        return new HigherOrderCollectionProxy($this, $key);
1807
    }
1808
}
1809