vakata /
collection
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | namespace vakata\collection; |
||
| 4 | |||
| 5 | class Collection implements \Iterator, \ArrayAccess, \Serializable, \Countable |
||
| 6 | { |
||
| 7 | protected $array = null; |
||
| 8 | protected $stack = []; |
||
| 9 | protected $iterator = null; |
||
| 10 | protected $key = null; |
||
| 11 | protected $val = null; |
||
| 12 | |||
| 13 | 4 | protected static function rangeGenerator($low, $high, $step = 1) |
|
| 14 | { |
||
| 15 | 4 | $k = -1; |
|
| 16 | 4 | for ($i = $low; $i <= $high; $i += $step) { |
|
| 17 | 4 | yield ++$k => $i; |
|
| 18 | } |
||
| 19 | 4 | } |
|
| 20 | /** |
||
| 21 | * Create a collection based on a range generator |
||
| 22 | * @param int|float $low start value |
||
| 23 | * @param int|float $high end value |
||
| 24 | * @param int|float $step increment |
||
| 25 | * @return Collection |
||
| 26 | */ |
||
| 27 | 4 | public static function range($low, $high, $step = 1) : Collection |
|
| 28 | { |
||
| 29 | 4 | return new static(static::rangeGenerator($low, $high, $step)); |
|
| 30 | } |
||
| 31 | /** |
||
| 32 | * A static alias of the __constructor |
||
| 33 | * @param mixed $input Anything iterable |
||
| 34 | * @return Collection |
||
| 35 | */ |
||
| 36 | 53 | public static function from($input) : Collection |
|
| 37 | { |
||
| 38 | 53 | return new static($input); |
|
| 39 | } |
||
| 40 | /** |
||
| 41 | * Create an instance |
||
| 42 | * @param mixed $input Anything iterable |
||
| 43 | */ |
||
| 44 | 57 | public function __construct($input = []) |
|
| 45 | { |
||
| 46 | 57 | if (is_object($input)) { |
|
| 47 | 28 | if ($input instanceof \Iterator) { |
|
| 48 | 5 | $this->array = $input; |
|
| 49 | 5 | $this->iterator = $input; |
|
| 50 | 23 | } else if ($input instanceof self) { |
|
| 51 | $this->array = $input->toArray(); |
||
| 52 | } else { |
||
| 53 | 23 | $input = get_object_vars($input); |
|
| 54 | } |
||
| 55 | } |
||
| 56 | 57 | if (is_array($input)) { |
|
| 57 | 53 | $this->array = new \ArrayObject($input); |
|
| 58 | 53 | $this->iterator = $this->array->getIterator(); |
|
| 59 | } |
||
| 60 | 57 | } |
|
| 61 | public function __clone() |
||
| 62 | { |
||
| 63 | $this->array = new \ArrayObject(iterator_to_array($this)); |
||
| 64 | $this->stack = []; |
||
| 65 | $this->iterator = $this->array->getIterator(); |
||
| 66 | } |
||
| 67 | 1 | public function __toString() |
|
| 68 | { |
||
| 69 | 1 | return implode(', ', $this->toArray()); |
|
| 70 | } |
||
| 71 | 1 | public function serialize() { |
|
| 72 | 1 | return serialize($this->toArray()); |
|
| 73 | } |
||
| 74 | 1 | public function unserialize($array) { |
|
| 75 | 1 | $this->array = new \ArrayObject(unserialize($array)); |
|
| 76 | 1 | $this->stack = []; |
|
| 77 | 1 | $this->iterator = $this->array->getIterator(); |
|
| 78 | 1 | } |
|
| 79 | |||
| 80 | /** |
||
| 81 | * Applies all pending operations |
||
| 82 | * @return $this |
||
| 83 | */ |
||
| 84 | 46 | public function squash() : Collection |
|
| 85 | { |
||
| 86 | 46 | if (count($this->stack) || !($this->array instanceof \ArrayObject)) { |
|
| 87 | 18 | $this->array = new \ArrayObject(iterator_to_array($this)); |
|
| 88 | 18 | $this->stack = []; |
|
| 89 | 18 | $this->iterator = $this->array->getIterator(); |
|
| 90 | } |
||
| 91 | 46 | return $this; |
|
| 92 | } |
||
| 93 | /** |
||
| 94 | * Get an actual array from the collection |
||
| 95 | * @return array |
||
| 96 | */ |
||
| 97 | 45 | public function toArray() : array |
|
| 98 | { |
||
| 99 | 45 | return $this->squash()->array->getArrayCopy(); |
|
|
0 ignored issues
–
show
|
|||
| 100 | } |
||
| 101 | /** |
||
| 102 | * Gets the first value in the collection or null if empty |
||
| 103 | * @return mixed |
||
| 104 | */ |
||
| 105 | 3 | public function value() |
|
| 106 | { |
||
| 107 | 3 | foreach ($this as $v) { |
|
| 108 | 3 | return $v; |
|
| 109 | } |
||
| 110 | 1 | return null; |
|
| 111 | } |
||
| 112 | |||
| 113 | // iterator |
||
| 114 | 29 | public function key() |
|
| 115 | { |
||
| 116 | 29 | return $this->key; |
|
| 117 | } |
||
| 118 | 34 | public function current() |
|
| 119 | { |
||
| 120 | 34 | return $this->val; |
|
| 121 | } |
||
| 122 | 34 | public function rewind() |
|
| 123 | { |
||
| 124 | 34 | return $this->iterator->rewind(); |
|
| 125 | } |
||
| 126 | 31 | public function next() |
|
| 127 | { |
||
| 128 | 31 | return $this->iterator->next(); |
|
| 129 | } |
||
| 130 | 34 | public function valid() |
|
| 131 | { |
||
| 132 | 34 | while ($this->iterator->valid()) { |
|
| 133 | 34 | $this->val = $this->iterator->current(); |
|
| 134 | 34 | $this->key = $this->iterator->key(); |
|
| 135 | 34 | $con = false; |
|
| 136 | 34 | foreach ($this->stack as $action) { |
|
| 137 | 14 | if ($action[0] === 'filter') { |
|
| 138 | 10 | if (!call_user_func($action[1], $this->val, $this->key, $this)) { |
|
| 139 | 10 | $con = true; |
|
| 140 | 10 | break; |
|
| 141 | } |
||
| 142 | } |
||
| 143 | 14 | if ($action[0] === 'map') { |
|
| 144 | 7 | $this->val = call_user_func($action[1], $this->val, $this->key, $this); |
|
| 145 | } |
||
| 146 | 14 | if ($action[0] === 'mapKey') { |
|
| 147 | 14 | $this->key = call_user_func($action[1], $this->val, $this->key, $this); |
|
| 148 | } |
||
| 149 | } |
||
| 150 | 34 | if ($con) { |
|
| 151 | 10 | $this->iterator->next(); |
|
| 152 | 10 | continue; |
|
| 153 | } |
||
| 154 | 34 | return true; |
|
| 155 | } |
||
| 156 | 31 | return false; |
|
| 157 | } |
||
| 158 | |||
| 159 | // array access |
||
| 160 | 1 | public function offsetGet($offset) |
|
| 161 | { |
||
| 162 | 1 | return $this->squash()->array->offsetGet($offset); |
|
|
0 ignored issues
–
show
The method
offsetGet does only exist in ArrayObject, but not in Iterator.
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
Loading history...
|
|||
| 163 | } |
||
| 164 | 1 | public function offsetExists($offset) |
|
| 165 | { |
||
| 166 | 1 | return $this->squash()->array->offsetExists($offset); |
|
|
0 ignored issues
–
show
The method
offsetExists does only exist in ArrayObject, but not in Iterator.
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
Loading history...
|
|||
| 167 | } |
||
| 168 | 1 | public function offsetUnset($offset) |
|
| 169 | { |
||
| 170 | 1 | return $this->squash()->array->offsetUnset($offset); |
|
|
0 ignored issues
–
show
The method
offsetUnset does only exist in ArrayObject, but not in Iterator.
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
Loading history...
|
|||
| 171 | } |
||
| 172 | 1 | public function offsetSet($offset, $value) |
|
| 173 | { |
||
| 174 | 1 | return $this->squash()->array->offsetSet($offset, $value); |
|
|
0 ignored issues
–
show
The method
offsetSet does only exist in ArrayObject, but not in Iterator.
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
Loading history...
|
|||
| 175 | } |
||
| 176 | public function add($value) |
||
| 177 | { |
||
| 178 | $this->squash()->array->append($value); |
||
|
0 ignored issues
–
show
The method
append does only exist in ArrayObject, but not in Iterator.
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
Loading history...
|
|||
| 179 | return $this; |
||
| 180 | } |
||
| 181 | public function append($value) |
||
| 182 | { |
||
| 183 | return $this->add($value); |
||
| 184 | } |
||
| 185 | public function remove($value) |
||
| 186 | { |
||
| 187 | return $this->filter(function ($v) use ($value) { return $v !== $value; })->squash(); |
||
| 188 | } |
||
| 189 | /** |
||
| 190 | * Get the collection length |
||
| 191 | * @return int |
||
| 192 | */ |
||
| 193 | 1 | public function count() |
|
| 194 | { |
||
| 195 | 1 | if (count($this->stack) || !($this->array instanceof \Countable)) { |
|
| 196 | $this->squash(); |
||
| 197 | } |
||
| 198 | 1 | return $this->array->count(); |
|
| 199 | } |
||
| 200 | |||
| 201 | // mutators |
||
| 202 | /** |
||
| 203 | * Filter values from the collection based on a predicate. The callback will receive the value, key and collection |
||
| 204 | * @param callable $iterator the predicate |
||
| 205 | * @return $this |
||
| 206 | */ |
||
| 207 | 10 | public function filter(callable $iterator) : Collection |
|
| 208 | { |
||
| 209 | 10 | $this->stack[] = [ 'filter', $iterator ]; |
|
| 210 | 10 | return $this; |
|
| 211 | } |
||
| 212 | /** |
||
| 213 | * Pass all values of the collection through a mutator callable, which will receive the value, key and collection |
||
| 214 | * @param callable $iterator the mutator |
||
| 215 | * @return $this |
||
| 216 | */ |
||
| 217 | 7 | public function map(callable $iterator) : Collection |
|
| 218 | { |
||
| 219 | 7 | $this->stack[] = [ 'map', $iterator ]; |
|
| 220 | 7 | return $this; |
|
| 221 | } |
||
| 222 | /** |
||
| 223 | * Pass all values of the collection through a key mutator callable, which will receive the value, key and collection |
||
| 224 | * @param callable $iterator the mutator |
||
| 225 | * @return $this |
||
| 226 | */ |
||
| 227 | 1 | public function mapKey(callable $iterator) : Collection |
|
| 228 | { |
||
| 229 | 1 | $this->stack[] = [ 'mapKey', $iterator ]; |
|
| 230 | 1 | return $this; |
|
| 231 | } |
||
| 232 | /** |
||
| 233 | * Clone the current collection and return it. |
||
| 234 | * @return Collection |
||
| 235 | */ |
||
| 236 | public function clone() : Collection |
||
| 237 | { |
||
| 238 | 1 | return new static($this->toArray()); |
|
| 239 | } |
||
| 240 | /** |
||
| 241 | * Remove all falsy values from the collection (uses filter internally). |
||
| 242 | * @return $this |
||
| 243 | */ |
||
| 244 | 1 | public function compact() : Collection |
|
| 245 | { |
||
| 246 | return $this->filter(function ($v) { |
||
| 247 | 1 | return !!$v; |
|
| 248 | 1 | }); |
|
| 249 | } |
||
| 250 | /** |
||
| 251 | * Exclude all listed values from the collection (uses filter internally). |
||
| 252 | * @param iterable $values the values to exclude |
||
| 253 | * @return $this |
||
| 254 | */ |
||
| 255 | 3 | public function difference($values) : Collection |
|
| 256 | { |
||
| 257 | 3 | if (!is_array($values)) { |
|
| 258 | 1 | $values = iterator_to_array($values); |
|
| 259 | } |
||
| 260 | 3 | $keys = array_keys($values); |
|
| 261 | 3 | $isAssoc = $keys !== array_keys($keys); |
|
| 262 | return $this->filter(function ($v, $k) use ($values, $isAssoc) { |
||
| 263 | 3 | return $isAssoc ? |
|
| 264 | 1 | ($index = array_search($v, $values)) === false || $index !== $k : |
|
| 265 | 3 | !in_array($v, $values, true); |
|
| 266 | 3 | }); |
|
| 267 | } |
||
| 268 | /** |
||
| 269 | * Append more values to the collection |
||
| 270 | * @param iterable $source the values to add |
||
| 271 | * @return Collection |
||
| 272 | */ |
||
| 273 | 2 | public function extend($source) : Collection |
|
| 274 | { |
||
| 275 | 2 | if (!is_array($source)) { |
|
| 276 | 1 | $source = iterator_to_array($source); |
|
| 277 | } |
||
| 278 | 2 | return new static(array_merge($this->toArray(), $source)); |
|
| 279 | } |
||
| 280 | /** |
||
| 281 | * Append more values to the collection |
||
| 282 | * @param iterable $source the values to add |
||
| 283 | * @return Collection |
||
| 284 | */ |
||
| 285 | 1 | public function merge($source) : Collection |
|
| 286 | { |
||
| 287 | 1 | return $this->extend($source); |
|
| 288 | } |
||
| 289 | /** |
||
| 290 | * Perform a shallow flatten of the collection |
||
| 291 | * @return Collection |
||
| 292 | */ |
||
| 293 | 1 | public function flatten() : Collection |
|
| 294 | { |
||
| 295 | 1 | $rslt = []; |
|
| 296 | 1 | $temp = $this->toArray(); |
|
| 297 | 1 | foreach ($temp as $v) { |
|
| 298 | 1 | $rslt = array_merge($rslt, is_array($v) ? $v : [$v]); |
|
| 299 | } |
||
| 300 | 1 | return new static($rslt); |
|
| 301 | } |
||
| 302 | /** |
||
| 303 | * Group by a key (if a callable is used - return the value to group by) |
||
| 304 | * @param string|callable $iterator the key to group by |
||
| 305 | * @return Collection |
||
| 306 | */ |
||
| 307 | 1 | public function groupBy($iterator) : Collection |
|
| 308 | { |
||
| 309 | 1 | $rslt = []; |
|
| 310 | 1 | $temp = $this->toArray(); |
|
| 311 | 1 | foreach ($temp as $k => $v) { |
|
| 312 | 1 | $rslt[is_string($iterator) ? (is_object($v) ? $v->{$iterator} : $v[$iterator]) : call_user_func($iterator, $v, $k)][] = $v; |
|
| 313 | } |
||
| 314 | 1 | return new static($rslt); |
|
| 315 | } |
||
| 316 | /** |
||
| 317 | * Get the first X items from the collection |
||
| 318 | * @param int $count the number of items to include (defaults to 1) |
||
| 319 | * @return Collection |
||
| 320 | */ |
||
| 321 | 1 | public function first(int $count = 1) : Collection |
|
| 322 | { |
||
| 323 | 1 | $i = 0; |
|
| 324 | 1 | $new = []; |
|
| 325 | 1 | foreach ($this as $k => $v) { |
|
| 326 | 1 | if (++$i > $count) { |
|
| 327 | 1 | break; |
|
| 328 | } |
||
| 329 | 1 | $new[$k] = $v; |
|
| 330 | } |
||
| 331 | 1 | return new static($new); |
|
| 332 | } |
||
| 333 | /** |
||
| 334 | * Get the first X items from the collection |
||
| 335 | * @param int $count the number of items to include (defaults to 1) |
||
| 336 | * @return Collection |
||
| 337 | */ |
||
| 338 | 1 | public function head(int $count = 1) : Collection |
|
| 339 | { |
||
| 340 | 1 | return $this->first($count); |
|
| 341 | } |
||
| 342 | /** |
||
| 343 | * Get the last X items from the collection |
||
| 344 | * @param int $count the number of items to include (defaults to 1) |
||
| 345 | * @return Collection |
||
| 346 | */ |
||
| 347 | 2 | public function last(int $count = 1) : Collection |
|
| 348 | { |
||
| 349 | 2 | $new = $this->toArray(); |
|
| 350 | 2 | return new static(array_slice($new, $count * -1)); |
|
| 351 | } |
||
| 352 | /** |
||
| 353 | * Get the first X items from the collection |
||
| 354 | * @param int $count the number of items to include (defaults to 1) |
||
| 355 | * @return Collection |
||
| 356 | */ |
||
| 357 | 1 | public function tail(int $count = 1) : Collection |
|
| 358 | { |
||
| 359 | 1 | return $this->last($count); |
|
| 360 | } |
||
| 361 | /** |
||
| 362 | * Get all but the last X items from the collection |
||
| 363 | * @param int $count the number of items to exclude (defaults to 1) |
||
| 364 | * @return Collection |
||
| 365 | */ |
||
| 366 | 1 | public function initial(int $count = 1) : Collection |
|
| 367 | { |
||
| 368 | 1 | $new = $this->toArray(); |
|
| 369 | 1 | return new static(array_slice($new, 0, $count * -1)); |
|
| 370 | } |
||
| 371 | /** |
||
| 372 | * Get all but the first X items from the collection |
||
| 373 | * @param int $count the number of items to exclude (defaults to 1) |
||
| 374 | * @return Collection |
||
| 375 | */ |
||
| 376 | 1 | public function rest(int $count = 1) : Collection |
|
| 377 | { |
||
| 378 | 1 | $new = $this->toArray(); |
|
| 379 | 1 | return new static(array_slice($new, $count)); |
|
| 380 | } |
||
| 381 | /** |
||
| 382 | * Execute a callable for each item in the collection (does not modify the collection) |
||
| 383 | * @param callable $iterator the callable to execute |
||
| 384 | * @return $this |
||
| 385 | */ |
||
| 386 | 1 | public function each(callable $iterator) : Collection |
|
| 387 | { |
||
| 388 | 1 | foreach ($this as $k => $v) { |
|
| 389 | 1 | call_user_func($iterator, $v, $k, $this); |
|
| 390 | } |
||
| 391 | 1 | return $this; |
|
| 392 | } |
||
| 393 | /** |
||
| 394 | * Execute a callable for each item in the collection (does not modify the collection) |
||
| 395 | * @param callable $iterator the callable to execute |
||
| 396 | * @return $this |
||
| 397 | */ |
||
| 398 | 1 | public function invoke(callable $iterator) : Collection |
|
| 399 | { |
||
| 400 | 1 | return $this->each($iterator); |
|
| 401 | } |
||
| 402 | /** |
||
| 403 | * Get all the collection keys |
||
| 404 | * @return $this |
||
| 405 | */ |
||
| 406 | public function keys() : Collection |
||
| 407 | { |
||
| 408 | return $this->map(function ($v, $k) { return $k; })->values(); |
||
| 409 | } |
||
| 410 | /** |
||
| 411 | * Pluck a value from each object (uses map internally) |
||
| 412 | * @param string|int $key the key to extract |
||
| 413 | * @return $this |
||
| 414 | */ |
||
| 415 | 2 | public function pluck($key) : Collection |
|
| 416 | { |
||
| 417 | return $this->map(function ($v) use ($key) { |
||
| 418 | 2 | return is_object($v) ? |
|
| 419 | 1 | (isset($v->{$key}) ? $v->{$key} : null) : |
|
| 420 | 2 | (isset($v[$key]) ? $v[$key] : null); |
|
| 421 | 2 | }); |
|
| 422 | } |
||
| 423 | /** |
||
| 424 | * Intersect the collection with another iterable (uses filter internally) |
||
| 425 | * @param interable $values the data to intersect with |
||
| 426 | * @return $this |
||
| 427 | */ |
||
| 428 | 1 | public function intersection($values) : Collection |
|
| 429 | { |
||
| 430 | 1 | if (!is_array($values)) { |
|
| 431 | 1 | $values = iterator_to_array($values); |
|
| 432 | } |
||
| 433 | 1 | $keys = array_keys($values); |
|
| 434 | 1 | $isAssoc = $keys !== array_keys($keys); |
|
| 435 | return $this->filter(function ($v, $k) use ($values, $isAssoc) { |
||
| 436 | 1 | return $isAssoc ? |
|
| 437 | 1 | array_search($v, $values) === $k : |
|
| 438 | 1 | in_array($v, $values, true); |
|
| 439 | 1 | }); |
|
| 440 | } |
||
| 441 | /** |
||
| 442 | * Reject values on a given predicate (opposite of filter) |
||
| 443 | * @param callable $iterator the predicate |
||
| 444 | * @return $this |
||
| 445 | */ |
||
| 446 | 1 | public function reject(callable $iterator) : Collection |
|
| 447 | { |
||
| 448 | return $this->filter(function ($v, $k, $array) use ($iterator) { |
||
| 449 | 1 | return !call_user_func($iterator, $v, $k, $array); |
|
| 450 | 1 | }); |
|
| 451 | } |
||
| 452 | /** |
||
| 453 | * Shuffle the values in the collection |
||
| 454 | * @return Collection |
||
| 455 | */ |
||
| 456 | 1 | public function shuffle() : Collection |
|
| 457 | { |
||
| 458 | 1 | $temp = $this->toArray(); |
|
| 459 | 1 | $keys = array_keys($temp); |
|
| 460 | 1 | shuffle($keys); |
|
| 461 | 1 | $rslt = []; |
|
| 462 | 1 | foreach ($keys as $key) { |
|
| 463 | 1 | $rslt[$key] = $temp[$key]; |
|
| 464 | } |
||
| 465 | 1 | return new static($rslt); |
|
| 466 | } |
||
| 467 | /** |
||
| 468 | * Sort the collection using a standard sorting function |
||
| 469 | * @param callable $iterator the sort function (must return -1, 0 or 1) |
||
| 470 | * @return Collection |
||
| 471 | */ |
||
| 472 | 1 | public function sortBy(callable $iterator) : Collection |
|
| 473 | { |
||
| 474 | 1 | $this->squash(); |
|
| 475 | 1 | $this->array->uasort($iterator); |
|
| 476 | 1 | return $this; |
|
| 477 | } |
||
| 478 | /** |
||
| 479 | * Inspect the whole collection (as an array) mid-chain |
||
| 480 | * @param callable $iterator the callable to execute |
||
| 481 | * @return $this |
||
| 482 | */ |
||
| 483 | 1 | public function tap(callable $iterator) : Collection |
|
| 484 | { |
||
| 485 | 1 | call_user_func($iterator, $this->toArray()); |
|
| 486 | 1 | return $this; |
|
| 487 | } |
||
| 488 | /** |
||
| 489 | * Modify the whole collection (as an array) mid-chain |
||
| 490 | * @param callable $iterator the callable to execute |
||
| 491 | * @return Collection |
||
| 492 | */ |
||
| 493 | 1 | public function thru(callable $iterator) : Collection |
|
| 494 | { |
||
| 495 | 1 | $temp = $this->toArray(); |
|
| 496 | 1 | $rslt = call_user_func($iterator, $temp); |
|
| 497 | 1 | return new static($rslt); |
|
| 498 | } |
||
| 499 | /** |
||
| 500 | * Leave only unique items in the collection |
||
| 501 | * @return Collection |
||
| 502 | */ |
||
| 503 | 3 | public function unique() : Collection |
|
| 504 | { |
||
| 505 | 3 | $temp = $this->toArray(); |
|
| 506 | 3 | $rslt = []; |
|
| 507 | 3 | foreach ($temp as $k => $v) { |
|
| 508 | 3 | if (!in_array($v, $rslt, true)) { |
|
| 509 | 3 | $rslt[$k] = $v; |
|
| 510 | } |
||
| 511 | } |
||
| 512 | 3 | return new static($rslt); |
|
| 513 | } |
||
| 514 | /** |
||
| 515 | * Get only the values of the collection |
||
| 516 | * @return Collection |
||
| 517 | */ |
||
| 518 | 5 | public function values() : Collection |
|
| 519 | { |
||
| 520 | 5 | return new static(array_values($this->toArray())); |
|
| 521 | } |
||
| 522 | |||
| 523 | 3 | protected function whereCallback($v, $properties, $strict = true) |
|
| 524 | { |
||
| 525 | 3 | foreach ($properties as $key => $value) { |
|
| 526 | 3 | $vv = is_object($v) ? (isset($v->{$key}) ? $v->{$key} : null) : (isset($v[$key]) ? $v[$key] : null); |
|
| 527 | 3 | $negate = false; |
|
| 528 | 3 | if (is_array($value) && count($value) === 1 && isset($value['not'])) { |
|
| 529 | 2 | $value = $value['not']; |
|
| 530 | 2 | $negate = true; |
|
| 531 | } |
||
| 532 | 3 | if (is_array($value) && isset($value['beg']) && strlen($value['beg']) && (!isset($value['end']) || !strlen($value['end']))) { |
|
| 533 | $value = [ 'gte' => $value['beg'] ]; |
||
| 534 | } |
||
| 535 | 3 | if (is_array($value) && isset($value['end']) && strlen($value['end']) && (!isset($value['beg']) || !strlen($value['beg']))) { |
|
| 536 | $value = [ 'lte' => $value['end'] ]; |
||
| 537 | } |
||
| 538 | 3 | if (is_array($value)) { |
|
| 539 | 1 | if (isset($value['beg']) && isset($value['end'])) { |
|
| 540 | 1 | if ($vv < $value['beg'] || $vv > $value['end']) { |
|
| 541 | 1 | if (!$negate) { |
|
| 542 | 1 | return false; |
|
| 543 | } |
||
| 544 | } else { |
||
| 545 | 1 | if ($negate) { |
|
| 546 | 1 | return false; |
|
| 547 | } |
||
| 548 | } |
||
| 549 | 1 | } elseif (isset($value['lt']) || isset($value['gt']) || isset($value['lte']) || isset($value['gte'])) { |
|
| 550 | 1 | if (isset($value['lt']) && $vv >= $value['lt']) { |
|
| 551 | 1 | if (!$negate) { |
|
| 552 | 1 | return false; |
|
| 553 | } |
||
| 554 | } else { |
||
| 555 | 1 | if ($negate) { |
|
| 556 | return false; |
||
| 557 | } |
||
| 558 | } |
||
| 559 | 1 | if (isset($value['gt']) && $vv <= $value['gt']) { |
|
| 560 | if (!$negate) { |
||
| 561 | return false; |
||
| 562 | } |
||
| 563 | } else { |
||
| 564 | 1 | if ($negate) { |
|
| 565 | return false; |
||
| 566 | } |
||
| 567 | } |
||
| 568 | 1 | if (isset($value['lte']) && $vv > $value['lte']) { |
|
| 569 | 1 | if (!$negate) { |
|
| 570 | 1 | return false; |
|
| 571 | } |
||
| 572 | } else { |
||
| 573 | 1 | if ($negate) { |
|
| 574 | return false; |
||
| 575 | } |
||
| 576 | } |
||
| 577 | 1 | if (isset($value['gte']) && $vv < $value['gte']) { |
|
| 578 | 1 | if (!$negate) { |
|
| 579 | 1 | return false; |
|
| 580 | } |
||
| 581 | } else { |
||
| 582 | 1 | if ($negate) { |
|
| 583 | 1 | return false; |
|
| 584 | } |
||
| 585 | } |
||
| 586 | } else { |
||
| 587 | 1 | if (!in_array($vv, $value, $strict)) { |
|
| 588 | 1 | if (!$negate) { |
|
| 589 | 1 | return false; |
|
| 590 | } |
||
| 591 | } else { |
||
| 592 | 1 | if ($negate) { |
|
| 593 | 1 | return false; |
|
| 594 | } |
||
| 595 | } |
||
| 596 | } |
||
| 597 | } else { |
||
| 598 | 3 | if (($strict && $vv !== $value) || (!$strict && $vv != $value)) { |
|
| 599 | 3 | if (!$negate) { |
|
| 600 | 3 | return false; |
|
| 601 | } |
||
| 602 | } else { |
||
| 603 | 3 | if ($negate) { |
|
| 604 | 3 | return false; |
|
| 605 | } |
||
| 606 | } |
||
| 607 | } |
||
| 608 | } |
||
| 609 | 3 | return true; |
|
| 610 | } |
||
| 611 | 1 | public function whereAll(array $criteria) : Collection |
|
| 612 | { |
||
| 613 | return $this->filter(function ($v) use ($criteria) { |
||
| 614 | 1 | foreach ($criteria as $row) { |
|
| 615 | 1 | if (!$this->whereCallback($v, $row)) { |
|
| 616 | 1 | return false; |
|
| 617 | } |
||
| 618 | } |
||
| 619 | 1 | return true; |
|
| 620 | 1 | }); |
|
| 621 | } |
||
| 622 | 1 | public function whereAny(array $criteria) : Collection |
|
| 623 | { |
||
| 624 | return $this->filter(function ($v) use ($criteria) { |
||
| 625 | 1 | foreach ($criteria as $row) { |
|
| 626 | 1 | if ($this->whereCallback($v, $row)) { |
|
| 627 | 1 | return true; |
|
| 628 | } |
||
| 629 | } |
||
| 630 | 1 | return false; |
|
| 631 | 1 | }); |
|
| 632 | } |
||
| 633 | /** |
||
| 634 | * Filter items from the collection using key => value pairs |
||
| 635 | * @param array $properties the key => value to check for in each item |
||
| 636 | * @param boolean $strict should the comparison be strict |
||
| 637 | * @return $this |
||
| 638 | */ |
||
| 639 | public function where(array $properties, $strict = true) : Collection |
||
| 640 | { |
||
| 641 | 1 | return $this->filter(function ($v) use ($properties, $strict) { |
|
| 642 | 1 | return $this->whereCallback($v, $properties, $strict); |
|
| 643 | 1 | }); |
|
| 644 | } |
||
| 645 | /** |
||
| 646 | * Exclude all listed values from the collection (uses filter internally). |
||
| 647 | * @param iterable $values the values to exclude |
||
| 648 | * @return $this |
||
| 649 | */ |
||
| 650 | 2 | public function without($values) : Collection |
|
| 651 | { |
||
| 652 | 2 | return $this->difference($values); |
|
| 653 | } |
||
| 654 | /** |
||
| 655 | * Combine all the values from the collection with a key |
||
| 656 | * @param iterable $keys the keys to use |
||
| 657 | * @return Collection |
||
| 658 | */ |
||
| 659 | 2 | public function zip($keys) : Collection |
|
| 660 | { |
||
| 661 | 2 | if (!is_array($keys)) { |
|
| 662 | 1 | $keys = iterator_to_array($keys); |
|
| 663 | } |
||
| 664 | 2 | return new static(array_combine($keys, $this->toArray())); |
|
| 665 | } |
||
| 666 | /** |
||
| 667 | * Reverse the collection order |
||
| 668 | * @return Collection |
||
| 669 | */ |
||
| 670 | 2 | public function reverse() : Collection |
|
| 671 | { |
||
| 672 | 2 | return new static(array_reverse($this->toArray())); |
|
| 673 | } |
||
| 674 | |||
| 675 | // accessors |
||
| 676 | /** |
||
| 677 | * Do all of the items in the collection match a given criteria |
||
| 678 | * @param callable $iterator the criteria - should return true / false |
||
| 679 | * @return bool |
||
| 680 | */ |
||
| 681 | 1 | public function all(callable $iterator) : bool |
|
| 682 | { |
||
| 683 | 1 | foreach ($this as $k => $v) { |
|
| 684 | 1 | if (!call_user_func($iterator, $v, $k, $this)) { |
|
| 685 | 1 | return false; |
|
| 686 | } |
||
| 687 | } |
||
| 688 | 1 | return true; |
|
| 689 | } |
||
| 690 | /** |
||
| 691 | * Do any of the items in the collection match a given criteria |
||
| 692 | * @param callable $iterator the criteria - should return true / false |
||
| 693 | * @return bool |
||
| 694 | */ |
||
| 695 | 1 | public function any(callable $iterator) : bool |
|
| 696 | { |
||
| 697 | 1 | foreach ($this as $k => $v) { |
|
| 698 | 1 | if (call_user_func($iterator, $v, $k, $this)) { |
|
| 699 | 1 | return true; |
|
| 700 | } |
||
| 701 | } |
||
| 702 | 1 | return false; |
|
| 703 | } |
||
| 704 | /** |
||
| 705 | * Does the collection contain a given value |
||
| 706 | * @param mixed $needle the value to check for |
||
| 707 | * @return bool |
||
| 708 | */ |
||
| 709 | 1 | public function contains($needle) : bool |
|
| 710 | { |
||
| 711 | 1 | foreach ($this as $k => $v) { |
|
| 712 | 1 | if ($v === $needle) { |
|
| 713 | 1 | return true; |
|
| 714 | } |
||
| 715 | } |
||
| 716 | 1 | return false; |
|
| 717 | } |
||
| 718 | /** |
||
| 719 | * Get the first element matching a given criteria (or null) |
||
| 720 | * @param callable $iterator the filter criteria |
||
| 721 | * @return mixed |
||
| 722 | */ |
||
| 723 | 1 | public function find(callable $iterator) |
|
| 724 | { |
||
| 725 | 1 | foreach ($this as $k => $v) { |
|
| 726 | 1 | if (call_user_func($iterator, $v, $k, $this)) { |
|
| 727 | 1 | return $v; |
|
| 728 | } |
||
| 729 | } |
||
| 730 | 1 | return null; |
|
| 731 | } |
||
| 732 | /** |
||
| 733 | * Get all the elements matching a given criteria (with the option to limit the number of results) |
||
| 734 | * @param callable $iterator the search criteria |
||
| 735 | * @param int|null $limit optional limit to the number of results (default to null - no limit) |
||
| 736 | * @return Collection |
||
| 737 | */ |
||
| 738 | 1 | public function findAll(callable $iterator, int $limit = null) : Collection |
|
| 739 | { |
||
| 740 | 1 | $res = []; |
|
| 741 | 1 | foreach ($this as $k => $v) { |
|
| 742 | 1 | if (call_user_func($iterator, $v, $k, $this)) { |
|
| 743 | 1 | $res[] = $v; |
|
| 744 | } |
||
| 745 | 1 | if ((int)$limit > 0 && count($res) >= $limit) { |
|
| 746 | 1 | break; |
|
| 747 | } |
||
| 748 | } |
||
| 749 | 1 | return new static($res); |
|
| 750 | } |
||
| 751 | /** |
||
| 752 | * Get the key corresponding to a value (or false) |
||
| 753 | * @param mixed $needle the value to search for |
||
| 754 | * @return mixed |
||
| 755 | */ |
||
| 756 | 1 | public function indexOf($needle) |
|
| 757 | { |
||
| 758 | 1 | return array_search($needle, $this->toArray(), true); |
|
| 759 | } |
||
| 760 | /** |
||
| 761 | * Get the last key corresponding to a value (or false) |
||
| 762 | * @param mixed $needle the value to search for |
||
| 763 | * @return mixed |
||
| 764 | */ |
||
| 765 | 1 | public function lastIndexOf($needle) |
|
| 766 | { |
||
| 767 | 1 | $res = null; |
|
| 768 | 1 | foreach ($this as $k => $v) { |
|
| 769 | 1 | if ($v === $needle) { |
|
| 770 | 1 | $res = $k; |
|
| 771 | } |
||
| 772 | } |
||
| 773 | 1 | return $res; |
|
| 774 | } |
||
| 775 | /** |
||
| 776 | * Get the number of elements in the collection |
||
| 777 | * @return int |
||
| 778 | */ |
||
| 779 | 1 | public function size() : int |
|
| 780 | { |
||
| 781 | 1 | return $this->count(); |
|
| 782 | } |
||
| 783 | /** |
||
| 784 | * Get the minimal item in the collection |
||
| 785 | * @return mixed |
||
| 786 | */ |
||
| 787 | 1 | public function min() |
|
| 788 | { |
||
| 789 | 1 | $min = null; |
|
| 790 | 1 | $first = false; |
|
| 791 | 1 | foreach ($this as $v) { |
|
| 792 | 1 | if (!$first || $v < $min) { |
|
| 793 | 1 | $min = $v; |
|
| 794 | 1 | $first = true; |
|
| 795 | } |
||
| 796 | } |
||
| 797 | 1 | return $min; |
|
| 798 | } |
||
| 799 | /** |
||
| 800 | * Get the maximum item in the collection |
||
| 801 | * @return mixed |
||
| 802 | */ |
||
| 803 | 1 | public function max() |
|
| 804 | { |
||
| 805 | 1 | $max = null; |
|
| 806 | 1 | $first = false; |
|
| 807 | 1 | foreach ($this as $v) { |
|
| 808 | 1 | if (!$first || $v > $max) { |
|
| 809 | 1 | $max = $v; |
|
| 810 | 1 | $first = true; |
|
| 811 | } |
||
| 812 | } |
||
| 813 | 1 | return $max; |
|
| 814 | } |
||
| 815 | /** |
||
| 816 | * Does the collection contain a given key |
||
| 817 | * @param string|int $key the key to check |
||
| 818 | * @return bool |
||
| 819 | */ |
||
| 820 | 1 | public function has($key) : bool |
|
| 821 | { |
||
| 822 | 1 | return $this->offsetExists($key); |
|
| 823 | } |
||
| 824 | /** |
||
| 825 | * Reduce the collection to a single value |
||
| 826 | * @param callable $iterator the reducer (will recieve the carried value, the value, the key and the collection) |
||
| 827 | * @param mixed $initial the initial value |
||
| 828 | * @return mixed the final value |
||
| 829 | */ |
||
| 830 | 2 | public function reduce(callable $iterator, $initial = null) |
|
| 831 | { |
||
| 832 | 2 | foreach ($this as $k => $v) { |
|
| 833 | 2 | $initial = $iterator($initial, $v, $k, $this); |
|
| 834 | } |
||
| 835 | 2 | return $initial; |
|
| 836 | } |
||
| 837 | /** |
||
| 838 | * Reduce the collection to a single value, starting from the last element |
||
| 839 | * @param callable $iterator the reducer (will recieve the carried value, the value, the key and the collection) |
||
| 840 | * @param mixed $initial the initial value |
||
| 841 | * @return mixed the final value |
||
| 842 | */ |
||
| 843 | 1 | public function reduceRight(callable $iterator, $initial = null) |
|
| 844 | { |
||
| 845 | 1 | return $this->reverse()->reduce($iterator, $initial); |
|
| 846 | } |
||
| 847 | } |
||
| 848 |
It seems like the method you are trying to call exists only in some of the possible types.
Let’s take a look at an example:
Available Fixes
Add an additional type-check:
Only allow a single type to be passed if the variable comes from a parameter: