Collection::intersect()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Magister\Services\Support;
4
5
use ArrayAccess;
6
use ArrayIterator;
7
use Countable;
8
use IteratorAggregate;
9
use Magister\Services\Contracts\Support\Arrayable;
10
use Magister\Services\Contracts\Support\Jsonable;
11
12
/**
13
 * Class Collection.
14
 */
15
class Collection implements Arrayable, ArrayAccess, Countable, IteratorAggregate, Jsonable
16
{
17
    /**
18
     * The items in the collection.
19
     *
20
     * @var array
21
     */
22
    protected $items = [];
23
24
    /**
25
     * Create a new collection instance.
26
     *
27
     * @param array $items
28
     */
29
    public function __construct($items = [])
30
    {
31
        $this->items = is_array($items) ? $items : $this->getArrayableItems($items);
32
    }
33
34
    /**
35
     * Create a new collection instance if the value isn't one already.
36
     *
37
     * @param mixed $items
38
     *
39
     * @return static
40
     */
41
    public static function make($items = null)
42
    {
43
        return new static($items);
44
    }
45
46
    /**
47
     * Return all the items inside the collection.
48
     *
49
     * @return array
50
     */
51
    public function all()
52
    {
53
        return $this->items;
54
    }
55
56
    /**
57
     * Determine if an item exists in the collection.
58
     *
59
     * @param mixed $key
60
     * @param mixed $value
61
     *
62
     * @return bool
63
     */
64
    public function contains($key, $value = null)
65
    {
66
        if (func_num_args() == 2) {
67
            return $this->contains(function ($k, $item) use ($key, $value) {
68
                return data_get($item, $key) == $value;
69
            });
70
        }
71
72
        if ($this->useAsCallable($key)) {
73
            return !is_null($this->first($key));
74
        }
75
76
        return in_array($key, $this->items);
77
    }
78
79
    /**
80
     * Diff the collection with the given items.
81
     *
82
     * @param mixed $items
83
     *
84
     * @return static
85
     */
86
    public function diff($items)
87
    {
88
        return new static(array_diff($this->items, $this->getArrayableItems($items)));
89
    }
90
91
    /**
92
     * Execute a callback over each item.
93
     *
94
     * @param callable $callback
95
     *
96
     * @return $this
97
     */
98
    public function each(callable $callback)
99
    {
100
        array_map($callback, $this->items);
101
102
        return $this;
103
    }
104
105
    /**
106
     * Run a filter over each of the items.
107
     *
108
     * @param callable|null $callback
109
     *
110
     * @return static
111
     */
112
    public function filter(callable $callback = null)
113
    {
114
        if ($callback) {
115
            return new static(array_filter($this->items, $callback));
116
        }
117
118
        return new static(array_filter($this->items));
119
    }
120
121
    /**
122
     * Filter items by the given key value pair.
123
     *
124
     * @param string $key
125
     * @param mixed  $value
126
     * @param bool   $strict
127
     *
128
     * @return static
129
     */
130
    public function where($key, $value, $strict = true)
131
    {
132
        return $this->filter(function ($item) use ($key, $value, $strict) {
133
            return $strict ? data_get($item, $key) === $value : data_get($item, $key) == $value;
134
        });
135
    }
136
137
    /**
138
     * Filter items by the given key value pair using loose comparison.
139
     *
140
     * @param string $key
141
     * @param mixed  $value
142
     *
143
     * @return static
144
     */
145
    public function whereLoose($key, $value)
146
    {
147
        return $this->where($key, $value, false);
148
    }
149
150
    /**
151
     * Find a model in the collection by key.
152
     *
153
     * @param mixed $key
154
     * @param mixed $default
155
     *
156
     * @return \Magister\Services\Database\Elegant\Model
157
     */
158
    public function find($key, $default = null)
159
    {
160
        return array_first($this->items, function ($itemKey, $model) use ($key) {
0 ignored issues
show
Unused Code introduced by
The parameter $model is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
161
            return $itemKey == $key;
162
        }, $default);
163
    }
164
165
    /**
166
     * Get the first item from the collection.
167
     *
168
     * @param callable $callback
169
     * @param mixed    $default
170
     *
171
     * @return mixed|null
172
     */
173
    public function first(callable $callback = null, $default = null)
174
    {
175
        if (is_null($callback)) {
176
            return count($this->items) > 0 ? reset($this->items) : null;
177
        }
178
179
        return array_first($this->items, $callback, $default);
180
    }
181
182
    /**
183
     * Get a flattened array of the items in the collection.
184
     *
185
     * @return static
186
     */
187
    public function flatten()
188
    {
189
        return new static(array_flatten($this->items));
190
    }
191
192
    /**
193
     * Flip the items in the collection.
194
     *
195
     * @return static
196
     */
197
    public function flip()
198
    {
199
        return new static(array_flip($this->items));
200
    }
201
202
    /**
203
     * Remove an item from the collection by key.
204
     *
205
     * @param mixed $key
206
     *
207
     * @return void
208
     */
209
    public function forget($key)
210
    {
211
        unset($this->items[$key]);
212
    }
213
214
    /**
215
     * Get an item from the collection by key.
216
     *
217
     * @param mixed $key
218
     * @param mixed $default
219
     *
220
     * @return mixed
221
     */
222
    public function get($key, $default = null)
223
    {
224
        if ($this->has($key)) {
225
            return $this->items[$key];
226
        }
227
228
        return $default;
229
    }
230
231
    /**
232
     * Group an associative array by a field or using a callback.
233
     *
234
     * @param callable|string $groupBy
235
     * @param bool            $preserveKeys
236
     *
237
     * @return static
238
     */
239
    public function groupBy($groupBy, $preserveKeys = false)
240
    {
241
        $groupBy = $this->valueRetriever($groupBy);
0 ignored issues
show
Documentation introduced by
$groupBy is of type callable, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
242
243
        $results = [];
244
245
        foreach ($this->items as $key => $value) {
246
            $groupKey = $groupBy($value, $key);
247
248
            if (!array_key_exists($groupKey, $results)) {
249
                $results[$groupKey] = new static();
250
            }
251
252
            $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);
253
        }
254
255
        return new static($results);
256
    }
