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