1 | <?php |
||||||
2 | |||||||
3 | namespace MuCTS\Collections\Traits; |
||||||
4 | |||||||
5 | use CachingIterator; |
||||||
6 | use Closure; |
||||||
7 | use Exception; |
||||||
8 | use MuCTS\Contracts\Collections\Enumerable; |
||||||
9 | use MuCTS\Contracts\Support\Arrayable; |
||||||
10 | use MuCTS\Contracts\Support\Jsonable; |
||||||
11 | use MuCTS\Collections\Arr; |
||||||
12 | use MuCTS\Collections\Collection; |
||||||
13 | use MuCTS\Collections\HigherOrderCollectionProxy; |
||||||
14 | use MuCTS\Collections\HigherOrderWhenProxy; |
||||||
15 | use JsonSerializable; |
||||||
16 | use Symfony\Component\VarDumper\VarDumper; |
||||||
17 | use Traversable; |
||||||
18 | |||||||
19 | /** |
||||||
20 | * @property-read HigherOrderCollectionProxy $average |
||||||
21 | * @property-read HigherOrderCollectionProxy $avg |
||||||
22 | * @property-read HigherOrderCollectionProxy $contains |
||||||
23 | * @property-read HigherOrderCollectionProxy $each |
||||||
24 | * @property-read HigherOrderCollectionProxy $every |
||||||
25 | * @property-read HigherOrderCollectionProxy $filter |
||||||
26 | * @property-read HigherOrderCollectionProxy $first |
||||||
27 | * @property-read HigherOrderCollectionProxy $flatMap |
||||||
28 | * @property-read HigherOrderCollectionProxy $groupBy |
||||||
29 | * @property-read HigherOrderCollectionProxy $keyBy |
||||||
30 | * @property-read HigherOrderCollectionProxy $map |
||||||
31 | * @property-read HigherOrderCollectionProxy $max |
||||||
32 | * @property-read HigherOrderCollectionProxy $min |
||||||
33 | * @property-read HigherOrderCollectionProxy $partition |
||||||
34 | * @property-read HigherOrderCollectionProxy $reject |
||||||
35 | * @property-read HigherOrderCollectionProxy $some |
||||||
36 | * @property-read HigherOrderCollectionProxy $sortBy |
||||||
37 | * @property-read HigherOrderCollectionProxy $sortByDesc |
||||||
38 | * @property-read HigherOrderCollectionProxy $sum |
||||||
39 | * @property-read HigherOrderCollectionProxy $unique |
||||||
40 | * @property-read HigherOrderCollectionProxy $until |
||||||
41 | */ |
||||||
42 | trait EnumeratesValues |
||||||
43 | { |
||||||
44 | /** |
||||||
45 | * The methods that can be proxied. |
||||||
46 | * |
||||||
47 | * @var array |
||||||
48 | */ |
||||||
49 | protected static array $proxies = [ |
||||||
50 | 'average', |
||||||
51 | 'avg', |
||||||
52 | 'contains', |
||||||
53 | 'each', |
||||||
54 | 'every', |
||||||
55 | 'filter', |
||||||
56 | 'first', |
||||||
57 | 'flatMap', |
||||||
58 | 'groupBy', |
||||||
59 | 'keyBy', |
||||||
60 | 'map', |
||||||
61 | 'max', |
||||||
62 | 'min', |
||||||
63 | 'partition', |
||||||
64 | 'reject', |
||||||
65 | 'skipUntil', |
||||||
66 | 'skipWhile', |
||||||
67 | 'some', |
||||||
68 | 'sortBy', |
||||||
69 | 'sortByDesc', |
||||||
70 | 'sum', |
||||||
71 | 'takeUntil', |
||||||
72 | 'takeWhile', |
||||||
73 | 'unique', |
||||||
74 | 'until', |
||||||
75 | ]; |
||||||
76 | |||||||
77 | /** |
||||||
78 | * Create a new collection instance if the value isn't one already. |
||||||
79 | * |
||||||
80 | * @param mixed $items |
||||||
81 | * @return static |
||||||
82 | */ |
||||||
83 | public static function make($items = []) |
||||||
84 | { |
||||||
85 | return new static($items); |
||||||
0 ignored issues
–
show
|
|||||||
86 | } |
||||||
87 | |||||||
88 | /** |
||||||
89 | * Wrap the given value in a collection if applicable. |
||||||
90 | * |
||||||
91 | * @param mixed $value |
||||||
92 | * @return static |
||||||
93 | */ |
||||||
94 | public static function wrap($value) |
||||||
95 | { |
||||||
96 | return $value instanceof Enumerable |
||||||
97 | ? new static($value) |
||||||
0 ignored issues
–
show
The call to
MuCTS\Collections\Traits...esValues::__construct() has too many arguments starting with $value .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
98 | : new static(Arr::wrap($value)); |
||||||
99 | } |
||||||
100 | |||||||
101 | /** |
||||||
102 | * Get the underlying items from the given collection if applicable. |
||||||
103 | * |
||||||
104 | * @param array|static $value |
||||||
105 | * @return array |
||||||
106 | */ |
||||||
107 | public static function unwrap($value) |
||||||
108 | { |
||||||
109 | return $value instanceof Enumerable ? $value->all() : $value; |
||||||
0 ignored issues
–
show
|
|||||||
110 | } |
||||||
111 | |||||||
112 | /** |
||||||
113 | * Alias for the "avg" method. |
||||||
114 | * |
||||||
115 | * @param callable|string|null $callback |
||||||
116 | * @return mixed |
||||||
117 | */ |
||||||
118 | public function average($callback = null) |
||||||
119 | { |
||||||
120 | return $this->avg($callback); |
||||||
0 ignored issues
–
show
It seems like
avg() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
121 | } |
||||||
122 | |||||||
123 | /** |
||||||
124 | * Alias for the "contains" method. |
||||||
125 | * |
||||||
126 | * @param mixed $key |
||||||
127 | * @param mixed $operator |
||||||
128 | * @param mixed $value |
||||||
129 | * @return bool |
||||||
130 | */ |
||||||
131 | public function some($key, $operator = null, $value = null) |
||||||
132 | { |
||||||
133 | return $this->contains(...func_get_args()); |
||||||
0 ignored issues
–
show
The method
contains() does not exist on MuCTS\Collections\Traits\EnumeratesValues . Did you maybe mean containsStrict() ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
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. ![]() |
|||||||
134 | } |
||||||
135 | |||||||
136 | /** |
||||||
137 | * Determine if an item exists, using strict comparison. |
||||||
138 | * |
||||||
139 | * @param mixed $key |
||||||
140 | * @param mixed $value |
||||||
141 | * @return bool |
||||||
142 | */ |
||||||
143 | public function containsStrict($key, $value = null) |
||||||
144 | { |
||||||
145 | if (func_num_args() === 2) { |
||||||
146 | return $this->contains(function ($item) use ($key, $value) { |
||||||
147 | return data_get($item, $key) === $value; |
||||||
148 | }); |
||||||
149 | } |
||||||
150 | |||||||
151 | if ($this->useAsCallable($key)) { |
||||||
152 | return !is_null($this->first($key)); |
||||||
0 ignored issues
–
show
The method
first() does not exist on MuCTS\Collections\Traits\EnumeratesValues . Did you maybe mean firstWhere() ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
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. ![]() |
|||||||
153 | } |
||||||
154 | |||||||
155 | foreach ($this as $item) { |
||||||
156 | if ($item === $key) { |
||||||
157 | return true; |
||||||
158 | } |
||||||
159 | } |
||||||
160 | |||||||
161 | return false; |
||||||
162 | } |
||||||
163 | |||||||
164 | /** |
||||||
165 | * Dump the items and end the script. |
||||||
166 | * |
||||||
167 | * @param mixed ...$args |
||||||
168 | * @return void |
||||||
169 | */ |
||||||
170 | public function dd(...$args) |
||||||
171 | { |
||||||
172 | call_user_func_array([$this, 'dump'], $args); |
||||||
173 | } |
||||||
174 | |||||||
175 | /** |
||||||
176 | * Dump the items. |
||||||
177 | * |
||||||
178 | * @return $this |
||||||
179 | */ |
||||||
180 | public function dump() |
||||||
181 | { |
||||||
182 | (new static(func_get_args())) |
||||||
0 ignored issues
–
show
The call to
MuCTS\Collections\Traits...esValues::__construct() has too many arguments starting with func_get_args() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
183 | ->push($this) |
||||||
0 ignored issues
–
show
It seems like
push() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
184 | ->each(function ($item) { |
||||||
185 | VarDumper::dump($item); |
||||||
186 | }); |
||||||
187 | |||||||
188 | return $this; |
||||||
189 | } |
||||||
190 | |||||||
191 | /** |
||||||
192 | * Execute a callback over each item. |
||||||
193 | * |
||||||
194 | * @param callable $callback |
||||||
195 | * @return $this |
||||||
196 | */ |
||||||
197 | public function each(callable $callback) |
||||||
198 | { |
||||||
199 | foreach ($this as $key => $item) { |
||||||
200 | if ($callback($item, $key) === false) { |
||||||
201 | break; |
||||||
202 | } |
||||||
203 | } |
||||||
204 | |||||||
205 | return $this; |
||||||
206 | } |
||||||
207 | |||||||
208 | /** |
||||||
209 | * Execute a callback over each nested chunk of items. |
||||||
210 | * |
||||||
211 | * @param callable $callback |
||||||
212 | * @return static |
||||||
213 | */ |
||||||
214 | public function eachSpread(callable $callback) |
||||||
215 | { |
||||||
216 | return $this->each(function ($chunk, $key) use ($callback) { |
||||||
217 | $chunk[] = $key; |
||||||
218 | |||||||
219 | return $callback(...$chunk); |
||||||
220 | }); |
||||||
221 | } |
||||||
222 | |||||||
223 | /** |
||||||
224 | * Determine if all items pass the given truth test. |
||||||
225 | * |
||||||
226 | * @param string|callable $key |
||||||
227 | * @param mixed $operator |
||||||
228 | * @param mixed $value |
||||||
229 | * @return bool |
||||||
230 | */ |
||||||
231 | public function every($key, $operator = null, $value = null) |
||||||
232 | { |
||||||
233 | if (func_num_args() === 1) { |
||||||
234 | $callback = $this->valueRetriever($key); |
||||||
235 | |||||||
236 | foreach ($this as $k => $v) { |
||||||
237 | if (!$callback($v, $k)) { |
||||||
238 | return false; |
||||||
239 | } |
||||||
240 | } |
||||||
241 | |||||||
242 | return true; |
||||||
243 | } |
||||||
244 | |||||||
245 | return $this->every($this->operatorForWhere(...func_get_args())); |
||||||
0 ignored issues
–
show
func_get_args() is expanded, but the parameter $key of MuCTS\Collections\Traits...ues::operatorForWhere() does not expect variable arguments.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
246 | } |
||||||
247 | |||||||
248 | /** |
||||||
249 | * Get the first item by the given key value pair. |
||||||
250 | * |
||||||
251 | * @param string $key |
||||||
252 | * @param mixed $operator |
||||||
253 | * @param mixed $value |
||||||
254 | * @return mixed |
||||||
255 | */ |
||||||
256 | public function firstWhere($key, $operator = null, $value = null) |
||||||
257 | { |
||||||
258 | return $this->first($this->operatorForWhere(...func_get_args())); |
||||||
0 ignored issues
–
show
func_get_args() is expanded, but the parameter $key of MuCTS\Collections\Traits...ues::operatorForWhere() does not expect variable arguments.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
259 | } |
||||||
260 | |||||||
261 | /** |
||||||
262 | * Determine if the collection is not empty. |
||||||
263 | * |
||||||
264 | * @return bool |
||||||
265 | */ |
||||||
266 | public function isNotEmpty() |
||||||
267 | { |
||||||
268 | return !$this->isEmpty(); |
||||||
0 ignored issues
–
show
It seems like
isEmpty() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
269 | } |
||||||
270 | |||||||
271 | /** |
||||||
272 | * Run a map over each nested chunk of items. |
||||||
273 | * |
||||||
274 | * @param callable $callback |
||||||
275 | * @return static |
||||||
276 | */ |
||||||
277 | public function mapSpread(callable $callback) |
||||||
278 | { |
||||||
279 | return $this->map(function ($chunk, $key) use ($callback) { |
||||||
0 ignored issues
–
show
It seems like
map() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
280 | $chunk[] = $key; |
||||||
281 | |||||||
282 | return $callback(...$chunk); |
||||||
283 | }); |
||||||
284 | } |
||||||
285 | |||||||
286 | /** |
||||||
287 | * Run a grouping map over the items. |
||||||
288 | * |
||||||
289 | * The callback should return an associative array with a single key/value pair. |
||||||
290 | * |
||||||
291 | * @param callable $callback |
||||||
292 | * @return static |
||||||
293 | */ |
||||||
294 | public function mapToGroups(callable $callback) |
||||||
295 | { |
||||||
296 | $groups = $this->mapToDictionary($callback); |
||||||
0 ignored issues
–
show
It seems like
mapToDictionary() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
297 | |||||||
298 | return $groups->map([$this, 'make']); |
||||||
299 | } |
||||||
300 | |||||||
301 | /** |
||||||
302 | * Map a collection and flatten the result by a single level. |
||||||
303 | * |
||||||
304 | * @param callable $callback |
||||||
305 | * @return static |
||||||
306 | */ |
||||||
307 | public function flatMap(callable $callback) |
||||||
308 | { |
||||||
309 | return $this->map($callback)->collapse(); |
||||||
310 | } |
||||||
311 | |||||||
312 | /** |
||||||
313 | * Map the values into a new class. |
||||||
314 | * |
||||||
315 | * @param string $class |
||||||
316 | * @return static |
||||||
317 | */ |
||||||
318 | public function mapInto($class) |
||||||
319 | { |
||||||
320 | return $this->map(function ($value, $key) use ($class) { |
||||||
321 | return new $class($value, $key); |
||||||
322 | }); |
||||||
323 | } |
||||||
324 | |||||||
325 | /** |
||||||
326 | * Get the min value of a given key. |
||||||
327 | * |
||||||
328 | * @param callable|string|null $callback |
||||||
329 | * @return mixed |
||||||
330 | */ |
||||||
331 | public function min($callback = null) |
||||||
332 | { |
||||||
333 | $callback = $this->valueRetriever($callback); |
||||||
334 | |||||||
335 | return $this->map(function ($value) use ($callback) { |
||||||
336 | return $callback($value); |
||||||
337 | })->filter(function ($value) { |
||||||
338 | return !is_null($value); |
||||||
339 | })->reduce(function ($result, $value) { |
||||||
340 | return is_null($result) || $value < $result ? $value : $result; |
||||||
341 | }); |
||||||
342 | } |
||||||
343 | |||||||
344 | /** |
||||||
345 | * Get the max value of a given key. |
||||||
346 | * |
||||||
347 | * @param callable|string|null $callback |
||||||
348 | * @return mixed |
||||||
349 | */ |
||||||
350 | public function max($callback = null) |
||||||
351 | { |
||||||
352 | $callback = $this->valueRetriever($callback); |
||||||
353 | |||||||
354 | return $this->filter(function ($value) { |
||||||
0 ignored issues
–
show
It seems like
filter() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
355 | return !is_null($value); |
||||||
356 | })->reduce(function ($result, $item) use ($callback) { |
||||||
357 | $value = $callback($item); |
||||||
358 | |||||||
359 | return is_null($result) || $value > $result ? $value : $result; |
||||||
360 | }); |
||||||
361 | } |
||||||
362 | |||||||
363 | /** |
||||||
364 | * "Paginate" the collection by slicing it into a smaller collection. |
||||||
365 | * |
||||||
366 | * @param int $page |
||||||
367 | * @param int $perPage |
||||||
368 | * @return static |
||||||
369 | */ |
||||||
370 | public function forPage($page, $perPage) |
||||||
371 | { |
||||||
372 | $offset = max(0, ($page - 1) * $perPage); |
||||||
373 | |||||||
374 | return $this->slice($offset, $perPage); |
||||||
0 ignored issues
–
show
It seems like
slice() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
375 | } |
||||||
376 | |||||||
377 | /** |
||||||
378 | * Partition the collection into two arrays using the given callback or key. |
||||||
379 | * |
||||||
380 | * @param callable|string $key |
||||||
381 | * @param mixed $operator |
||||||
382 | * @param mixed $value |
||||||
383 | * @return static |
||||||
384 | */ |
||||||
385 | public function partition($key, $operator = null, $value = null) |
||||||
386 | { |
||||||
387 | $passed = []; |
||||||
388 | $failed = []; |
||||||
389 | |||||||
390 | $callback = func_num_args() === 1 |
||||||
391 | ? $this->valueRetriever($key) |
||||||
392 | : $this->operatorForWhere(...func_get_args()); |
||||||
0 ignored issues
–
show
func_get_args() is expanded, but the parameter $key of MuCTS\Collections\Traits...ues::operatorForWhere() does not expect variable arguments.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
393 | |||||||
394 | foreach ($this as $key => $item) { |
||||||
0 ignored issues
–
show
|
|||||||
395 | if ($callback($item, $key)) { |
||||||
396 | $passed[$key] = $item; |
||||||
397 | } else { |
||||||
398 | $failed[$key] = $item; |
||||||
399 | } |
||||||
400 | } |
||||||
401 | |||||||
402 | return new static([new static($passed), new static($failed)]); |
||||||
0 ignored issues
–
show
The call to
MuCTS\Collections\Traits...esValues::__construct() has too many arguments starting with $passed .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
403 | } |
||||||
404 | |||||||
405 | /** |
||||||
406 | * Get the sum of the given values. |
||||||
407 | * |
||||||
408 | * @param callable|string|null $callback |
||||||
409 | * @return mixed |
||||||
410 | */ |
||||||
411 | public function sum($callback = null) |
||||||
412 | { |
||||||
413 | $callback = is_null($callback) |
||||||
414 | ? $this->identity() |
||||||
415 | : $this->valueRetriever($callback); |
||||||
416 | |||||||
417 | return $this->reduce(function ($result, $item) use ($callback) { |
||||||
0 ignored issues
–
show
It seems like
reduce() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
418 | return $result + $callback($item); |
||||||
419 | }, 0); |
||||||
420 | } |
||||||
421 | |||||||
422 | /** |
||||||
423 | * Apply the callback if the value is truthy. |
||||||
424 | * |
||||||
425 | * @param bool|mixed $value |
||||||
426 | * @param callable|null $callback |
||||||
427 | * @param callable|null $default |
||||||
428 | * @return static|mixed |
||||||
429 | */ |
||||||
430 | public function when($value, callable $callback = null, callable $default = null) |
||||||
431 | { |
||||||
432 | if (!$callback) { |
||||||
433 | return new HigherOrderWhenProxy($this, $value); |
||||||
0 ignored issues
–
show
$this of type MuCTS\Collections\Traits\EnumeratesValues is incompatible with the type MuCTS\Contracts\Collections\Enumerable expected by parameter $collection of MuCTS\Collections\Higher...henProxy::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
434 | } |
||||||
435 | |||||||
436 | if ($value) { |
||||||
437 | return $callback($this, $value); |
||||||
438 | } elseif ($default) { |
||||||
439 | return $default($this, $value); |
||||||
440 | } |
||||||
441 | |||||||
442 | return $this; |
||||||
443 | } |
||||||
444 | |||||||
445 | /** |
||||||
446 | * Apply the callback if the collection is empty. |
||||||
447 | * |
||||||
448 | * @param callable $callback |
||||||
449 | * @param callable|null $default |
||||||
450 | * @return static|mixed |
||||||
451 | */ |
||||||
452 | public function whenEmpty(callable $callback, callable $default = null) |
||||||
453 | { |
||||||
454 | return $this->when($this->isEmpty(), $callback, $default); |
||||||
455 | } |
||||||
456 | |||||||
457 | /** |
||||||
458 | * Apply the callback if the collection is not empty. |
||||||
459 | * |
||||||
460 | * @param callable $callback |
||||||
461 | * @param callable|null $default |
||||||
462 | * @return static|mixed |
||||||
463 | */ |
||||||
464 | public function whenNotEmpty(callable $callback, callable $default = null) |
||||||
465 | { |
||||||
466 | return $this->when($this->isNotEmpty(), $callback, $default); |
||||||
467 | } |
||||||
468 | |||||||
469 | /** |
||||||
470 | * Apply the callback if the value is falsy. |
||||||
471 | * |
||||||
472 | * @param bool $value |
||||||
473 | * @param callable $callback |
||||||
474 | * @param callable|null $default |
||||||
475 | * @return static|mixed |
||||||
476 | */ |
||||||
477 | public function unless($value, callable $callback, callable $default = null) |
||||||
478 | { |
||||||
479 | return $this->when(!$value, $callback, $default); |
||||||
480 | } |
||||||
481 | |||||||
482 | /** |
||||||
483 | * Apply the callback unless the collection is empty. |
||||||
484 | * |
||||||
485 | * @param callable $callback |
||||||
486 | * @param callable|null $default |
||||||
487 | * @return static|mixed |
||||||
488 | */ |
||||||
489 | public function unlessEmpty(callable $callback, callable $default = null) |
||||||
490 | { |
||||||
491 | return $this->whenNotEmpty($callback, $default); |
||||||
492 | } |
||||||
493 | |||||||
494 | /** |
||||||
495 | * Apply the callback unless the collection is not empty. |
||||||
496 | * |
||||||
497 | * @param callable $callback |
||||||
498 | * @param callable|null $default |
||||||
499 | * @return static|mixed |
||||||
500 | */ |
||||||
501 | public function unlessNotEmpty(callable $callback, callable $default = null) |
||||||
502 | { |
||||||
503 | return $this->whenEmpty($callback, $default); |
||||||
504 | } |
||||||
505 | |||||||
506 | /** |
||||||
507 | * Filter items by the given key value pair. |
||||||
508 | * |
||||||
509 | * @param string $key |
||||||
510 | * @param mixed $operator |
||||||
511 | * @param mixed $value |
||||||
512 | * @return static |
||||||
513 | */ |
||||||
514 | public function where($key, $operator = null, $value = null) |
||||||
515 | { |
||||||
516 | return $this->filter($this->operatorForWhere(...func_get_args())); |
||||||
0 ignored issues
–
show
func_get_args() is expanded, but the parameter $key of MuCTS\Collections\Traits...ues::operatorForWhere() does not expect variable arguments.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
517 | } |
||||||
518 | |||||||
519 | /** |
||||||
520 | * Filter items where the value for the given key is null. |
||||||
521 | * |
||||||
522 | * @param string|null $key |
||||||
523 | * @return static |
||||||
524 | */ |
||||||
525 | public function whereNull($key = null) |
||||||
526 | { |
||||||
527 | return $this->whereStrict($key, null); |
||||||
528 | } |
||||||
529 | |||||||
530 | /** |
||||||
531 | * Filter items where the value for the given key is not null. |
||||||
532 | * |
||||||
533 | * @param string|null $key |
||||||
534 | * @return static |
||||||
535 | */ |
||||||
536 | public function whereNotNull($key = null) |
||||||
537 | { |
||||||
538 | return $this->where($key, '!==', null); |
||||||
539 | } |
||||||
540 | |||||||
541 | /** |
||||||
542 | * Filter items by the given key value pair using strict comparison. |
||||||
543 | * |
||||||
544 | * @param string $key |
||||||
545 | * @param mixed $value |
||||||
546 | * @return static |
||||||
547 | */ |
||||||
548 | public function whereStrict($key, $value) |
||||||
549 | { |
||||||
550 | return $this->where($key, '===', $value); |
||||||
551 | } |
||||||
552 | |||||||
553 | /** |
||||||
554 | * Filter items by the given key value pair. |
||||||
555 | * |
||||||
556 | * @param string $key |
||||||
557 | * @param mixed $values |
||||||
558 | * @param bool $strict |
||||||
559 | * @return static |
||||||
560 | */ |
||||||
561 | public function whereIn($key, $values, $strict = false) |
||||||
562 | { |
||||||
563 | $values = $this->getArrayableItems($values); |
||||||
564 | |||||||
565 | return $this->filter(function ($item) use ($key, $values, $strict) { |
||||||
566 | return in_array(data_get($item, $key), $values, $strict); |
||||||
567 | }); |
||||||
568 | } |
||||||
569 | |||||||
570 | /** |
||||||
571 | * Filter items by the given key value pair using strict comparison. |
||||||
572 | * |
||||||
573 | * @param string $key |
||||||
574 | * @param mixed $values |
||||||
575 | * @return static |
||||||
576 | */ |
||||||
577 | public function whereInStrict($key, $values) |
||||||
578 | { |
||||||
579 | return $this->whereIn($key, $values, true); |
||||||
580 | } |
||||||
581 | |||||||
582 | /** |
||||||
583 | * Filter items such that the value of the given key is between the given values. |
||||||
584 | * |
||||||
585 | * @param string $key |
||||||
586 | * @param array $values |
||||||
587 | * @return static |
||||||
588 | */ |
||||||
589 | public function whereBetween($key, $values) |
||||||
590 | { |
||||||
591 | return $this->where($key, '>=', reset($values))->where($key, '<=', end($values)); |
||||||
592 | } |
||||||
593 | |||||||
594 | /** |
||||||
595 | * Filter items such that the value of the given key is not between the given values. |
||||||
596 | * |
||||||
597 | * @param string $key |
||||||
598 | * @param array $values |
||||||
599 | * @return static |
||||||
600 | */ |
||||||
601 | public function whereNotBetween($key, $values) |
||||||
602 | { |
||||||
603 | return $this->filter(function ($item) use ($key, $values) { |
||||||
604 | return data_get($item, $key) < reset($values) || data_get($item, $key) > end($values); |
||||||
605 | }); |
||||||
606 | } |
||||||
607 | |||||||
608 | /** |
||||||
609 | * Filter items by the given key value pair. |
||||||
610 | * |
||||||
611 | * @param string $key |
||||||
612 | * @param mixed $values |
||||||
613 | * @param bool $strict |
||||||
614 | * @return static |
||||||
615 | */ |
||||||
616 | public function whereNotIn($key, $values, $strict = false) |
||||||
617 | { |
||||||
618 | $values = $this->getArrayableItems($values); |
||||||
619 | |||||||
620 | return $this->reject(function ($item) use ($key, $values, $strict) { |
||||||
621 | return in_array(data_get($item, $key), $values, $strict); |
||||||
622 | }); |
||||||
623 | } |
||||||
624 | |||||||
625 | /** |
||||||
626 | * Filter items by the given key value pair using strict comparison. |
||||||
627 | * |
||||||
628 | * @param string $key |
||||||
629 | * @param mixed $values |
||||||
630 | * @return static |
||||||
631 | */ |
||||||
632 | public function whereNotInStrict($key, $values) |
||||||
633 | { |
||||||
634 | return $this->whereNotIn($key, $values, true); |
||||||
635 | } |
||||||
636 | |||||||
637 | /** |
||||||
638 | * Filter the items, removing any items that don't match the given type. |
||||||
639 | * |
||||||
640 | * @param string $type |
||||||
641 | * @return static |
||||||
642 | */ |
||||||
643 | public function whereInstanceOf($type) |
||||||
644 | { |
||||||
645 | return $this->filter(function ($value) use ($type) { |
||||||
646 | return $value instanceof $type; |
||||||
647 | }); |
||||||
648 | } |
||||||
649 | |||||||
650 | /** |
||||||
651 | * Pass the collection to the given callback and return the result. |
||||||
652 | * |
||||||
653 | * @param callable $callback |
||||||
654 | * @return mixed |
||||||
655 | */ |
||||||
656 | public function pipe(callable $callback) |
||||||
657 | { |
||||||
658 | return $callback($this); |
||||||
659 | } |
||||||
660 | |||||||
661 | /** |
||||||
662 | * Pass the collection to the given callback and then return it. |
||||||
663 | * |
||||||
664 | * @param callable $callback |
||||||
665 | * @return $this |
||||||
666 | */ |
||||||
667 | public function tap(callable $callback) |
||||||
668 | { |
||||||
669 | $callback(clone $this); |
||||||
670 | |||||||
671 | return $this; |
||||||
672 | } |
||||||
673 | |||||||
674 | /** |
||||||
675 | * Create a collection of all elements that do not pass a given truth test. |
||||||
676 | * |
||||||
677 | * @param callable|mixed $callback |
||||||
678 | * @return static |
||||||
679 | */ |
||||||
680 | public function reject($callback = true) |
||||||
681 | { |
||||||
682 | $useAsCallable = $this->useAsCallable($callback); |
||||||
683 | |||||||
684 | return $this->filter(function ($value, $key) use ($callback, $useAsCallable) { |
||||||
685 | return $useAsCallable |
||||||
686 | ? !$callback($value, $key) |
||||||
687 | : $value != $callback; |
||||||
688 | }); |
||||||
689 | } |
||||||
690 | |||||||
691 | /** |
||||||
692 | * Return only unique items from the collection array. |
||||||
693 | * |
||||||
694 | * @param string|callable|null $key |
||||||
695 | * @param bool $strict |
||||||
696 | * @return static |
||||||
697 | */ |
||||||
698 | public function unique($key = null, $strict = false) |
||||||
699 | { |
||||||
700 | $callback = $this->valueRetriever($key); |
||||||
701 | |||||||
702 | $exists = []; |
||||||
703 | |||||||
704 | return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) { |
||||||
705 | if (in_array($id = $callback($item, $key), $exists, $strict)) { |
||||||
706 | return true; |
||||||
707 | } |
||||||
708 | |||||||
709 | $exists[] = $id; |
||||||
710 | }); |
||||||
711 | } |
||||||
712 | |||||||
713 | /** |
||||||
714 | * Return only unique items from the collection array using strict comparison. |
||||||
715 | * |
||||||
716 | * @param string|callable|null $key |
||||||
717 | * @return static |
||||||
718 | */ |
||||||
719 | public function uniqueStrict($key = null) |
||||||
720 | { |
||||||
721 | return $this->unique($key, true); |
||||||
722 | } |
||||||
723 | |||||||
724 | /** |
||||||
725 | * Take items in the collection until the given condition is met. |
||||||
726 | * |
||||||
727 | * This is an alias to the "takeUntil" method. |
||||||
728 | * |
||||||
729 | * @param mixed $value |
||||||
730 | * @return static |
||||||
731 | * |
||||||
732 | * @deprecated Use the "takeUntil" method directly. |
||||||
733 | */ |
||||||
734 | public function until($value) |
||||||
735 | { |
||||||
736 | return $this->takeUntil($value); |
||||||
0 ignored issues
–
show
It seems like
takeUntil() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
737 | } |
||||||
738 | |||||||
739 | /** |
||||||
740 | * Collect the values into a collection. |
||||||
741 | * |
||||||
742 | * @return \MuCTS\Collections\Collection |
||||||
743 | */ |
||||||
744 | public function collect() |
||||||
745 | { |
||||||
746 | return new Collection($this->all()); |
||||||
0 ignored issues
–
show
It seems like
all() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
747 | } |
||||||
748 | |||||||
749 | /** |
||||||
750 | * Get the collection of items as a plain array. |
||||||
751 | * |
||||||
752 | * @return array |
||||||
753 | */ |
||||||
754 | public function toArray() |
||||||
755 | { |
||||||
756 | return $this->map(function ($value) { |
||||||
757 | return $value instanceof Arrayable ? $value->toArray() : $value; |
||||||
758 | })->all(); |
||||||
759 | } |
||||||
760 | |||||||
761 | /** |
||||||
762 | * Convert the object into something JSON serializable. |
||||||
763 | * |
||||||
764 | * @return array |
||||||
765 | */ |
||||||
766 | public function jsonSerialize() |
||||||
767 | { |
||||||
768 | return array_map(function ($value) { |
||||||
769 | if ($value instanceof JsonSerializable) { |
||||||
770 | return $value->jsonSerialize(); |
||||||
771 | } elseif ($value instanceof Jsonable) { |
||||||
772 | return json_decode($value->toJson(), true); |
||||||
773 | } elseif ($value instanceof Arrayable) { |
||||||
774 | return $value->toArray(); |
||||||
775 | } |
||||||
776 | |||||||
777 | return $value; |
||||||
778 | }, $this->all()); |
||||||
779 | } |
||||||
780 | |||||||
781 | /** |
||||||
782 | * Get the collection of items as JSON. |
||||||
783 | * |
||||||
784 | * @param int $options |
||||||
785 | * @return string |
||||||
786 | */ |
||||||
787 | public function toJson($options = 0) |
||||||
788 | { |
||||||
789 | return json_encode($this->jsonSerialize(), $options); |
||||||
790 | } |
||||||
791 | |||||||
792 | /** |
||||||
793 | * Get a CachingIterator instance. |
||||||
794 | * |
||||||
795 | * @param int $flags |
||||||
796 | * @return \CachingIterator |
||||||
797 | */ |
||||||
798 | public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING) |
||||||
799 | { |
||||||
800 | return new CachingIterator($this->getIterator(), $flags); |
||||||
0 ignored issues
–
show
It seems like
getIterator() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
801 | } |
||||||
802 | |||||||
803 | /** |
||||||
804 | * Convert the collection to its string representation. |
||||||
805 | * |
||||||
806 | * @return string |
||||||
807 | */ |
||||||
808 | public function __toString() |
||||||
809 | { |
||||||
810 | return $this->toJson(); |
||||||
811 | } |
||||||
812 | |||||||
813 | /** |
||||||
814 | * Add a method to the list of proxied methods. |
||||||
815 | * |
||||||
816 | * @param string $method |
||||||
817 | * @return void |
||||||
818 | */ |
||||||
819 | public static function proxy($method) |
||||||
820 | { |
||||||
821 | static::$proxies[] = $method; |
||||||
822 | } |
||||||
823 | |||||||
824 | /** |
||||||
825 | * Dynamically access collection proxies. |
||||||
826 | * |
||||||
827 | * @param string $key |
||||||
828 | * @return mixed |
||||||
829 | * |
||||||
830 | * @throws Exception |
||||||
831 | */ |
||||||
832 | public function __get($key) |
||||||
833 | { |
||||||
834 | if (!in_array($key, static::$proxies)) { |
||||||
835 | throw new Exception("Property [{$key}] does not exist on this collection instance."); |
||||||
836 | } |
||||||
837 | |||||||
838 | return new HigherOrderCollectionProxy($this, $key); |
||||||
0 ignored issues
–
show
$this of type MuCTS\Collections\Traits\EnumeratesValues is incompatible with the type MuCTS\Contracts\Collections\Enumerable expected by parameter $collection of MuCTS\Collections\Higher...ionProxy::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
839 | } |
||||||
840 | |||||||
841 | /** |
||||||
842 | * Results array of items from Collection or Arrayable. |
||||||
843 | * |
||||||
844 | * @param mixed $items |
||||||
845 | * @return array |
||||||
846 | */ |
||||||
847 | protected function getArrayableItems($items) |
||||||
848 | { |
||||||
849 | if (is_array($items)) { |
||||||
850 | return $items; |
||||||
851 | } elseif ($items instanceof Enumerable) { |
||||||
852 | return $items->all(); |
||||||
853 | } elseif ($items instanceof Arrayable) { |
||||||
854 | return $items->toArray(); |
||||||
855 | } elseif ($items instanceof Jsonable) { |
||||||
856 | return json_decode($items->toJson(), true); |
||||||
857 | } elseif ($items instanceof JsonSerializable) { |
||||||
858 | return (array)$items->jsonSerialize(); |
||||||
859 | } elseif ($items instanceof Traversable) { |
||||||
860 | return iterator_to_array($items); |
||||||
861 | } |
||||||
862 | |||||||
863 | return (array)$items; |
||||||
864 | } |
||||||
865 | |||||||
866 | /** |
||||||
867 | * Get an operator checker callback. |
||||||
868 | * |
||||||
869 | * @param string $key |
||||||
870 | * @param string|null $operator |
||||||
871 | * @param mixed $value |
||||||
872 | * @return Closure |
||||||
873 | */ |
||||||
874 | protected function operatorForWhere($key, $operator = null, $value = null) |
||||||
875 | { |
||||||
876 | if (func_num_args() === 1) { |
||||||
877 | $value = true; |
||||||
878 | |||||||
879 | $operator = '='; |
||||||
880 | } |
||||||
881 | |||||||
882 | if (func_num_args() === 2) { |
||||||
883 | $value = $operator; |
||||||
884 | |||||||
885 | $operator = '='; |
||||||
886 | } |
||||||
887 | |||||||
888 | return function ($item) use ($key, $operator, $value) { |
||||||
889 | $retrieved = data_get($item, $key); |
||||||
890 | |||||||
891 | $strings = array_filter([$retrieved, $value], function ($value) { |
||||||
892 | return is_string($value) || (is_object($value) && method_exists($value, '__toString')); |
||||||
893 | }); |
||||||
894 | |||||||
895 | if (count($strings) < 2 && count(array_filter([$retrieved, $value], 'is_object')) == 1) { |
||||||
896 | return in_array($operator, ['!=', '<>', '!==']); |
||||||
897 | } |
||||||
898 | |||||||
899 | switch ($operator) { |
||||||
900 | default: |
||||||
901 | case '=': |
||||||
902 | case '==': |
||||||
903 | return $retrieved == $value; |
||||||
904 | case '!=': |
||||||
905 | case '<>': |
||||||
906 | return $retrieved != $value; |
||||||
907 | case '<': |
||||||
908 | return $retrieved < $value; |
||||||
909 | case '>': |
||||||
910 | return $retrieved > $value; |
||||||
911 | case '<=': |
||||||
912 | return $retrieved <= $value; |
||||||
913 | case '>=': |
||||||
914 | return $retrieved >= $value; |
||||||
915 | case '===': |
||||||
916 | return $retrieved === $value; |
||||||
917 | case '!==': |
||||||
918 | return $retrieved !== $value; |
||||||
919 | } |
||||||
920 | }; |
||||||
921 | } |
||||||
922 | |||||||
923 | /** |
||||||
924 | * Determine if the given value is callable, but not a string. |
||||||
925 | * |
||||||
926 | * @param mixed $value |
||||||
927 | * @return bool |
||||||
928 | */ |
||||||
929 | protected function useAsCallable($value) |
||||||
930 | { |
||||||
931 | return !is_string($value) && is_callable($value); |
||||||
932 | } |
||||||
933 | |||||||
934 | /** |
||||||
935 | * Get a value retrieving callback. |
||||||
936 | * |
||||||
937 | * @param callable|string|null $value |
||||||
938 | * @return callable |
||||||
939 | */ |
||||||
940 | protected function valueRetriever($value) |
||||||
941 | { |
||||||
942 | if ($this->useAsCallable($value)) { |
||||||
943 | return $value; |
||||||
944 | } |
||||||
945 | |||||||
946 | return function ($item) use ($value) { |
||||||
947 | return data_get($item, $value); |
||||||
948 | }; |
||||||
949 | } |
||||||
950 | |||||||
951 | /** |
||||||
952 | * Make a function to check an item's equality. |
||||||
953 | * |
||||||
954 | * @param mixed $value |
||||||
955 | * @return Closure |
||||||
956 | */ |
||||||
957 | protected function equality($value) |
||||||
958 | { |
||||||
959 | return function ($item) use ($value) { |
||||||
960 | return $item === $value; |
||||||
961 | }; |
||||||
962 | } |
||||||
963 | |||||||
964 | /** |
||||||
965 | * Make a function using another function, by negating its result. |
||||||
966 | * |
||||||
967 | * @param Closure $callback |
||||||
968 | * @return Closure |
||||||
969 | */ |
||||||
970 | protected function negate(Closure $callback) |
||||||
971 | { |
||||||
972 | return function (...$params) use ($callback) { |
||||||
973 | return !$callback(...$params); |
||||||
974 | }; |
||||||
975 | } |
||||||
976 | |||||||
977 | /** |
||||||
978 | * Make a function that returns what's passed to it. |
||||||
979 | * |
||||||
980 | * @return Closure |
||||||
981 | */ |
||||||
982 | protected function identity() |
||||||
983 | { |
||||||
984 | return function ($value) { |
||||||
985 | return $value; |
||||||
986 | }; |
||||||
987 | } |
||||||
988 | } |
||||||
989 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.