Collection::range()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 3
rs 10
1
<?php 
2
3
/**
4
 * Lenevor Framework
5
 *
6
 * LICENSE
7
 *
8
 * This source file is subject to the new BSD license that is bundled
9
 * with this package in the file license.md.
10
 * It is also available through the world-wide-web at this URL:
11
 * https://lenevor.com/license
12
 * If you did not receive a copy of the license and are unable to
13
 * obtain it through the world-wide-web, please send an email
14
 * to [email protected] so we can send you a copy immediately.
15
 *
16
 * @package     Lenevor
17
 * @subpackage  Base
18
 * @link        https://lenevor.com
19
 * @copyright   Copyright (c) 2019 - 2021 Alexander Campo <[email protected]>
20
 * @license     https://opensource.org/licenses/BSD-3-Clause New BSD license or see https://lenevor.com/license or see /license.md
21
 */
22
23
namespace Syscodes\Collections;
24
25
use Countable;
26
use ArrayAccess;
27
use ArrayIterator;
28
use IteratorAggregate;
29
use Syscodes\Contracts\Support\Jsonable;
30
use Syscodes\Contracts\Support\Arrayable;
31
use Syscodes\Collections\Traits\Enumerates;
32
33
/**
34
 * Allows provide a way for working with arrays of data.
35
 * 
36
 * @author Alexander Campo <[email protected]>
37
 */
