Completed
Push — master ( 247c5c...61eea1 )
by Antonio Carlos
02:35
created

Collection::contains()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 3
dl 0
loc 14
ccs 7
cts 7
cp 1
crap 3
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace IlluminateAgnostic\Str\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\Str\Support\Debug\Dumper;
15
use IlluminateAgnostic\Str\Support\Traits\Macroable;
16
use IlluminateAgnostic\Str\Contracts\Support\Jsonable;
17
use IlluminateAgnostic\Str\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\Str\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
        return new static(Arr::shuffle($this->items, $seed));
1364
    }
1365
1366
    /**
1367
     * Slice the underlying collection array.
1368
     *
1369
     * @param  int  $offset
1370
     * @param  int  $length
1371
     * @return static
1372
     */
1373 10
    public function slice($offset, $length = null)
1374
    {
1375 10
        return new static(array_slice($this->items, $offset, $length, true));
1376
    }
1377
1378
    /**
1379
     * Split a collection into a certain number of groups.
1380
     *
1381
     * @param  int  $numberOfGroups
1382
     * @return static
1383
     */
1384 4
    public function split($numberOfGroups)
1385
    {
1386 4
        if ($this->isEmpty()) {
1387 1
            return new static;
1388
        }
1389
1390 3
        $groupSize = ceil($this->count() / $numberOfGroups);
1391
1392 3
        return $this->chunk($groupSize);
1393
    }
1394
1395
    /**
1396
     * Chunk the underlying collection array.
1397
     *
1398
     * @param  int  $size
1399
     * @return static
1400
     */
1401 6
    public function chunk($size)
1402
    {
1403 6
        if ($size <= 0) {
1404 2
            return new static;
1405
        }
1406
1407 4
        $chunks = [];
1408
1409 4
        foreach (array_chunk($this->items, $size, true) as $chunk) {
1410 4
            $chunks[] = new static($chunk);
1411
        }
1412
1413 4
        return new static($chunks);
1414
    }
1415
1416
    /**
1417
     * Sort through each item with a callback.
1418
     *
1419
     * @param  callable|null  $callback
1420
     * @return static
1421
     */
1422 9
    public function sort(callable $callback = null)
1423
    {
1424 9
        $items = $this->items;
1425
1426 9
        $callback
1427 1
            ? uasort($items, $callback)
1428 8
            : asort($items);
1429
1430 9
        return new static($items);
1431
    }
1432
1433
    /**
1434
     * Sort the collection using the given callback.
1435
     *
1436
     * @param  callable|string  $callback
1437
     * @param  int  $options
1438
     * @param  bool  $descending
1439
     * @return static
1440
     */
1441 5
    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
1442
    {
1443 5
        $results = [];
1444
1445 5
        $callback = $this->valueRetriever($callback);
1446
1447
        // First we will loop through the items and get the comparator from a callback
1448
        // function which we were given. Then, we will sort the returned values and
1449
        // and grab the corresponding values for the sorted keys from this array.
1450 5
        foreach ($this->items as $key => $value) {
1451 5
            $results[$key] = $callback($value, $key);
1452
        }
1453
1454 5
        $descending ? arsort($results, $options)
1455 5
            : asort($results, $options);
1456
1457
        // Once we have sorted all of the keys in the array, we will loop through them
1458
        // and grab the corresponding model so we can set the underlying items list
1459
        // to the sorted version. Then we'll just return the collection instance.
1460 5
        foreach (array_keys($results) as $key) {
1461 5
            $results[$key] = $this->items[$key];
1462
        }
1463
1464 5
        return new static($results);
1465
    }
1466
1467
    /**
1468
     * Sort the collection in descending order using the given callback.
1469
     *
1470
     * @param  callable|string  $callback
1471
     * @param  int  $options
1472
     * @return static
1473
     */
1474 1
    public function sortByDesc($callback, $options = SORT_REGULAR)
1475
    {
1476 1
        return $this->sortBy($callback, $options, true);
1477
    }
1478
1479
    /**
1480
     * Sort the collection keys.
1481
     *
1482
     * @param  int  $options
1483
     * @param  bool  $descending
1484
     * @return static
1485
     */
1486 2
    public function sortKeys($options = SORT_REGULAR, $descending = false)
1487
    {
1488 2
        $items = $this->items;
1489
1490 2
        $descending ? krsort($items, $options) : ksort($items, $options);
1491
1492 2
        return new static($items);
1493
    }
1494
1495
    /**
1496
     * Sort the collection keys in descending order.
1497
     *
1498
     * @param  int $options
1499
     * @return static
1500
     */
1501
    public function sortKeysDesc($options = SORT_REGULAR)
1502
    {
1503
        return $this->sortKeys($options, true);
1504
    }
1505
1506
    /**
1507
     * Splice a portion of the underlying collection array.
1508
     *
1509
     * @param  int  $offset
1510
     * @param  int|null  $length
1511
     * @param  mixed  $replacement
1512
     * @return static
1513
     */
1514 1
    public function splice($offset, $length = null, $replacement = [])