257
258
    /**
259
     * Key an associative array by a field or using a callback.
260
     *
261
     * @param callable|string $keyBy
262
     *
263
     * @return static
264
     */
265
    public function keyBy($keyBy)
266
    {
267
        $keyBy = $this->valueRetriever($keyBy);
0 ignored issues
show
Documentation introduced by
$keyBy is of type callable, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
268
269
        $results = [];
270
271
        foreach ($this->items as $item) {
272
            $results[$keyBy($item)] = $item;
273
        }
274
275
        return new static($results);
276
    }
277
278
    /**
279
     * Determine if an item exists in the collection by key.
280
     *
281
     * @param mixed $key
282
     *
283
     * @return bool
284
     */
285
    public function has($key)
286
    {
287
        return array_key_exists($key, $this->items);
288
    }
289
290
    /**
291
     * Concatenate values of a given key as a string.
292
     *
293
     * @param string $value
294
     * @param string $glue
295
     *
296
     * @return string
297
     */
298
    public function implode($value, $glue = null)
299
    {
300
        $first = $this->first();
301
302
        if (is_array($first) || is_object($first)) {
303
            return implode($glue, $this->pluck($value)->all());
304
        }
305
306
        return implode($value, $this->items);
307
    }
308
309
    /**
310
     * Intersect the collection with the given items.
311
     *
312
     * @param mixed $items
313
     *
314
     * @return static
315
     */
316
    public function intersect($items)
317
    {
318
        return new static(array_intersect($this->items, $this->getArrayableItems($items)));
319
    }
320
321
    /**
322
     * Determine if the collection is empty.
323
     *
324
     * @return bool
325
     */
326
    public function isEmpty()
327
    {
328
        return empty($this->items);
329
    }
330
331
    /**
332
     * Determine if the given value is callable, but not a string.
333
     *
334
     * @param mixed $value
335
     *
336
     * @return bool
337
     */
338
    protected function useAsCallable($value)
339
    {
340
        return !is_string($value) && is_callable($value);
341
    }
342
343
    /**
344
     * Get the keys of the collection items.
345
     *
346
     * @return static
347
     */
348
    public function keys()
349
    {
350
        return new static(array_keys($this->items));
351
    }
352
353
    /**
354
     * Get the last item from the collection.
355
     *
356
     * @return mixed|null
357
     */
358
    public function last()
359
    {
360
        return count($this->items) > 0 ? end($this->items) : null;
361
    }
362
363
    /**
364
     * Get an array with the values of a given key.
365
     *
366
     * @param string $value
367
     * @param string $key
368
     *
369
     * @return static
370
     */
371
    public function pluck($value, $key = null)
372
    {
373
        return new static(array_pluck($this->items, $value, $key));
374
    }
375
376
    /**
377
     * Alias for the "pluck" method.
378
     *
379
     * @param string $value
380
     * @param string $key
381
     *
382
     * @return static
383
     */