38
class Collection implements ArrayAccess, IteratorAggregate, Countable
39
{
40
    use Enumerates;
41
42
    /**
43
     * The items contained in the collection.
44
     * 
45
     * @var array $items
46
     */
47
    protected $items = [];
48
49
    /**
50
     * Constructor. Create a new Collection instance.
51
     * 
52
     * @param  mixed  $items
53
     * 
54
     * @return void
55
     */
56
    public function __construct($items = [])
57
    {
58
        $this->items = $this->getArrayItems($items);
59
    }
60
61
    /**
62
     * Get all of the items in the collection.
63
     * 
64
     * @return array
65
     */
66
    public function all()
67
    {
68
        return $this->items;
69
    }
70
71
    /**
72
     * Collapse the collection items into a single array.
73
     * 
74
     * @return static
75
     */
76
    public function collapse()
77
    {
78
        return new static(Arr::collapse($this->items));
79
    }
80
81
    /**
82
     * Diff the collection with the given items.
83
     * 
84
     * @param  mixed  $items
85
     * 
86
     * @return static
87
     */
88
    public function diff($items)
89
    {
90
        return new static(array_diff($this->items, $this->getArrayItems($items)));
91
    }
92
93
    /**
94
     * Returns the items in a collection that are not present 
95
     * in the given items, using the callback.
96
     * 
97
     * @param  mixed  $items
98
     * @param  \callable  $callback
0 ignored issues
show
Bug introduced by
The type callable was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
99
     * 
100
     * @return static
101
     */
102
    public function diffUsing($items, callable $callback)
103
    {
104
        return new static(array_udiff($this->items, $this->getArrayItems($items), $callback));
105
    }
106
107
    /**
108
     * Returns the items in the collection when the keys and values 
109
     * are not present in the given items.
110
     * 
111
     * @param  mixed  $items
112
     * 
113
     * @return static
114
     */
115
    public function diffAssoc($items)
116
    {
117
        return new static(array_diff_assoc($this->items, $this->getArrayItems($items)));
118
    }
119
120
    /**
121
     * Returns the items in the collection when the keys and values 
122
     * are not present in the given items, using the callback.
123
     * 
124
     * @param  mixed  $items
125
     * @param  \callable  $callback
126
     * 
127
     * @return static
128
     */
129
    public function diffAssocUsing($items, callable $callback)
130
    {
131
        return new static(array_diff_uassoc($this->items, $this->getArrayItems($items), $callback));
132
    }
133
134
    /**
135
     * Returns the items in the collection when the keys 
136
     * are not present in the given items.
137
     * 
138
     * @param  mixed  $items
139
     * 
140
     * @return static
141
     */
142
    public function diffKeys($items)
143
    {
144
        return new static(array_diff_key($this->items, $this->getArrayItems($items)));
145
    }
146
147
    /**
148
     * Returns the items in the collection when the keys are 
149
     * not present in the given items, using the callback.
150
     * 
151
     * @param  mixed  $items
152
     * @param  \callable  $callback
153
     * 
154
     * @return static
155
     */
156
    public function diffKeyUsing($items, callable $callback)
157
    {
158
        return new static(array_diff_ukey($this->items, $this->getArrayItems($items), $callback));
159
    }
160
161
    /**
162
     * Execute a callback over each item.
163
     * 
164
     * @param  \callable  $callback
165
     * 
166
     * @return $this
167
     */
168
    public function each(callable $callback)
169
    {
170
        array_map($callback, $this->items);
171
172
        return $this;
173
    }
174
175
    /**
176
     * Run a filter over each of the items.
177
     * 
178
     * @param  \callable|null  $callback
179
     * 
180
     * @return static
181
     */
182
    public function filter(callable $callback = null)
183
    {
184
        if ($callback) {
185
            return new static(Arr::where($this->items, $callback));
186
        }
187
188
        return new static(array_filter($this->items));
189
    }
190
191
    /**
192
     * Get the first item from the collection.
193
     * 
194
     * @param  \callable|null  $callback
195
     * @param  mixed  $default
196
     * 
197
     * @return mixed
198
     */
199
    public function first(callable $callback = null, $default = null)
200
    {
201
        if (is_null($callback)) {
202
            return count($this->items) > 0 ? head($this->items) : null;
203
        } else {
204
            return Arr::first($this->items, $callback, $default);
205
        }
206
    }
207
208
    /**
209
     * Flip the items in the collection.
210
     * 
211
     * @return static
212
     */
213
    public function flip()
214
    {
215
        return new static(array_flip($this->items));
216
    }
217
218
    /**
219
     * Get a flattened array of the items in the collection.
220
     * 
221
     * @return static
222
     */
223
    public function flatten()
224
    {
225
        return new static(Arr::flatten($this->items));
226
    }
227
228
    /**
229
     * Determine if an item exists in the collection by key.
230
     * 
231
     * @param  mixed  $keys
232
     * 
233
     * @return bool
234
     */
235
    public function has($key)
236
    {
237
        return Arr::has($this->items, $key);
238
    }
239
240
    /**
241
     * Remove an item from the collection by key.
242
     * 
243
     * @param  string|array  $keys
244
     * 
245
     * @return $this
246
     */
247
    public function erase($keys)
248
    {
249
        foreach ((array) $keys as $key) {
250
            $this->offsetUnset($key);
251
        }
252
253
        return $this;
254
    }
255
256
    /**
257
     * Run a map over each of the items.
258
     * 
259
     * @param  \callable  $callback
260
     * 
261
     * @return static
262
     */
263
    public function map(callable $callback)
264
    {
265
        $keys = array_keys($this->items);
266
267
        $items = array_map($callback, $this->items, $keys);
268
269
        return new static(array_combine($keys, $items));
270
    }
271
272
     /**
273
     * Reset the keys of the collection.
274
     * 
275
     * @return static
276
     */
277
    public function keys()
278
    {
279
        return new static(array_keys($this->items));
280
    }
281
282
    /**
283
     * Merge the collection with the given items.
284
     * 
285
     * @param  mixed  $items
286
     * 
287
     * @return static
288
     */
289
    public function merge(array $items)
290
    {
291
        return new static(array_merge($this->items, $this->getArrayItems($items)));
292
    }
293
294
    /**
295
     * Recursively Merge the collection with the given items.
296
     * 
297
     * @param  mixed  $items
298
     * 
299
     * @return static
300
     */
301
    public function mergeRecursive($items)
302
    {
303
        return new static(array_merge_recursive($this->items, $this->getArrayItems($items)));
304
    }
305
306
    /**
307
     * Creates a collection by using this collection for 
308
     * keys and other its values.
309
     * 
310
     * @param  mixed  $items
311
     * 
312
     * @return static
313
     */
314
    public function combine($items)
315
    {
316
        return new static(array_combine($this->all(), $this->getArrayItems($items)));
317
    }
318
319
    /**
320
     * Intersect the collection with the given items.
321
     * 
322
     * @param  mixed  $items
323
     * 
324
     * @return static
325
     */
326
    public function intersect($items)
327
    {
328
        return new static(array_intersect($this->items, $this->getArrayItems($items)));
329
    }
330
331
    /**
332
     * Intersect the collection with the given items by key.
333
     * 
334
     * @param  mixed  $items
335
     * 
336
     * @return static
337
     */
338
    public function intersectKey($items)
339
    {
340
        return new static(array_intersect_key($this->items, $this->getArrayItems($items)));
341
    }
342
343
    /**
344
     * Determine if the collection is empty or not.
345
     * 
346
     * @return bool
347
     */
348
    public function isEmpty()
349
    {
350
        return empty($this->items);
351
    }
352
353
    /**
354
     * Get the last item from the collection.
355
     * 
356
     * @param  \callable|null  $callback
357
     * @param  mixed|null  $default
358
     * 
359
     * @return mixed
360
     */
361
    public function last(callable $callback = null, $default = null)
362
    {
363
        return Arr::last($this->items, $callback, $default);
364
    }
365
366
    /**
367
     * Union the collection with the given items.
368
     * 
369
     * @param  mixed  $items
370
     * 
371
     * @return static
372
     */
373
    public function union($items)
374
    {
375
        return new static($this->items + $this->getArrayItems($items));
376
    }
377
378
    /**
379
     * Create a collection with the given range.
380
     * 
381
     * @param  int  $from
382
     * @param  int  $to
383
     * 
384
     * @return static
385
     */
386
    public function range($from, $to)
387
    {
388
        return new static(range($from, $to));
389
    }
390
391
    /**
392
     * Get and remove the last item from the collection.
393
     * 
394
     * @return mixed
395
     */
396
    public function pop()
397
    {
398
        return array_pop($this->items);
399
    }
400
401
    /**
402
     * Push an item onto the beginning of the collection.
403
     * 
404
     * @param  mixed  $value
405
     * @param  mixed  $key
406
     * 
407
     * @return $this
408
     */
409
    public function prepend($value, $key = null)
410
    {
411
        return Arr::prepend($this->items, $value, $key);
0 ignored issues
show
Bug Best Practice introduced by
The expression return Syscodes\Collecti...s->items, $value, $key) returns the type array which is incompatible with the documented return type Syscodes\Collections\Collection.
Loading history...
412
    }
