Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
36 / 36
100.00% covered (success)
100.00%
19 / 19
CRAP
100.00% covered (success)
100.00%
1 / 1
Collection
100.00% covered (success)
100.00%
36 / 36
100.00% covered (success)
100.00%
19 / 19
27
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
 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%
4 / 4
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
 column
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
 getDataAsArray
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Utils;
16
17/**
18 * Pop utils array collection class
19 *
20 * @category   Pop
21 * @package    Pop\Utils
22 * @author     Nick Sagona, III <nick@popphp.org>
23 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
24 * @license    https://www.popphp.org/license     New BSD License
25 * @version    3.0.0
26 */
27class Collection extends AbstractArray
28{
29
30    /**
31     * Constructor
32     *
33     * Instantiate the collection object
34     *
35     * @param mixed $data
36     */
37    public function __construct(mixed $data = [])
38    {
39        $this->data = $this->getDataAsArray($data);
40    }
41
42    /**
43     * Execute a callback over each item
44     *
45     * @param  callable $callback
46     * @return Collection
47     */
48    public function each(callable $callback): Collection
49    {
50        foreach ($this->data as $key => $item) {
51            if ($callback($item, $key) === false) {
52                break;
53            }
54        }
55
56        return $this;
57    }
58
59    /**
60     * Create a new collection from every n-th element
61     *
62     * @param  int $step
63     * @param  int $offset
64     * @return Collection
65     */
66    public function every(int $step, int $offset = 0): Collection
67    {
68        $new      = [];
69        $position = 0;
70
71        foreach ($this->data as $item) {
72            if (($position % $step) === $offset) {
73                $new[] = $item;
74            }
75            $position++;
76        }
77
78        return new static($new);
79    }
80
81    /**
82     * Apply filter to the collection
83     *
84     * @param  ?callable $callback
85     * @param  int       $flag
86     * @return Collection
87     */
88    public function filter(?callable $callback = null, int $flag = 0): Collection
89    {
90        return new static(array_filter($this->data, $callback, $flag));
91    }
92
93    /**
94     * Apply map to the collection
95     *
96     * @param  callable $callback
97     * @return Collection
98     */
99    public function map(callable $callback): Collection
100    {
101        return new static(array_map($callback, $this->data));
102    }
103
104    /**
105     * Flip the data in the collection
106     *
107     * @return Collection
108     */
109    public function flip(): Collection
110    {
111        $flipped = [];
112
113        foreach ($this->data as $i => $item) {
114            $flipped[$i] = array_flip($item);
115        }
116
117        return new static($flipped);
118    }
119
120    /**
121     * Determine if the key exists
122     *
123     * @param  mixed $key
124     * @return bool
125     */
126    public function has(mixed $key): bool
127    {
128        return $this->offsetExists($key);
129    }
130
131    /**
132     * Determine if the collection is empty or not
133     *
134     * @return bool
135     */
136    public function isEmpty(): bool
137    {
138        return empty($this->data);
139    }
140
141    /**
142     * Get the keys of the collection data
143     *
144     * @return Collection
145     */
146    public function keys(): Collection
147    {
148        return new static(array_keys($this->data));
149    }
150
151    /**
152     * Get the values of a column
153     *
154     * @return Collection
155     */
156    public function column(string $column): Collection
157    {
158        return new static(array_column($this->data, $column));
159    }
160
161    /**
162     * Get the values of the collection data
163     *
164     * @return Collection
165     */
166    public function values(): Collection
167    {
168        return new static(array_values($this->data));
169    }
170
171    /**
172     * Merge the collection with the passed data
173     *
174     * @param  mixed $data
175     * @param  bool  $recursive
176     * @return Collection
177     */
178    public function merge(mixed $data, bool $recursive = false): Collection
179    {
180        return ($recursive) ?
181            new static(array_merge_recursive($this->data, $this->getDataAsArray($data))) :
182            new static(array_merge($this->data, $this->getDataAsArray($data)));
183    }
184
185    /**
186     * Slice the collection for a page
187     *
188     * @param  int  $page
189     * @param  int  $perPage
190     * @return Collection
191     */
192    public function forPage(int $page, int $perPage): Collection
193    {
194        return $this->slice(($page - 1) * $perPage, $perPage);
195    }
196
197    /**
198     * Get and remove the last item from the collection
199     *
200     * @return mixed
201     */
202    public function pop(): mixed
203    {
204        return array_pop($this->data);
205    }
206
207    /**
208     * Push an item onto the end of the collection.
209     *
210     * @param  mixed $value
211     * @return Collection
212     */
213    public function push(mixed $value): Collection
214    {
215        $this->offsetSet(null, $value);
216        return $this;
217    }
218
219    /**
220     * Get and remove the first item from the collection
221     *
222     * @return mixed
223     */
224    public function shift(): mixed
225    {
226        return array_shift($this->data);
227    }
228
229    /**
230     * Slice the collection
231     *
232     * @param  int  $offset
233     * @param  ?int $length
234     * @return Collection
235     */
236    public function slice(int $offset, ?int $length = null): Collection
237    {
238        return new static(array_slice($this->data, $offset, $length, true));
239    }
240
241    /**
242     * Splice a portion of the collection
243     *
244     * @param  int   $offset
245     * @param  ?int  $length
246     * @param  mixed $replacement
247     * @return Collection
248     */
249    public function splice(int $offset, ?int $length = null, mixed $replacement = []): Collection
250    {
251        return (($length === null) && (count($replacement) == 0)) ?
252            new static(array_splice($this->data, $offset)) :
253            new static(array_splice($this->data, $offset, $length, $replacement));
254    }
255
256    /**
257     * Method to get data as an array
258     *
259     * @param  mixed $data
260     * @return array
261     */
262    protected function getDataAsArray(mixed $data): array
263    {
264        return Arr::toArray($data);
265    }
266
267}