Completed
Push — master ( 6bd308...0b7d57 )
by Antonio Carlos
07:27
created

Collection::getIterator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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