413
414
    /**
415
     * Push an item onto the end of the collection.
416
     * 
417
     * @param  mixed  $values  [optional]
418
     * 
419
     * @return $this
420
     */
421
    public function push(...$values)
422
    {
423
        foreach ($values as $value) {
424
            $this->items[] = $value;
425
        }
426
427
        return $this;
428
    }
429
430
    /**
431
     * Put an item in the collection by key.
432
     * 
433
     * @param  mixed  $key
434
     * @param  mixed  $value
435
     * 
436
     * @return $this
437
     */
438
    public function put($key, $value)
439
    {
440
        $this->offsetSet($key, $value);
441
442
        return $this;
443
    }
444
445
    /**
446
     * Get and remove an item from the collection.
447
     * 
448
     * @param  mixed  $key
449
     * @param  mixed  $default
450
     * 
451
     * @return mixed
452
     */
453
    public function pull($key, $default = null)
454
    {
455
        return Arr::pull($this->items, $key, $default);
456
    }
457
    
458
    /**
459
     * Get the values of a given key.
460
     * 
461
     * @param  string|array|int|null  $value
462
     * @param  string|null  $key
463
     * 
464
     * @return static
465
     */
466
    public function pluck($value, $key = null)
467
    {
468
        return new static(Arr::pluck($this->items, $value, $key));
469
    }
470
471
    /**
472
     * Reduce the collection to a single value.
473
     * 
474
     * @param  \callable  $callback
475
     * @param  mixed  $initial
476
     * 
477
     * @return mixed
478
     */
479
    public function reduce(callable $callback, $initial = null)