1515
    {
1516 1
        if (func_num_args() == 1) {
1517 1
            return new static(array_splice($this->items, $offset));
1518
        }
1519
1520 1
        return new static(array_splice($this->items, $offset, $length, $replacement));
1521
    }
1522
1523
    /**
1524
     * Get the sum of the given values.
1525
     *
1526
     * @param  callable|string|null  $callback
1527
     * @return mixed
1528
     */
1529 8
    public function sum($callback = null)
1530
    {
1531 8
        if (is_null($callback)) {
1532 6
            return array_sum($this->items);
1533
        }
1534
1535 3
        $callback = $this->valueRetriever($callback);
1536
1537 3
        return $this->reduce(function ($result, $item) use ($callback) {
1538 2
            return $result + $callback($item);
1539 3
        }, 0);
1540
    }
1541
1542
    /**
1543
     * Take the first or last {$limit} items.
1544
     *
1545
     * @param  int  $limit
1546
     * @return static
1547
     */
1548 2
    public function take($limit)
1549
    {
1550 2
        if ($limit < 0) {
1551 1
            return $this->slice($limit, abs($limit));
1552
        }
1553
1554 1
        return $this->slice(0, $limit);
1555
    }
1556
1557
    /**
1558
     * Pass the collection to the given callback and then return it.
1559
     *
1560
     * @param  callable  $callback
1561
     * @return $this
1562
     */
1563 1
    public function tap(callable $callback)
1564
    {
1565 1
        $callback(new static($this->items));
1566
1567 1
        return $this;
1568
    }
1569
1570
    /**
1571
     * Transform each item in the collection using a callback.
1572
     *
1573
     * @param  callable  $callback
1574
     * @return $this
1575
     */
1576 1
    public function transform(callable $callback)
1577
    {
1578 1
        $this->items = $this->map($callback)->all();
1579
1580 1
        return $this;
1581
    }
1582
1583
    /**
1584
     * Return only unique items from the collection array.
1585
     *
1586
     * @param  string|callable|null  $key
1587
     * @param  bool  $strict
1588
     * @return static
1589
     */
1590 5
    public function unique($key = null, $strict = false)
1591
    {
1592 5
        $callback = $this->valueRetriever($key);
1593
1594 5
        $exists = [];
1595
1596 5
        return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) {
1597 5
            if (in_array($id = $callback($item, $key), $exists, $strict)) {
1598 5
                return true;
1599
            }
1600
1601 5
            $exists[] = $id;
1602 5
        });
1603
    }
1604
1605
    /**
1606
     * Return only unique items from the collection array using strict comparison.
1607
     *
1608
     * @param  string|callable|null  $key
1609
     * @return static
1610
     */
1611 1
    public function uniqueStrict($key = null)
1612
    {
1613 1
        return $this->unique($key, true);
1614
    }
1615
1616
    /**
1617
     * Reset the keys on the underlying array.
1618
     *
1619
     * @return static
1620
     */
1621 32
    public function values()
1622
    {
1623 32
        return new static(array_values($this->items));
1624
    }
1625
1626
    /**
1627
     * Get a value retrieving callback.
1628
     *
1629
     * @param  string  $value
1630
     * @return callable
1631
     */
1632 32
    protected function valueRetriever($value)
1633
    {
1634 32
        if ($this->useAsCallable($value)) {
1635 22
            return $value;
1636
        }
1637
1638 19
        return function ($item) use ($value) {
1639 18
            return data_get($item, $value);
1640 19
        };
1641
    }
1642
1643
    /**
1644
     * Zip the collection together with one or more arrays.
1645
     *
1646
     * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1647
     *      => [[1, 4], [2, 5], [3, 6]]
1648
     *
1649
     * @param  mixed ...$items
1650
     * @return static
1651
     */
1652
    public function zip($items)
1653
    {
1654 1
        $arrayableItems = array_map(function ($items) {
1655 1
            return $this->getArrayableItems($items);
1656 1
        }, func_get_args());
1657
1658 1
        $params = array_merge([function () {
1659 1
            return new static(func_get_args());
1660 1
        }, $this->items], $arrayableItems);
1661
1662 1
        return new static(call_user_func_array('array_map', $params));
1663
    }
1664
1665
    /**
1666
     * Pad collection to the specified length with a value.
1667
     *
1668
     * @param  int  $size
1669
     * @param  mixed  $value
1670
     * @return static
1671
     */
1672 1
    public function pad($size, $value)
1673
    {
1674 1
        return new static(array_pad($this->items, $size, $value));
1675
    }
1676
1677
    /**
1678
     * Get the collection of items as a plain array.
1679
     *
1680
     * @return array
1681
     */
1682
    public function toArray()
1683
    {
1684 48
        return array_map(function ($value) {
1685 45
            return $value instanceof Arrayable ? $value->toArray() : $value;
1686 48
        }, $this->items);
1687
    }
1688
1689
    /**
1690
     * Convert the object into something JSON serializable.
1691
     *
1692
     * @return array
1693
     */