384
    public function lists($value, $key = null)
385
    {
386
        return $this->pluck($value, $key);
387
    }
388
389
    /**
390
     * Run a map over each of the items.
391
     *
392
     * @param callable $callback
393
     *
394
     * @return static
395
     */
396
    public function map(callable $callback)
397
    {
398
        $keys = array_keys($this->items);
399
400
        $items = array_map($callback, $this->items, $keys);
401
402
        return new static(array_combine($keys, $items));
403
    }
404
405
    /**
406
     * Merge the collection with the given items.
407
     *
408
     * @param mixed $items
409
     *
410
     * @return static
411
     */
412
    public function merge($items)
413
    {
414
        return new static(array_merge($this->items, $this->getArrayableItems($items)));
415
    }
416
417
    /**
418
     * Get and remove the last item from the collection.
419
     *
420
     * @return mixed|null
421
     */
422
    public function pop()
423
    {
424
        return array_pop($this->items);
425
    }
426
427
    /**
428
     * Push an item onto the beginning of the collection.
429
     *
430
     * @param mixed $value
431
     *
432
     * @return void
433
     */
434
    public function prepend($value)
435
    {
436
        array_unshift($this->items, $value);
437
    }
438
439
    /**
440
     * Put an item in the collection by key.
441
     *
442
     * @param mixed $key
443
     * @param mixed $value
444
     *
445
     * @return void
446
     */
447
    public function put($key, $value)
448
    {
449
        $this->items[$key] = $value;
450
    }
451
452
    /**
453
     * Get one or more items randomly from the collection.
454
     *
455
     * @param int $amount
456
     *
457
     * @return mixed
458
     */
459
    public function random($amount = 1)
460
    {
461
        if ($this->isEmpty()) {
462
            return;
463
        }
464
465
        $keys = array_rand($this->items, $amount);
466
467
        return is_array($keys) ? array_intersect_key($this->items, array_flip($keys)) : $this->items[$keys];
468
    }
469
470
    /**
471
     * Reduce the collection to a single value.
472
     *
473
     * @param callable $callback
474
     * @param mixed    $initial
475
     *
476
     * @return mixed
477
     */
478
    public function reduce(callable $callback, $initial = null)
479
    {
480
        return array_reduce($this->items, $callback, $initial);
481
    }
482
483
    /**
484
     * Reverse items order.
485
     *
486
     * @return static
487
     */
488
    public function reverse()
489
    {
490
        return new static(array_reverse($this->items));
491
    }
492
493
    /**
494
     * Get and remove the first item from the collection.
495
     *
496
     * @return mixed|null
497
     */
498
    public function shift()
499
    {
500
        return array_shift($this->items);
501
    }
502
503
    /**
504
     * Shuffle the items in the collection.
505
     *
506
     * @return $this
507
     */
508
    public function shuffle()
509
    {
510
        $items = $this->items;
511
512
        shuffle($items);
513
514
        return new static($items);
515
    }
516
517
    /**
518
     * Slice the underlying collection array.
519
     *
520
     * @param int  $offset
521
     * @param int  $length
522
     * @param bool $preserveKeys
523
     *
524
     * @return static
525
     */
526
    public function slice($offset, $length = null, $preserveKeys = false)
527
    {
528
        return new static(array_slice($this->items, $offset, $length, $preserveKeys));
529
    }
530
531
    /**
532
     * Chunk the underlying collection array.
533
     *
534
     * @param int  $size
535
     * @param bool $preserveKeys
536
     *
537
     * @return static
538
     */
539
    public function chunk($size, $preserveKeys = false)
540
    {
541
        $chunks = [];
542
543
        foreach (array_chunk($this->items, $size, $preserveKeys) as $chunk) {
544
            $chunks[] = new static($chunk);
545
        }
546
547
        return new static($chunks);
548
    }
549
550
    /**
551
     * Sort through each item with a callback.
552
     *
553
     * @param callable $callback
554
     *
555
     * @return $this
556
     */
557
    public function sort(callable $callback)
558
    {
559
        uasort($this->items, $callback);
560
561
        return $this;
562
    }
563
564
    /**
565
     * Sort the collection using the given callback.
566
     *
567
     * @param callable|string $callback
568
     * @param int             $options
569
     * @param bool            $descending
570
     *
571
     * @return static
572
     */
573
    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