480
    {
481
        return array_reduce($this->items, $callback, $initial);
482
    }
483
484
    /**
485
     * Replace the collection items with the given items.
486
     * 
487
     * @param  mixed  $items
488
     * 
489
     * @return static
490
     */
491
    public function replace($items)
492
    {
493
        return new static(array_replace($this->items, $this->getArrayItems($items)));
494
    }
495
496
    /**
497
     * Recursively replace the collection items with the given items.
498
     * 
499
     * @param  mixed  $items
500
     * 
501
     * @return static
502
     */
503
    public function replaceRecursive($items)
504
    {
505
        return new static(array_replace_recursive($this->items, $this->getArrayItems($items)));
506
    }
507
508
    /**
509
     * Reverse items order.
510
     * 
511
     * @return static
512
     */
513
    public function reverse()
514
    {
515
        return new static(array_reverse($this->items, true));
516
    }
517
518
    /**
519
     * Search the collection for a given value and return the corresponding key if successful.
520
     * 
521
     * @param  mixed  $value
522
     * @param  bool  $strict  (false by default)
523
     * 
524
     * @return mixed
525
     */
526
    public function search($value, $strict = false)
527
    {
528
        if ( ! $this->usesAscallable($value)) {
0 ignored issues
show
Bug introduced by
The method usesAscallable() does not exist on Syscodes\Collections\Collection. Did you maybe mean useAsCallable()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

528
        if ( ! $this->/** @scrutinizer ignore-call */ usesAscallable($value)) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
529
            return array_search($value, $this->items, $strict);
530
        }
531
532
        foreach($this->items as $key => $item) {
533
            if ($value($item, $key)) {
534
                return $key;
535
            }
536
        }
537
538
        return false;
539
    }
540
541
    /**
542
     * Get one or more items randomly from the collection.
543
     * 
544
     * @param  int  $amount  (1 by default)
545
     * 
546
     * @return mixed
547
     */
548
    public function random($amount = 1)
549
    {
550
        $keys = array_rand($this->items, $amount);
551
552
        return is_array($keys) ? array_intersect_key($this->items, array_flip($keys)) : $this->items[$keys];
553
    }
554
555
    /**
556
     * Slice the underlying collection array.
557
     * 
558
     * @param  int  $offset
559
     * @param  int|null  $length
560
     * 
561
     * @return static
562
     */
563
    public function slice($offset, $length = null)
564
    {
565
        return new static(array_slice($this->items, $offset, $length, true));
566
    }
567
568
    /**
569
     * Chunk the underlying collection array.
570
     * 
571
     * @param  int  $size
572
     * 
573
     * @return static
574
     */
575
    public function chunk($size)
576
    {
577
        if ($size <= 0) {
578
            return new static;
579
        }
580
581
        $chunks = [];
582
583
        foreach (array_chunk($this->items, $size, true) as $chunk) {
584
            $chunks[] = $chunk;
585
        }
586
587
        return new static($chunks);
588
    }
589
590
    /**
591
     * Get and remove the first item from the collection.
592
     * 
593
     * @return void
594
     */
595
    public function shift()
596
    {
597
        return array_shift($this->items);
598
    }
599
600
    /**
601
     * Splice portion of the underlying collection array.
602
     * 
603
     * @param  int  $offset
604
     * @param  int|null  $length
605
     * @param  mixed  $replacement
606
     * 
607
     * @return static
608
     */
609
    public function splice($offset, $length = null, $replacement = [])
610
    {
611
        if (func_num_args() == 1) {
612
            return new static(array_splice($this->items, $offset));
613
        }
614
615
        return new static(array_splice($this->items, $offset, $length, $replacement));
616
    }
617
618
    /**
619
     * Take the first or last {$limit} items.
620
     * 
621
     * @param  int  $limit
622
     * 
623
     * @return static
624
     */
625
    public function take($limit)