1694
    public function jsonSerialize()
1695
    {
1696 2
        return array_map(function ($value) {
1697 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...
1698 2
                return $value->jsonSerialize();
1699 2
            } elseif ($value instanceof Jsonable) {
1700 1
                return json_decode($value->toJson(), true);
1701 2
            } elseif ($value instanceof Arrayable) {
1702 2
                return $value->toArray();
1703
            }
1704
1705 1
            return $value;
1706 2
        }, $this->items);
1707
    }
1708
1709
    /**
1710
     * Get the collection of items as JSON.
1711
     *
1712
     * @param  int  $options
1713
     * @return string
1714
     */
1715 2
    public function toJson($options = 0)
1716
    {
1717 2
        return json_encode($this->jsonSerialize(), $options);
1718
    }
1719
1720
    /**
1721
     * Get an iterator for the items.
1722
     *
1723
     * @return \ArrayIterator
1724
     */
1725 5
    public function getIterator()
1726
    {
1727 5
        return new ArrayIterator($this->items);
1728
    }
1729
1730
    /**
1731
     * Get a CachingIterator instance.
1732
     *
1733
     * @param  int  $flags
1734
     * @return \CachingIterator
1735
     */
1736 1
    public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
1737
    {
1738 1
        return new CachingIterator($this->getIterator(), $flags);
1739
    }
1740
1741
    /**
1742
     * Count the number of items in the collection.
1743
     *
1744
     * @return int
1745
     */
1746 22
    public function count()
1747
    {
1748 22
        return count($this->items);
1749
    }
1750
1751
    /**
1752
     * Get a base Support collection instance from this collection.
1753
     *
1754
     * @return \IlluminateAgnostic\Str\Support\Collection
1755
     */
1756
    public function toBase()
1757
    {
1758
        return new self($this);
1759
    }
1760
1761
    /**
1762
     * Determine if an item exists at an offset.
1763
     *
1764
     * @param  mixed  $key
1765
     * @return bool
1766
     */
1767 16
    public function offsetExists($key)
1768
    {
1769 16
        return array_key_exists($key, $this->items);
1770
    }
1771
1772
    /**
1773
     * Get an item at a given offset.
1774
     *
1775
     * @param  mixed  $key
1776
     * @return mixed
1777
     */
1778 17
    public function offsetGet($key)
1779
    {
1780 17
        return $this->items[$key];
1781
    }
1782
1783
    /**
1784
     * Set the item at a given offset.
1785
     *
1786
     * @param  mixed  $key
1787
     * @param  mixed  $value
1788
     * @return void
1789
     */
1790 30
    public function offsetSet($key, $value)
1791
    {
1792 30
        if (is_null($key)) {
1793 15
            $this->items[] = $value;
1794
        } else {
1795 17
            $this->items[$key] = $value;
1796
        }
1797 30
    }
1798
1799
    /**
1800
     * Unset the item at a given offset.
1801
     *
1802
     * @param  string  $key
1803
     * @return void
1804
     */
1805 4
    public function offsetUnset($key)
1806
    {
1807 4
        unset($this->items[$key]);
1808 4
    }
1809
1810
    /**
1811
     * Convert the collection to its string representation.
1812
     *
1813
     * @return string
1814
     */
1815 1
    public function __toString()
1816
    {
1817 1
        return $this->toJson();
1818
    }
1819
1820
    /**
1821
     * Results array of items from Collection or Arrayable.
1822
     *
1823
     * @param  mixed  $items
1824
     * @return array
1825
     */
1826 215
    protected function getArrayableItems($items)
1827
    {
1828 215
        if (is_array($items)) {
1829 209
            return $items;
1830 35
        } elseif ($items instanceof self) {
1831 20
            return $items->all();
1832 16
        } elseif ($items instanceof Arrayable) {
1833 1
            return $items->toArray();
1834 16
        } elseif ($items instanceof Jsonable) {
1835 1
            return json_decode($items->toJson(), true);
1836 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...
1837 1
            return $items->jsonSerialize();
1838 15
        } elseif ($items instanceof Traversable) {
1839 2
            return iterator_to_array($items);
1840
        }
1841
1842 13
        return (array) $items;
1843
    }
1844
1845
    /**
1846
     * Add a method to the list of proxied methods.
1847
     *
1848
     * @param  string  $method
1849
     * @return void
1850
     */
1851 1
    public static function proxy($method)
1852
    {
1853 1
        static::$proxies[] = $method;
1854 1
    }
1855
1856
    /**
1857
     * Dynamically access collection proxies.
1858
     *
1859
     * @param  string  $key
1860
     * @return mixed
1861
     *
1862
     * @throws \Exception
1863
     */
1864 12
    public function __get($key)
1865
    {
1866 12
        if (! in_array($key, static::$proxies)) {
1867 1
            throw new Exception("Property [{$key}] does not exist on this collection instance.");
1868
        }
1869
1870 11
        return new HigherOrderCollectionProxy($this, $key);
1871
    }
1872
}
1873