574
    {
575
        $results = [];
576
577
        $callback = $this->valueRetriever($callback);
0 ignored issues
show
Documentation introduced by
$callback is of type callable, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
578
579
        foreach ($this->items as $key => $value) {
580
            $results[$key] = $callback($value, $key);
581
        }
582
583
        $descending ? arsort($results, $options) : asort($results, $options);
584
585
        foreach (array_keys($results) as $key) {
586
            $results[$key] = $this->items[$key];
587
        }
588
589
        return new static($results);
590
    }
591
592
    /**
593
     * Sort the collection in descending order using the given callback.
594
     *
595
     * @param callable|string $callback
596
     * @param int             $options
597
     *
598
     * @return static
599
     */
600
    public function sortByDesc($callback, $options = SORT_REGULAR)
601
    {
602
        return $this->sortBy($callback, $options, true);
603
    }
604
605
    /**
606
     * Take the first or last {$limit} items.
607
     *
608
     * @param int $limit
609
     *
610
     * @return static
611
     */
612
    public function take($limit = null)
613
    {
614
        if ($limit < 0) {
615
            return $this->slice($limit, abs($limit));
616
        }
617
618
        return $this->slice(0, $limit);
619
    }
620
621
    /**
622
     * Return only unique items from the collection array.
623
     *
624
     * @return static
625
     */
626
    public function unique()
627
    {
628
        return new static(array_unique($this->items));
629
    }
630
631
    /**
632
     * Reset the keys on the underlying array.
633
     *
634
     * @return static
635
     */
636
    public function values()
637
    {
638
        return new static(array_values($this->items));
639
    }
640
641
    /**
642
     * Get a value retrieving callback.
643
     *
644
     * @param string $value
645
     *
646
     * @return callable
647
     */
648
    protected function valueRetriever($value)
649
    {
650
        if ($this->useAsCallable($value)) {
651
            return $value;
652
        }
653
654
        return function ($item) use ($value) {
655
            return data_get($item, $value);
656
        };
657
    }
658
659
    /**
660
     * Results array of items from Collection or Arrayable.
661
     *
662
     * @param mixed $items
663
     *
664
     * @return array
665
     */
666
    protected function getArrayableItems($items)
667
    {
668
        if ($items instanceof self) {
669
            return $items->all();
670
        } elseif ($items instanceof Arrayable) {
671
            return $items->toArray();
672
        } elseif ($items instanceof Jsonable) {
673
            return json_decode($items->toJson(), true);
674
        }
675
676
        return (array) $items;
677
    }
678
679
    /**
680
     * Get the collection of items as a plain array.
681
     *
682
     * @return array
683
     */
684
    public function toArray()
685
    {
686
        return array_map(function ($value) {
687
            return $value instanceof Arrayable ? $value->toArray() : $value;
688
        }, $this->items);
689
    }
690
691
    /**
692
     * Get the collection of items as JSON.
693
     *
694
     * @param int $options
695
     *
696
     * @return string
697
     */
698
    public function toJson($options = 0)
699
    {
700
        return json_encode($this->toArray(), $options);
701
    }
702
703
    /**
704
     * Get an iterator for the items.
705
     *
706
     * @return \ArrayIterator
707
     */
708
    public function getIterator()
709
    {
710
        return new ArrayIterator($this->items);
711
    }
712
713
    /**
714
     * Count the number of items in the collection.
715
     *
716
     * @return int
717
     */
718
    public function count()
719
    {
720
        return count($this->items);
721
    }
722
723
    /**
724
     * Set the item at a given offset.
725
     *
726
     * @param mixed $key
727
     * @param mixed $value
728
     *
729
     * @return void
730
     */
731
    public function offsetSet($key, $value)
732
    {
733
        $this->put($key, $value);
734
    }
735
736
    /**
737
     * Get an item at a given offset.
738
     *
739
     * @param mixed $key
740
     *
741
     * @return mixed
742
     */
743
    public function offsetGet($key)
744
    {
745
        return $this->get($key);
746
    }
747
748
    /**
749
     * Determine if an item exists at a given offset.
750
     *
751
     * @param mixed $key
752
     *
753
     * @return bool
754
     */
755
    public function offsetExists($key)
756
    {
757
        return $this->has($key);
758
    }
759
760
    /**
761
     * Unset the item at a given offset.
762
     *
763
     * @param string $key
764
     *
765
     * @return void
766
     */
767
    public function offsetUnset($key)
768
    {
769
        $this->forget($key);
770
    }
771
772
    /**
773
     * Convert the collection to its string representation.
774
     *
775
     * @return string
776
     */
777
    public function __toString()
778
    {
779
        return $this->toJson();
780
    }
781
}
782