626
    {
627
        if ($limit < 0) {
628
            $this->slice($limit, abs($limit));
0 ignored issues
show
Bug introduced by
It seems like abs($limit) can also be of type double; however, parameter $length of Syscodes\Collections\Collection::slice() does only seem to accept integer|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

628
            $this->slice($limit, /** @scrutinizer ignore-type */ abs($limit));
Loading history...
629
        }
630
631
        return $this->slice(0, $limit);
632
    }
633
634
    /**
635
     * Pad collection to the specified length with a value.
636
     * 
637
     * @param  int  $size
638
     * @param  mixed  $value
639
     * 
640
     * @return static
641
     */
642
    public function pad($size, $value)
643
    {
644
        return new static(array_pad($this->items, $size, $value));
645
    }
646
647
    /**
648
     * Return only unique items from the collection array.
649
     * 
650
     * @return static
651
     */
652
    public function unique()
653
    {
654
        return new static(array_unique($this->items));
655
    }
656
657
    /**
658
     * Add an item in the collection.
659
     * 
660
     * @param  mixed  $item
661
     * 
662
     * @return $this
663
     */
664
    public function add($item)
665
    {
666
        $this->items[] = $item;
667
668
        return $this;
669
    }
670
671
    /**
672
     * Reset the keys on the underlying array.
673
     * 
674
     * @return static
675
     */
676
    public function values()
677
    {
678
        return new static(array_values($this->items));
679
    }
680
681
    /**
682
     * Results array of items from Collection.
683
     * 
684
     * @param  \Syscodes\Collections\Collection|array  $items
685
     * 
686
     * @return array
687
     */
688
    private function getArrayItems($items)
689
    {
690
        if (is_array($items)) {
691
            return $items;
692
        } elseif($items instanceof Arrayable) {
693
            return $items->toArray();
694
        } elseif ($items instanceof Jsonable) {
695
            return json_decode($items->toJson(), true);
696
        } elseif ($items instanceof Collection) {
0 ignored issues
show
introduced by
$items is always a sub-type of Syscodes\Collections\Collection.
Loading history...
697
            return $items->all();
698
        }
699
700
        return (array) $items;
701
    }
702
703
    /*
704
    |-----------------------------------------------------------------
705
    | ArrayIterator Methods
706
    |-----------------------------------------------------------------
707
    */
708
709
    /**
710
     * Get an iterator for the items.
711
     * 
712
     * @return \ArrayIterator
713
     */
714
    public function getIterator()
715
    {
716
        return new ArrayIterator($this->items);
717
    }
718
719
    /*
720
    |-----------------------------------------------------------------
721
    | Countable Methods
722
    |-----------------------------------------------------------------
723
    */
724
725
    /**
726
     * Count the number of items in the collection.
727
     * 
728
     * @return int
729
     */
730
    public function count()
731
    {
732
        return count($this->items);
733
    }
734
735
    /*
736
    |-----------------------------------------------------------------
737
    | ArrayAccess Methods
738
    |-----------------------------------------------------------------
739
    */
740
741
    /**
742
     * Determine if a given offset exists.
743
     * 
744
     * @param  string  $offset
745
     * 
746
     * @return bool
747
     */
748
    public function offsetExists($offset)
749
    {
750
        return isset($this->items[$offset]);
751
    }
752
753
    /**
754
     * Get the value at a given offset.
755
     * 
756
     * @param  string  $offset
757
     * 
758
     * @return mixed
759
     */
760
    public function offsetGet($offset)
761
    {
762
        return $this->items[$offset];
763
    }
764
765
    /**
766
     * Set the value at a given offset.
767
     * 
768
     * @param  string  $offset
769
     * @param  mixed  $value
770
     * 
771
     * @return void
772
     */
773
    public function offsetSet($offset, $value)
774
    {
775
        if (is_null($offset)) {
0 ignored issues
show
introduced by
The condition is_null($offset) is always false.
Loading history...
776
            $this->items[] = $value;
777
        } else {
778
            $this->items[$offset] = $value;
779
        }
780
    }
781
782
    /**
783
     * Unset the value at a given offset.
784
     * 
785
     * @param  string  $offset
786
     * 
787
     * @return void
788
     */
789
    public function offsetUnset($offset)
790
    {
791
        unset($this->items[$offset]);
792
    }
793
}