Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
73 / 73
100.00% covered (success)
100.00%
38 / 38
CRAP
100.00% covered (success)
100.00%
1 / 1
Collection
100.00% covered (success)
100.00%
73 / 73
100.00% covered (success)
100.00%
38 / 38
55
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 count
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 first
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 next
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 current
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 last
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 key
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 contains
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 each
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 every
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 filter
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 map
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 flip
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 has
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isEmpty
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 keys
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 values
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 merge
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 forPage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 pop
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 push
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 shift
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 slice
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 splice
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 sort
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 sortByAsc
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 sortByDesc
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 toArray
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getIterator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDataAsArray
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
6
 __set
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 __get
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 __isset
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __unset
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 offsetExists
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 offsetGet
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 offsetSet
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 offsetUnset
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2023 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Utils;
15
16use ReturnTypeWillChange;
17
18/**
19 * Pop utils array object class
20 *
21 * @category   Pop
22 * @package    Pop\Utils
23 * @author     Nick Sagona, III <dev@nolainteractive.com>
24 * @copyright  Copyright (c) 2009-2023 NOLA Interactive, LLC. (http://www.nolainteractive.com)
25 * @license    http://www.popphp.org/license     New BSD License
26 * @version    1.3.0
27 */
28class Collection extends AbstractArray implements \ArrayAccess, \Countable, \IteratorAggregate
29{
30
31    /**
32     * Constructor
33     *
34     * Instantiate the collection object
35     *
36     * @param mixed $data
37     */
38    public function __construct($data = [])
39    {
40        $this->data = $this->getDataAsArray($data);
41    }
42
43    /**
44     * Method to get the count of data in the collection
45     *
46     * @return int
47     */
48    public function count(): int
49    {
50        return count($this->data);
51    }
52
53    /**
54     * Get the first item of the collection
55     *
56     * @return mixed
57     */
58    public function first()
59    {
60        return reset($this->data);
61    }
62
63    /**
64     * Get the next item of the collection
65     *
66     * @return mixed
67     */
68    public function next()
69    {
70        return next($this->data);
71    }
72
73    /**
74     * Get the current item of the collection
75     *
76     * @return mixed
77     */
78    public function current()
79    {
80        return current($this->data);
81    }
82
83    /**
84     * Get the last item of the collection
85     *
86     * @return mixed
87     */
88    public function last()
89    {
90        return end($this->data);
91    }
92
93    /**
94     * Get the key of the current item of the collection
95     *
96     * @return mixed
97     */
98    public function key()
99    {
100        return key($this->data);
101    }
102
103    /**
104     * Determine if an item exists in the collection
105     *
106     * @param  mixed   $key
107     * @param  boolean $strict
108     * @return boolean
109     */
110    public function contains($key, $strict = false)
111    {
112        return in_array($key, $this->data, $strict);
113    }
114
115    /**
116     * Execute a callback over each item
117     *
118     * @param  callable $callback
119     * @return Collection
120     */
121    public function each(callable $callback)
122    {
123        foreach ($this->data as $key => $item) {
124            if ($callback($item, $key) === false) {
125                break;
126            }
127        }
128
129        return $this;
130    }
131
132    /**
133     * Create a new collection from every n-th element
134     *
135     * @param  int $step
136     * @param  int $offset
137     * @return Collection
138     */
139    public function every($step, $offset = 0)
140    {
141        $new      = [];
142        $position = 0;
143
144        foreach ($this->data as $item) {
145            if (($position % $step) === $offset) {
146                $new[] = $item;
147            }
148            $position++;
149        }
150
151        return new static($new);
152    }
153
154    /**
155     * Apply filter to the collection
156     *
157     * @param  callable $callback
158     * @param  int      $flag
159     * @return Collection
160     */
161    public function filter(callable $callback = null, $flag = 0)
162    {
163        return new static(array_filter($this->data, $callback, $flag));
164    }
165
166    /**
167     * Apply map to the collection
168     *
169     * @param  callable $callback
170     * @param  int       $flag
171     * @return Collection
172     */
173    public function map(callable $callback, $flag = 0)
174    {
175        return new static(array_map($callback, $this->data));
176    }
177
178    /**
179     * Flip the data in the collection
180     *
181     * @return Collection
182     */
183    public function flip()
184    {
185        foreach ($this->data as $i => $item) {
186            $this->data[$i] = array_flip($item);
187        }
188        return new static($this->data);
189    }
190
191    /**
192     * Determine if the key exists
193     *
194     * @param  mixed $key
195     * @return boolean
196     */
197    public function has($key)
198    {
199        return $this->offsetExists($key);
200    }
201
202    /**
203     * Determine if the collection is empty or not
204     *
205     * @return boolean
206     */
207    public function isEmpty()
208    {
209        return empty($this->data);
210    }
211
212    /**
213     * Get the keys of the collection data
214     *
215     * @return Collection
216     */
217    public function keys()
218    {
219        return new static(array_keys($this->data));
220    }
221
222    /**
223     * Get the values of the collection data
224     *
225     * @return Collection
226     */
227    public function values()
228    {
229        return new static(array_values($this->data));
230    }
231
232    /**
233     * Merge the collection with the passed data
234     *
235     * @param  mixed   $data
236     * @param  boolean $recursive
237     * @return Collection
238     */
239    public function merge($data, $recursive = false)
240    {
241        return ($recursive) ?
242            new static(array_merge_recursive($this->data, $this->getDataAsArray($data))) :
243            new static(array_merge($this->data, $this->getDataAsArray($data)));
244    }
245
246    /**
247     * Slice the collection for a page
248     *
249     * @param  int  $page
250     * @param  int  $perPage
251     * @return Collection
252     */
253    public function forPage($page, $perPage)
254    {
255        return $this->slice(($page - 1) * $perPage, $perPage);
256    }
257
258    /**
259     * Get and remove the last item from the collection
260     *
261     * @return mixed
262     */
263    public function pop()
264    {
265        return array_pop($this->data);
266    }
267
268    /**
269     * Push an item onto the end of the collection.
270     *
271     * @param  mixed $value
272     * @return Collection
273     */
274    public function push($value)
275    {
276        $this->offsetSet(null, $value);
277        return $this;
278    }
279
280    /**
281     * Get and remove the first item from the collection
282     *
283     * @return mixed
284     */
285    public function shift()
286    {
287        return array_shift($this->data);
288    }
289
290    /**
291     * Slice the collection
292     *
293     * @param  int $offset
294     * @param  int $length
295     * @return Collection
296     */
297    public function slice($offset, $length = null)
298    {
299        return new static(array_slice($this->data, $offset, $length, true));
300    }
301
302    /**
303     * Splice a portion of the collection
304     *
305     * @param  int      $offset
306     * @param  int|null $length
307     * @param  mixed    $replacement
308     * @return Collection
309     */
310    public function splice($offset, $length = null, $replacement = [])
311    {
312        return ((null === $length) && (count($replacement) == 0)) ?
313            new static(array_splice($this->data, $offset)) :
314            new static(array_splice($this->data, $offset, $length, $replacement));
315    }
316
317    /**
318     * Sort data
319     *
320     * @param  callable|null $callback
321     * @param  int           $flags
322     * @return Collection
323     */
324    public function sort(callable $callback = null, $flags = SORT_REGULAR)
325    {
326        $data = $this->data;
327
328        if (null !== $callback) {
329            uasort($data, $callback);
330        } else {
331            asort($data, $flags);
332        }
333
334        return new static($data);
335    }
336
337    /**
338     * Sort the collection ascending
339     *
340     * @param  int $flags
341     * @return Collection
342     */
343    public function sortByAsc($flags = SORT_REGULAR)
344    {
345        $results = $this->data;
346        asort($results, $flags);
347        return new static($results);
348    }
349
350    /**
351     * Sort the collection descending
352     *
353     * @param  int $flags
354     * @return Collection
355     */
356    public function sortByDesc($flags = SORT_REGULAR)
357    {
358        $results = $this->data;
359        arsort($results, $flags);
360        return new static($results);
361    }
362
363    /**
364     * Method to get collection object as an array
365     *
366     * @return array
367     */
368    public function toArray(): array
369    {
370        return $this->data;
371    }
372
373    /**
374     * Method to iterate over the collection
375     *
376     * @return \ArrayIterator
377     */
378    public function getIterator(): \ArrayIterator
379    {
380        return new \ArrayIterator($this->data);
381    }
382
383    /**
384     * Method to get data as an array
385     *
386     * @param  mixed $data
387     * @return array
388     */
389    protected function getDataAsArray($data)
390    {
391        if ($data instanceof self) {
392            $data = $data->toArray();
393        } else if ($data instanceof \ArrayObject) {
394            $data = (array)$data;
395        } else if (is_object($data) && method_exists($data, 'toArray')) {
396            $data = $data->toArray();
397        } else if ($data instanceof \Traversable) {
398            $data = iterator_to_array($data);
399        }
400
401        return $data;
402    }
403
404    /**
405     * Magic method to set the property to the value of $this->data[$name]
406     *
407     * @param  string $name
408     * @param  mixed $value
409     * @return void
410     */
411    public function __set($name, $value)
412    {
413        if (null !== $name) {
414            $this->data[$name] = $value;
415        } else {
416            $this->data[] = $value;
417        }
418    }
419
420    /**
421     * Magic method to return the value of $this->data[$name]
422     *
423     * @param  string $name
424     * @return mixed
425     */
426    public function __get($name)
427    {
428        return (isset($this->data[$name])) ? $this->data[$name] : null;
429    }
430
431    /**
432     * Magic method to return the isset value of $this->data[$name]
433     *
434     * @param  string $name
435     * @return boolean
436     */
437    public function __isset($name)
438    {
439        return array_key_exists($name, $this->data);
440    }
441
442    /**
443     * Magic method to unset $this->data[$name]
444     *
445     * @param  string $name
446     * @return void
447     */
448    public function __unset($name)
449    {
450        if (isset($this->data[$name])) {
451            unset($this->data[$name]);
452        }
453    }
454
455    /**
456     * ArrayAccess offsetExists
457     *
458     * @param  mixed $offset
459     * @return boolean
460     */
461    public function offsetExists($offset): bool
462    {
463        return $this->__isset($offset);
464    }
465
466    /**
467     * ArrayAccess offsetGet
468     *
469     * @param  mixed $offset
470     * @return mixed
471     */
472    #[ReturnTypeWillChange]
473    public function offsetGet($offset)
474    {
475        return $this->__get($offset);
476    }
477
478    /**
479     * ArrayAccess offsetSet
480     *
481     * @param  mixed $offset
482     * @param  mixed $value
483     * @return void
484     */
485    public function offsetSet($offset, $value): void
486    {
487        $this->__set($offset, $value);
488    }
489
490    /**
491     * ArrayAccess offsetUnset
492     *
493     * @param  mixed $offset
494     * @return void
495     */
496    public function offsetUnset($offset): void
497    {
498        $this->__unset($offset);
499    }
500
501}