Arr.php000064400000056440147536122360006023 0ustar00all(); } elseif (! is_array($values)) { continue; } $results[] = $values; } return array_merge([], ...$results); } /** * Cross join the given arrays, returning all possible permutations. * * @param iterable ...$arrays * @return array */ public static function crossJoin(...$arrays) { $results = [[]]; foreach ($arrays as $index => $array) { $append = []; foreach ($results as $product) { foreach ($array as $item) { $product[$index] = $item; $append[] = $product; } } $results = $append; } return $results; } /** * Divide an array into two arrays. One with keys and the other with values. * * @param array $array * @return array */ public static function divide($array) { return [array_keys($array), array_values($array)]; } /** * Flatten a multi-dimensional associative array with dots. * * @param iterable $array * @param string $prepend * @return array */ public static function dot($array, $prepend = '') { $results = []; foreach ($array as $key => $value) { if (is_array($value) && ! empty($value)) { $results = array_merge($results, static::dot($value, $prepend.$key.'.')); } else { $results[$prepend.$key] = $value; } } return $results; } /** * Convert a flatten "dot" notation array into an expanded array. * * @param iterable $array * @return array */ public static function undot($array) { $results = []; foreach ($array as $key => $value) { static::set($results, $key, $value); } return $results; } /** * Get all of the given array except for a specified array of keys. * * @param array $array * @param array|string|int|float $keys * @return array */ public static function except($array, $keys) { static::forget($array, $keys); return $array; } /** * Determine if the given key exists in the provided array. * * @param \ArrayAccess|array $array * @param string|int $key * @return bool */ public static function exists($array, $key) { if ($array instanceof Enumerable) { return $array->has($key); } if ($array instanceof ArrayAccess) { return $array->offsetExists($key); } if (is_float($key)) { $key = (string) $key; } return array_key_exists($key, $array); } /** * Return the first element in an array passing a given truth test. * * @template TKey * @template TValue * @template TFirstDefault * * @param iterable $array * @param (callable(TValue, TKey): bool)|null $callback * @param TFirstDefault|(\Closure(): TFirstDefault) $default * @return TValue|TFirstDefault */ public static function first($array, ?callable $callback = null, $default = null) { if (is_null($callback)) { if (empty($array)) { return value($default); } foreach ($array as $item) { return $item; } return value($default); } foreach ($array as $key => $value) { if ($callback($value, $key)) { return $value; } } return value($default); } /** * Return the last element in an array passing a given truth test. * * @param array $array * @param callable|null $callback * @param mixed $default * @return mixed */ public static function last($array, ?callable $callback = null, $default = null) { if (is_null($callback)) { return empty($array) ? value($default) : end($array); } return static::first(array_reverse($array, true), $callback, $default); } /** * Take the first or last {$limit} items from an array. * * @param array $array * @param int $limit * @return array */ public static function take($array, $limit) { if ($limit < 0) { return array_slice($array, $limit, abs($limit)); } return array_slice($array, 0, $limit); } /** * Flatten a multi-dimensional array into a single level. * * @param iterable $array * @param int $depth * @return array */ public static function flatten($array, $depth = INF) { $result = []; foreach ($array as $item) { $item = $item instanceof Collection ? $item->all() : $item; if (! is_array($item)) { $result[] = $item; } else { $values = $depth === 1 ? array_values($item) : static::flatten($item, $depth - 1); foreach ($values as $value) { $result[] = $value; } } } return $result; } /** * Remove one or many array items from a given array using "dot" notation. * * @param array $array * @param array|string|int|float $keys * @return void */ public static function forget(&$array, $keys) { $original = &$array; $keys = (array) $keys; if (count($keys) === 0) { return; } foreach ($keys as $key) { // if the exact key exists in the top-level, remove it if (static::exists($array, $key)) { unset($array[$key]); continue; } $parts = explode('.', $key); // clean up before each pass $array = &$original; while (count($parts) > 1) { $part = array_shift($parts); if (isset($array[$part]) && static::accessible($array[$part])) { $array = &$array[$part]; } else { continue 2; } } unset($array[array_shift($parts)]); } } /** * Get an item from an array using "dot" notation. * * @param \ArrayAccess|array $array * @param string|int|null $key * @param mixed $default * @return mixed */ public static function get($array, $key, $default = null) { if (! static::accessible($array)) { return value($default); } if (is_null($key)) { return $array; } if (static::exists($array, $key)) { return $array[$key]; } if (! str_contains($key, '.')) { return $array[$key] ?? value($default); } foreach (explode('.', $key) as $segment) { if (static::accessible($array) && static::exists($array, $segment)) { $array = $array[$segment]; } else { return value($default); } } return $array; } /** * Check if an item or items exist in an array using "dot" notation. * * @param \ArrayAccess|array $array * @param string|array $keys * @return bool */ public static function has($array, $keys) { $keys = (array) $keys; if (! $array || $keys === []) { return false; } foreach ($keys as $key) { $subKeyArray = $array; if (static::exists($array, $key)) { continue; } foreach (explode('.', $key) as $segment) { if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) { $subKeyArray = $subKeyArray[$segment]; } else { return false; } } } return true; } /** * Determine if any of the keys exist in an array using "dot" notation. * * @param \ArrayAccess|array $array * @param string|array $keys * @return bool */ public static function hasAny($array, $keys) { if (is_null($keys)) { return false; } $keys = (array) $keys; if (! $array) { return false; } if ($keys === []) { return false; } foreach ($keys as $key) { if (static::has($array, $key)) { return true; } } return false; } /** * Determines if an array is associative. * * An array is "associative" if it doesn't have sequential numerical keys beginning with zero. * * @param array $array * @return bool */ public static function isAssoc(array $array) { return ! array_is_list($array); } /** * Determines if an array is a list. * * An array is a "list" if all array keys are sequential integers starting from 0 with no gaps in between. * * @param array $array * @return bool */ public static function isList($array) { return array_is_list($array); } /** * Join all items using a string. The final items can use a separate glue string. * * @param array $array * @param string $glue * @param string $finalGlue * @return string */ public static function join($array, $glue, $finalGlue = '') { if ($finalGlue === '') { return implode($glue, $array); } if (count($array) === 0) { return ''; } if (count($array) === 1) { return end($array); } $finalItem = array_pop($array); return implode($glue, $array).$finalGlue.$finalItem; } /** * Key an associative array by a field or using a callback. * * @param array $array * @param callable|array|string $keyBy * @return array */ public static function keyBy($array, $keyBy) { return Collection::make($array)->keyBy($keyBy)->all(); } /** * Prepend the key names of an associative array. * * @param array $array * @param string $prependWith * @return array */ public static function prependKeysWith($array, $prependWith) { return static::mapWithKeys($array, fn ($item, $key) => [$prependWith.$key => $item]); } /** * Get a subset of the items from the given array. * * @param array $array * @param array|string $keys * @return array */ public static function only($array, $keys) { return array_intersect_key($array, array_flip((array) $keys)); } /** * Select an array of values from an array. * * @param array $array * @param array|string $keys * @return array */ public static function select($array, $keys) { $keys = static::wrap($keys); return static::map($array, function ($item) use ($keys) { $result = []; foreach ($keys as $key) { if (Arr::accessible($item) && Arr::exists($item, $key)) { $result[$key] = $item[$key]; } elseif (is_object($item) && isset($item->{$key})) { $result[$key] = $item->{$key}; } } return $result; }); } /** * Pluck an array of values from an array. * * @param iterable $array * @param string|array|int|null $value * @param string|array|null $key * @return array */ public static function pluck($array, $value, $key = null) { $results = []; [$value, $key] = static::explodePluckParameters($value, $key); foreach ($array as $item) { $itemValue = data_get($item, $value); // If the key is "null", we will just append the value to the array and keep // looping. Otherwise we will key the array using the value of the key we // received from the developer. Then we'll return the final array form. if (is_null($key)) { $results[] = $itemValue; } else { $itemKey = data_get($item, $key); if (is_object($itemKey) && method_exists($itemKey, '__toString')) { $itemKey = (string) $itemKey; } $results[$itemKey] = $itemValue; } } return $results; } /** * Explode the "value" and "key" arguments passed to "pluck". * * @param string|array $value * @param string|array|null $key * @return array */ protected static function explodePluckParameters($value, $key) { $value = is_string($value) ? explode('.', $value) : $value; $key = is_null($key) || is_array($key) ? $key : explode('.', $key); return [$value, $key]; } /** * Run a map over each of the items in the array. * * @param array $array * @param callable $callback * @return array */ public static function map(array $array, callable $callback) { $keys = array_keys($array); try { $items = array_map($callback, $array, $keys); } catch (ArgumentCountError) { $items = array_map($callback, $array); } return array_combine($keys, $items); } /** * Run an associative map over each of the items. * * The callback should return an associative array with a single key/value pair. * * @template TKey * @template TValue * @template TMapWithKeysKey of array-key * @template TMapWithKeysValue * * @param array $array * @param callable(TValue, TKey): array $callback * @return array */ public static function mapWithKeys(array $array, callable $callback) { $result = []; foreach ($array as $key => $value) { $assoc = $callback($value, $key); foreach ($assoc as $mapKey => $mapValue) { $result[$mapKey] = $mapValue; } } return $result; } /** * Run a map over each nested chunk of items. * * @template TMapSpreadValue * * @param array $array * @param callable(mixed...): TMapSpreadValue $callback * @return array */ public static function mapSpread(array $array, callable $callback) { return static::map($array, function ($chunk, $key) use ($callback) { $chunk[] = $key; return $callback(...$chunk); }); } /** * Push an item onto the beginning of an array. * * @param array $array * @param mixed $value * @param mixed $key * @return array */ public static function prepend($array, $value, $key = null) { if (func_num_args() == 2) { array_unshift($array, $value); } else { $array = [$key => $value] + $array; } return $array; } /** * Get a value from the array, and remove it. * * @param array $array * @param string|int $key * @param mixed $default * @return mixed */ public static function pull(&$array, $key, $default = null) { $value = static::get($array, $key, $default); static::forget($array, $key); return $value; } /** * Convert the array into a query string. * * @param array $array * @return string */ public static function query($array) { return http_build_query($array, '', '&', PHP_QUERY_RFC3986); } /** * Get one or a specified number of random values from an array. * * @param array $array * @param int|null $number * @param bool $preserveKeys * @return mixed * * @throws \InvalidArgumentException */ public static function random($array, $number = null, $preserveKeys = false) { $requested = is_null($number) ? 1 : $number; $count = count($array); if ($requested > $count) { throw new InvalidArgumentException( "You requested {$requested} items, but there are only {$count} items available." ); } if (empty($array) || (! is_null($number) && $number <= 0)) { return is_null($number) ? null : []; } $keys = (new Randomizer)->pickArrayKeys($array, $requested); if (is_null($number)) { return $array[$keys[0]]; } $results = []; if ($preserveKeys) { foreach ($keys as $key) { $results[$key] = $array[$key]; } } else { foreach ($keys as $key) { $results[] = $array[$key]; } } return $results; } /** * Set an array item to a given value using "dot" notation. * * If no key is given to the method, the entire array will be replaced. * * @param array $array * @param string|int|null $key * @param mixed $value * @return array */ public static function set(&$array, $key, $value) { if (is_null($key)) { return $array = $value; } $keys = explode('.', $key); foreach ($keys as $i => $key) { if (count($keys) === 1) { break; } unset($keys[$i]); // If the key doesn't exist at this depth, we will just create an empty array // to hold the next value, allowing us to create the arrays to hold final // values at the correct depth. Then we'll keep digging into the array. if (! isset($array[$key]) || ! is_array($array[$key])) { $array[$key] = []; } $array = &$array[$key]; } $array[array_shift($keys)] = $value; return $array; } /** * Shuffle the given array and return the result. * * @param array $array * @return array */ public static function shuffle($array) { return (new Randomizer)->shuffleArray($array); } /** * Sort the array using the given callback or "dot" notation. * * @param array $array * @param callable|array|string|null $callback * @return array */ public static function sort($array, $callback = null) { return Collection::make($array)->sortBy($callback)->all(); } /** * Sort the array in descending order using the given callback or "dot" notation. * * @param array $array * @param callable|array|string|null $callback * @return array */ public static function sortDesc($array, $callback = null) { return Collection::make($array)->sortByDesc($callback)->all(); } /** * Recursively sort an array by keys and values. * * @param array $array * @param int $options * @param bool $descending * @return array */ public static function sortRecursive($array, $options = SORT_REGULAR, $descending = false) { foreach ($array as &$value) { if (is_array($value)) { $value = static::sortRecursive($value, $options, $descending); } } if (! array_is_list($array)) { $descending ? krsort($array, $options) : ksort($array, $options); } else { $descending ? rsort($array, $options) : sort($array, $options); } return $array; } /** * Recursively sort an array by keys and values in descending order. * * @param array $array * @param int $options * @return array */ public static function sortRecursiveDesc($array, $options = SORT_REGULAR) { return static::sortRecursive($array, $options, true); } /** * Conditionally compile classes from an array into a CSS class list. * * @param array $array * @return string */ public static function toCssClasses($array) { $classList = static::wrap($array); $classes = []; foreach ($classList as $class => $constraint) { if (is_numeric($class)) { $classes[] = $constraint; } elseif ($constraint) { $classes[] = $class; } } return implode(' ', $classes); } /** * Conditionally compile styles from an array into a style list. * * @param array $array * @return string */ public static function toCssStyles($array) { $styleList = static::wrap($array); $styles = []; foreach ($styleList as $class => $constraint) { if (is_numeric($class)) { $styles[] = Str::finish($constraint, ';'); } elseif ($constraint) { $styles[] = Str::finish($class, ';'); } } return implode(' ', $styles); } /** * Filter the array using the given callback. * * @param array $array * @param callable $callback * @return array */ public static function where($array, callable $callback) { return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH); } /** * Filter items where the value is not null. * * @param array $array * @return array */ public static function whereNotNull($array) { return static::where($array, fn ($value) => ! is_null($value)); } /** * If the given value is not an array and not null, wrap it in one. * * @param mixed $value * @return array */ public static function wrap($value) { if (is_null($value)) { return []; } return is_array($value) ? $value : [$value]; } } Collection.php000064400000136340147536122360007370 0ustar00 * @implements \Illuminate\Support\Enumerable */ class Collection implements ArrayAccess, CanBeEscapedWhenCastToString, Enumerable { /** * @use \Illuminate\Support\Traits\EnumeratesValues */ use EnumeratesValues, Macroable; /** * The items contained in the collection. * * @var array */ protected $items = []; /** * Create a new collection. * * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $items * @return void */ public function __construct($items = []) { $this->items = $this->getArrayableItems($items); } /** * Create a collection with the given range. * * @param int $from * @param int $to * @return static */ public static function range($from, $to) { return new static(range($from, $to)); } /** * Get all of the items in the collection. * * @return array */ public function all() { return $this->items; } /** * Get a lazy collection for the items in this collection. * * @return \Illuminate\Support\LazyCollection */ public function lazy() { return new LazyCollection($this->items); } /** * Get the average value of a given key. * * @param (callable(TValue): float|int)|string|null $callback * @return float|int|null */ public function avg($callback = null) { $callback = $this->valueRetriever($callback); $items = $this ->map(fn ($value) => $callback($value)) ->filter(fn ($value) => ! is_null($value)); if ($count = $items->count()) { return $items->sum() / $count; } } /** * Get the median of a given key. * * @param string|array|null $key * @return float|int|null */ public function median($key = null) { $values = (isset($key) ? $this->pluck($key) : $this) ->filter(fn ($item) => ! is_null($item)) ->sort()->values(); $count = $values->count(); if ($count === 0) { return; } $middle = (int) ($count / 2); if ($count % 2) { return $values->get($middle); } return (new static([ $values->get($middle - 1), $values->get($middle), ]))->average(); } /** * Get the mode of a given key. * * @param string|array|null $key * @return array|null */ public function mode($key = null) { if ($this->count() === 0) { return; } $collection = isset($key) ? $this->pluck($key) : $this; $counts = new static; $collection->each(fn ($value) => $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1); $sorted = $counts->sort(); $highestValue = $sorted->last(); return $sorted->filter(fn ($value) => $value == $highestValue) ->sort()->keys()->all(); } /** * Collapse the collection of items into a single array. * * @return static */ public function collapse() { return new static(Arr::collapse($this->items)); } /** * Determine if an item exists in the collection. * * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool */ public function contains($key, $operator = null, $value = null) { if (func_num_args() === 1) { if ($this->useAsCallable($key)) { $placeholder = new stdClass; return $this->first($key, $placeholder) !== $placeholder; } return in_array($key, $this->items); } return $this->contains($this->operatorForWhere(...func_get_args())); } /** * Determine if an item exists, using strict comparison. * * @param (callable(TValue): bool)|TValue|array-key $key * @param TValue|null $value * @return bool */ public function containsStrict($key, $value = null) { if (func_num_args() === 2) { return $this->contains(fn ($item) => data_get($item, $key) === $value); } if ($this->useAsCallable($key)) { return ! is_null($this->first($key)); } return in_array($key, $this->items, true); } /** * Determine if an item is not contained in the collection. * * @param mixed $key * @param mixed $operator * @param mixed $value * @return bool */ public function doesntContain($key, $operator = null, $value = null) { return ! $this->contains(...func_get_args()); } /** * Cross join with the given lists, returning all possible permutations. * * @template TCrossJoinKey * @template TCrossJoinValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$lists * @return static> */ public function crossJoin(...$lists) { return new static(Arr::crossJoin( $this->items, ...array_map([$this, 'getArrayableItems'], $lists) )); } /** * Get the items in the collection that are not present in the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function diff($items) { return new static(array_diff($this->items, $this->getArrayableItems($items))); } /** * Get the items in the collection that are not present in the given items, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TValue, TValue): int $callback * @return static */ public function diffUsing($items, callable $callback) { return new static(array_udiff($this->items, $this->getArrayableItems($items), $callback)); } /** * Get the items in the collection whose keys and values are not present in the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function diffAssoc($items) { return new static(array_diff_assoc($this->items, $this->getArrayableItems($items))); } /** * Get the items in the collection whose keys and values are not present in the given items, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TKey, TKey): int $callback * @return static */ public function diffAssocUsing($items, callable $callback) { return new static(array_diff_uassoc($this->items, $this->getArrayableItems($items), $callback)); } /** * Get the items in the collection whose keys are not present in the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function diffKeys($items) { return new static(array_diff_key($this->items, $this->getArrayableItems($items))); } /** * Get the items in the collection whose keys are not present in the given items, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TKey, TKey): int $callback * @return static */ public function diffKeysUsing($items, callable $callback) { return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback)); } /** * Retrieve duplicate items from the collection. * * @param (callable(TValue): bool)|string|null $callback * @param bool $strict * @return static */ public function duplicates($callback = null, $strict = false) { $items = $this->map($this->valueRetriever($callback)); $uniqueItems = $items->unique(null, $strict); $compare = $this->duplicateComparator($strict); $duplicates = new static; foreach ($items as $key => $value) { if ($uniqueItems->isNotEmpty() && $compare($value, $uniqueItems->first())) { $uniqueItems->shift(); } else { $duplicates[$key] = $value; } } return $duplicates; } /** * Retrieve duplicate items from the collection using strict comparison. * * @param (callable(TValue): bool)|string|null $callback * @return static */ public function duplicatesStrict($callback = null) { return $this->duplicates($callback, true); } /** * Get the comparison function to detect duplicates. * * @param bool $strict * @return callable(TValue, TValue): bool */ protected function duplicateComparator($strict) { if ($strict) { return fn ($a, $b) => $a === $b; } return fn ($a, $b) => $a == $b; } /** * Get all items except for those with the specified keys. * * @param \Illuminate\Support\Enumerable|array|string $keys * @return static */ public function except($keys) { if (is_null($keys)) { return new static($this->items); } if ($keys instanceof Enumerable) { $keys = $keys->all(); } elseif (! is_array($keys)) { $keys = func_get_args(); } return new static(Arr::except($this->items, $keys)); } /** * Run a filter over each of the items. * * @param (callable(TValue, TKey): bool)|null $callback * @return static */ public function filter(?callable $callback = null) { if ($callback) { return new static(Arr::where($this->items, $callback)); } return new static(array_filter($this->items)); } /** * Get the first item from the collection passing the given truth test. * * @template TFirstDefault * * @param (callable(TValue, TKey): bool)|null $callback * @param TFirstDefault|(\Closure(): TFirstDefault) $default * @return TValue|TFirstDefault */ public function first(?callable $callback = null, $default = null) { return Arr::first($this->items, $callback, $default); } /** * Get a flattened array of the items in the collection. * * @param int $depth * @return static */ public function flatten($depth = INF) { return new static(Arr::flatten($this->items, $depth)); } /** * Flip the items in the collection. * * @return static */ public function flip() { return new static(array_flip($this->items)); } /** * Remove an item from the collection by key. * * \Illuminate\Contracts\Support\Arrayable|iterable|TKey $keys * * @return $this */ public function forget($keys) { foreach ($this->getArrayableItems($keys) as $key) { $this->offsetUnset($key); } return $this; } /** * Get an item from the collection by key. * * @template TGetDefault * * @param TKey $key * @param TGetDefault|(\Closure(): TGetDefault) $default * @return TValue|TGetDefault */ public function get($key, $default = null) { if (array_key_exists($key, $this->items)) { return $this->items[$key]; } return value($default); } /** * Get an item from the collection by key or add it to collection if it does not exist. * * @template TGetOrPutValue * * @param mixed $key * @param TGetOrPutValue|(\Closure(): TGetOrPutValue) $value * @return TValue|TGetOrPutValue */ public function getOrPut($key, $value) { if (array_key_exists($key, $this->items)) { return $this->items[$key]; } $this->offsetSet($key, $value = value($value)); return $value; } /** * Group an associative array by a field or using a callback. * * @param (callable(TValue, TKey): array-key)|array|string $groupBy * @param bool $preserveKeys * @return static> */ public function groupBy($groupBy, $preserveKeys = false) { if (! $this->useAsCallable($groupBy) && is_array($groupBy)) { $nextGroups = $groupBy; $groupBy = array_shift($nextGroups); } $groupBy = $this->valueRetriever($groupBy); $results = []; foreach ($this->items as $key => $value) { $groupKeys = $groupBy($value, $key); if (! is_array($groupKeys)) { $groupKeys = [$groupKeys]; } foreach ($groupKeys as $groupKey) { $groupKey = match (true) { is_bool($groupKey) => (int) $groupKey, $groupKey instanceof \BackedEnum => $groupKey->value, $groupKey instanceof \Stringable => (string) $groupKey, default => $groupKey, }; if (! array_key_exists($groupKey, $results)) { $results[$groupKey] = new static; } $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value); } } $result = new static($results); if (! empty($nextGroups)) { return $result->map->groupBy($nextGroups, $preserveKeys); } return $result; } /** * Key an associative array by a field or using a callback. * * @param (callable(TValue, TKey): array-key)|array|string $keyBy * @return static */ public function keyBy($keyBy) { $keyBy = $this->valueRetriever($keyBy); $results = []; foreach ($this->items as $key => $item) { $resolvedKey = $keyBy($item, $key); if (is_object($resolvedKey)) { $resolvedKey = (string) $resolvedKey; } $results[$resolvedKey] = $item; } return new static($results); } /** * Determine if an item exists in the collection by key. * * @param TKey|array $key * @return bool */ public function has($key) { $keys = is_array($key) ? $key : func_get_args(); foreach ($keys as $value) { if (! array_key_exists($value, $this->items)) { return false; } } return true; } /** * Determine if any of the keys exist in the collection. * * @param mixed $key * @return bool */ public function hasAny($key) { if ($this->isEmpty()) { return false; } $keys = is_array($key) ? $key : func_get_args(); foreach ($keys as $value) { if ($this->has($value)) { return true; } } return false; } /** * Concatenate values of a given key as a string. * * @param callable|string $value * @param string|null $glue * @return string */ public function implode($value, $glue = null) { if ($this->useAsCallable($value)) { return implode($glue ?? '', $this->map($value)->all()); } $first = $this->first(); if (is_array($first) || (is_object($first) && ! $first instanceof Stringable)) { return implode($glue ?? '', $this->pluck($value)->all()); } return implode($value ?? '', $this->items); } /** * Intersect the collection with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function intersect($items) { return new static(array_intersect($this->items, $this->getArrayableItems($items))); } /** * Intersect the collection with the given items, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TValue, TValue): int $callback * @return static */ public function intersectUsing($items, callable $callback) { return new static(array_uintersect($this->items, $this->getArrayableItems($items), $callback)); } /** * Intersect the collection with the given items with additional index check. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function intersectAssoc($items) { return new static(array_intersect_assoc($this->items, $this->getArrayableItems($items))); } /** * Intersect the collection with the given items with additional index check, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TValue, TValue): int $callback * @return static */ public function intersectAssocUsing($items, callable $callback) { return new static(array_intersect_uassoc($this->items, $this->getArrayableItems($items), $callback)); } /** * Intersect the collection with the given items by key. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function intersectByKeys($items) { return new static(array_intersect_key( $this->items, $this->getArrayableItems($items) )); } /** * Determine if the collection is empty or not. * * @return bool */ public function isEmpty() { return empty($this->items); } /** * Determine if the collection contains a single item. * * @return bool */ public function containsOneItem() { return $this->count() === 1; } /** * Join all items from the collection using a string. The final items can use a separate glue string. * * @param string $glue * @param string $finalGlue * @return string */ public function join($glue, $finalGlue = '') { if ($finalGlue === '') { return $this->implode($glue); } $count = $this->count(); if ($count === 0) { return ''; } if ($count === 1) { return $this->last(); } $collection = new static($this->items); $finalItem = $collection->pop(); return $collection->implode($glue).$finalGlue.$finalItem; } /** * Get the keys of the collection items. * * @return static */ public function keys() { return new static(array_keys($this->items)); } /** * Get the last item from the collection. * * @template TLastDefault * * @param (callable(TValue, TKey): bool)|null $callback * @param TLastDefault|(\Closure(): TLastDefault) $default * @return TValue|TLastDefault */ public function last(?callable $callback = null, $default = null) { return Arr::last($this->items, $callback, $default); } /** * Get the values of a given key. * * @param string|int|array|null $value * @param string|null $key * @return static */ public function pluck($value, $key = null) { return new static(Arr::pluck($this->items, $value, $key)); } /** * Run a map over each of the items. * * @template TMapValue * * @param callable(TValue, TKey): TMapValue $callback * @return static */ public function map(callable $callback) { return new static(Arr::map($this->items, $callback)); } /** * Run a dictionary map over the items. * * The callback should return an associative array with a single key/value pair. * * @template TMapToDictionaryKey of array-key * @template TMapToDictionaryValue * * @param callable(TValue, TKey): array $callback * @return static> */ public function mapToDictionary(callable $callback) { $dictionary = []; foreach ($this->items as $key => $item) { $pair = $callback($item, $key); $key = key($pair); $value = reset($pair); if (! isset($dictionary[$key])) { $dictionary[$key] = []; } $dictionary[$key][] = $value; } return new static($dictionary); } /** * Run an associative map over each of the items. * * The callback should return an associative array with a single key/value pair. * * @template TMapWithKeysKey of array-key * @template TMapWithKeysValue * * @param callable(TValue, TKey): array $callback * @return static */ public function mapWithKeys(callable $callback) { return new static(Arr::mapWithKeys($this->items, $callback)); } /** * Merge the collection with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function merge($items) { return new static(array_merge($this->items, $this->getArrayableItems($items))); } /** * Recursively merge the collection with the given items. * * @template TMergeRecursiveValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function mergeRecursive($items) { return new static(array_merge_recursive($this->items, $this->getArrayableItems($items))); } /** * Create a collection by using this collection for keys and another for its values. * * @template TCombineValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @return static */ public function combine($values) { return new static(array_combine($this->all(), $this->getArrayableItems($values))); } /** * Union the collection with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function union($items) { return new static($this->items + $this->getArrayableItems($items)); } /** * Create a new collection consisting of every n-th element. * * @param int $step * @param int $offset * @return static */ public function nth($step, $offset = 0) { $new = []; $position = 0; foreach ($this->slice($offset)->items as $item) { if ($position % $step === 0) { $new[] = $item; } $position++; } return new static($new); } /** * Get the items with the specified keys. * * @param \Illuminate\Support\Enumerable|array|string|null $keys * @return static */ public function only($keys) { if (is_null($keys)) { return new static($this->items); } if ($keys instanceof Enumerable) { $keys = $keys->all(); } $keys = is_array($keys) ? $keys : func_get_args(); return new static(Arr::only($this->items, $keys)); } /** * Select specific values from the items within the collection. * * @param \Illuminate\Support\Enumerable|array|string|null $keys * @return static */ public function select($keys) { if (is_null($keys)) { return new static($this->items); } if ($keys instanceof Enumerable) { $keys = $keys->all(); } $keys = is_array($keys) ? $keys : func_get_args(); return new static(Arr::select($this->items, $keys)); } /** * Get and remove the last N items from the collection. * * @param int $count * @return static|TValue|null */ public function pop($count = 1) { if ($count === 1) { return array_pop($this->items); } if ($this->isEmpty()) { return new static; } $results = []; $collectionCount = $this->count(); foreach (range(1, min($count, $collectionCount)) as $item) { array_push($results, array_pop($this->items)); } return new static($results); } /** * Push an item onto the beginning of the collection. * * @param TValue $value * @param TKey $key * @return $this */ public function prepend($value, $key = null) { $this->items = Arr::prepend($this->items, ...func_get_args()); return $this; } /** * Push one or more items onto the end of the collection. * * @param TValue ...$values * @return $this */ public function push(...$values) { foreach ($values as $value) { $this->items[] = $value; } return $this; } /** * Push all of the given items onto the collection. * * @template TConcatKey of array-key * @template TConcatValue * * @param iterable $source * @return static */ public function concat($source) { $result = new static($this); foreach ($source as $item) { $result->push($item); } return $result; } /** * Get and remove an item from the collection. * * @template TPullDefault * * @param TKey $key * @param TPullDefault|(\Closure(): TPullDefault) $default * @return TValue|TPullDefault */ public function pull($key, $default = null) { return Arr::pull($this->items, $key, $default); } /** * Put an item in the collection by key. * * @param TKey $key * @param TValue $value * @return $this */ public function put($key, $value) { $this->offsetSet($key, $value); return $this; } /** * Get one or a specified number of items randomly from the collection. * * @param (callable(self): int)|int|null $number * @param bool $preserveKeys * @return static|TValue * * @throws \InvalidArgumentException */ public function random($number = null, $preserveKeys = false) { if (is_null($number)) { return Arr::random($this->items); } if (is_callable($number)) { return new static(Arr::random($this->items, $number($this), $preserveKeys)); } return new static(Arr::random($this->items, $number, $preserveKeys)); } /** * Replace the collection items with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function replace($items) { return new static(array_replace($this->items, $this->getArrayableItems($items))); } /** * Recursively replace the collection items with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function replaceRecursive($items) { return new static(array_replace_recursive($this->items, $this->getArrayableItems($items))); } /** * Reverse items order. * * @return static */ public function reverse() { return new static(array_reverse($this->items, true)); } /** * Search the collection for a given value and return the corresponding key if successful. * * @param TValue|(callable(TValue,TKey): bool) $value * @param bool $strict * @return TKey|false */ public function search($value, $strict = false) { if (! $this->useAsCallable($value)) { return array_search($value, $this->items, $strict); } foreach ($this->items as $key => $item) { if ($value($item, $key)) { return $key; } } return false; } /** * Get and remove the first N items from the collection. * * @param int $count * @return static|TValue|null */ public function shift($count = 1) { if ($count === 1) { return array_shift($this->items); } if ($this->isEmpty()) { return new static; } $results = []; $collectionCount = $this->count(); foreach (range(1, min($count, $collectionCount)) as $item) { array_push($results, array_shift($this->items)); } return new static($results); } /** * Shuffle the items in the collection. * * @return static */ public function shuffle() { return new static(Arr::shuffle($this->items)); } /** * Create chunks representing a "sliding window" view of the items in the collection. * * @param int $size * @param int $step * @return static */ public function sliding($size = 2, $step = 1) { $chunks = floor(($this->count() - $size) / $step) + 1; return static::times($chunks, fn ($number) => $this->slice(($number - 1) * $step, $size)); } /** * Skip the first {$count} items. * * @param int $count * @return static */ public function skip($count) { return $this->slice($count); } /** * Skip items in the collection until the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value * @return static */ public function skipUntil($value) { return new static($this->lazy()->skipUntil($value)->all()); } /** * Skip items in the collection while the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value * @return static */ public function skipWhile($value) { return new static($this->lazy()->skipWhile($value)->all()); } /** * Slice the underlying collection array. * * @param int $offset * @param int|null $length * @return static */ public function slice($offset, $length = null) { return new static(array_slice($this->items, $offset, $length, true)); } /** * Split a collection into a certain number of groups. * * @param int $numberOfGroups * @return static */ public function split($numberOfGroups) { if ($this->isEmpty()) { return new static; } $groups = new static; $groupSize = floor($this->count() / $numberOfGroups); $remain = $this->count() % $numberOfGroups; $start = 0; for ($i = 0; $i < $numberOfGroups; $i++) { $size = $groupSize; if ($i < $remain) { $size++; } if ($size) { $groups->push(new static(array_slice($this->items, $start, $size))); $start += $size; } } return $groups; } /** * Split a collection into a certain number of groups, and fill the first groups completely. * * @param int $numberOfGroups * @return static */ public function splitIn($numberOfGroups) { return $this->chunk(ceil($this->count() / $numberOfGroups)); } /** * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception. * * @param (callable(TValue, TKey): bool)|string $key * @param mixed $operator * @param mixed $value * @return TValue * * @throws \Illuminate\Support\ItemNotFoundException * @throws \Illuminate\Support\MultipleItemsFoundException */ public function sole($key = null, $operator = null, $value = null) { $filter = func_num_args() > 1 ? $this->operatorForWhere(...func_get_args()) : $key; $items = $this->unless($filter == null)->filter($filter); $count = $items->count(); if ($count === 0) { throw new ItemNotFoundException; } if ($count > 1) { throw new MultipleItemsFoundException($count); } return $items->first(); } /** * Get the first item in the collection but throw an exception if no matching items exist. * * @param (callable(TValue, TKey): bool)|string $key * @param mixed $operator * @param mixed $value * @return TValue * * @throws \Illuminate\Support\ItemNotFoundException */ public function firstOrFail($key = null, $operator = null, $value = null) { $filter = func_num_args() > 1 ? $this->operatorForWhere(...func_get_args()) : $key; $placeholder = new stdClass(); $item = $this->first($filter, $placeholder); if ($item === $placeholder) { throw new ItemNotFoundException; } return $item; } /** * Chunk the collection into chunks of the given size. * * @param int $size * @return static */ public function chunk($size) { if ($size <= 0) { return new static; } $chunks = []; foreach (array_chunk($this->items, $size, true) as $chunk) { $chunks[] = new static($chunk); } return new static($chunks); } /** * Chunk the collection into chunks with a callback. * * @param callable(TValue, TKey, static): bool $callback * @return static> */ public function chunkWhile(callable $callback) { return new static( $this->lazy()->chunkWhile($callback)->mapInto(static::class) ); } /** * Sort through each item with a callback. * * @param (callable(TValue, TValue): int)|null|int $callback * @return static */ public function sort($callback = null) { $items = $this->items; $callback && is_callable($callback) ? uasort($items, $callback) : asort($items, $callback ?? SORT_REGULAR); return new static($items); } /** * Sort items in descending order. * * @param int $options * @return static */ public function sortDesc($options = SORT_REGULAR) { $items = $this->items; arsort($items, $options); return new static($items); } /** * Sort the collection using the given callback. * * @param array|(callable(TValue, TKey): mixed)|string $callback * @param int $options * @param bool $descending * @return static */ public function sortBy($callback, $options = SORT_REGULAR, $descending = false) { if (is_array($callback) && ! is_callable($callback)) { return $this->sortByMany($callback, $options); } $results = []; $callback = $this->valueRetriever($callback); // First we will loop through the items and get the comparator from a callback // function which we were given. Then, we will sort the returned values and // grab all the corresponding values for the sorted keys from this array. foreach ($this->items as $key => $value) { $results[$key] = $callback($value, $key); } $descending ? arsort($results, $options) : asort($results, $options); // Once we have sorted all of the keys in the array, we will loop through them // and grab the corresponding model so we can set the underlying items list // to the sorted version. Then we'll just return the collection instance. foreach (array_keys($results) as $key) { $results[$key] = $this->items[$key]; } return new static($results); } /** * Sort the collection using multiple comparisons. * * @param array $comparisons * @param int $options * @return static */ protected function sortByMany(array $comparisons = [], int $options = SORT_REGULAR) { $items = $this->items; uasort($items, function ($a, $b) use ($comparisons, $options) { foreach ($comparisons as $comparison) { $comparison = Arr::wrap($comparison); $prop = $comparison[0]; $ascending = Arr::get($comparison, 1, true) === true || Arr::get($comparison, 1, true) === 'asc'; if (! is_string($prop) && is_callable($prop)) { $result = $prop($a, $b); } else { $values = [data_get($a, $prop), data_get($b, $prop)]; if (! $ascending) { $values = array_reverse($values); } if (($options & SORT_FLAG_CASE) === SORT_FLAG_CASE) { if (($options & SORT_NATURAL) === SORT_NATURAL) { $result = strnatcasecmp($values[0], $values[1]); } else { $result = strcasecmp($values[0], $values[1]); } } else { $result = match ($options) { SORT_NUMERIC => intval($values[0]) <=> intval($values[1]), SORT_STRING => strcmp($values[0], $values[1]), SORT_NATURAL => strnatcmp($values[0], $values[1]), SORT_LOCALE_STRING => strcoll($values[0], $values[1]), default => $values[0] <=> $values[1], }; } } if ($result === 0) { continue; } return $result; } }); return new static($items); } /** * Sort the collection in descending order using the given callback. * * @param array|(callable(TValue, TKey): mixed)|string $callback * @param int $options * @return static */ public function sortByDesc($callback, $options = SORT_REGULAR) { if (is_array($callback) && ! is_callable($callback)) { foreach ($callback as $index => $key) { $comparison = Arr::wrap($key); $comparison[1] = 'desc'; $callback[$index] = $comparison; } } return $this->sortBy($callback, $options, true); } /** * Sort the collection keys. * * @param int $options * @param bool $descending * @return static */ public function sortKeys($options = SORT_REGULAR, $descending = false) { $items = $this->items; $descending ? krsort($items, $options) : ksort($items, $options); return new static($items); } /** * Sort the collection keys in descending order. * * @param int $options * @return static */ public function sortKeysDesc($options = SORT_REGULAR) { return $this->sortKeys($options, true); } /** * Sort the collection keys using a callback. * * @param callable(TKey, TKey): int $callback * @return static */ public function sortKeysUsing(callable $callback) { $items = $this->items; uksort($items, $callback); return new static($items); } /** * Splice a portion of the underlying collection array. * * @param int $offset * @param int|null $length * @param array $replacement * @return static */ public function splice($offset, $length = null, $replacement = []) { if (func_num_args() === 1) { return new static(array_splice($this->items, $offset)); } return new static(array_splice($this->items, $offset, $length, $this->getArrayableItems($replacement))); } /** * Take the first or last {$limit} items. * * @param int $limit * @return static */ public function take($limit) { if ($limit < 0) { return $this->slice($limit, abs($limit)); } return $this->slice(0, $limit); } /** * Take items in the collection until the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value * @return static */ public function takeUntil($value) { return new static($this->lazy()->takeUntil($value)->all()); } /** * Take items in the collection while the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value * @return static */ public function takeWhile($value) { return new static($this->lazy()->takeWhile($value)->all()); } /** * Transform each item in the collection using a callback. * * @param callable(TValue, TKey): TValue $callback * @return $this */ public function transform(callable $callback) { $this->items = $this->map($callback)->all(); return $this; } /** * Flatten a multi-dimensional associative array with dots. * * @return static */ public function dot() { return new static(Arr::dot($this->all())); } /** * Convert a flatten "dot" notation array into an expanded array. * * @return static */ public function undot() { return new static(Arr::undot($this->all())); } /** * Return only unique items from the collection array. * * @param (callable(TValue, TKey): mixed)|string|null $key * @param bool $strict * @return static */ public function unique($key = null, $strict = false) { if (is_null($key) && $strict === false) { return new static(array_unique($this->items, SORT_REGULAR)); } $callback = $this->valueRetriever($key); $exists = []; return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) { if (in_array($id = $callback($item, $key), $exists, $strict)) { return true; } $exists[] = $id; }); } /** * Reset the keys on the underlying array. * * @return static */ public function values() { return new static(array_values($this->items)); } /** * Zip the collection together with one or more arrays. * * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]); * => [[1, 4], [2, 5], [3, 6]] * * @template TZipValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$items * @return static> */ public function zip($items) { $arrayableItems = array_map(fn ($items) => $this->getArrayableItems($items), func_get_args()); $params = array_merge([fn () => new static(func_get_args()), $this->items], $arrayableItems); return new static(array_map(...$params)); } /** * Pad collection to the specified length with a value. * * @template TPadValue * * @param int $size * @param TPadValue $value * @return static */ public function pad($size, $value) { return new static(array_pad($this->items, $size, $value)); } /** * Get an iterator for the items. * * @return \ArrayIterator */ public function getIterator(): Traversable { return new ArrayIterator($this->items); } /** * Count the number of items in the collection. * * @return int */ public function count(): int { return count($this->items); } /** * Count the number of items in the collection by a field or using a callback. * * @param (callable(TValue, TKey): array-key)|string|null $countBy * @return static */ public function countBy($countBy = null) { return new static($this->lazy()->countBy($countBy)->all()); } /** * Add an item to the collection. * * @param TValue $item * @return $this */ public function add($item) { $this->items[] = $item; return $this; } /** * Get a base Support collection instance from this collection. * * @return \Illuminate\Support\Collection */ public function toBase() { return new self($this); } /** * Determine if an item exists at an offset. * * @param TKey $key * @return bool */ public function offsetExists($key): bool { return isset($this->items[$key]); } /** * Get an item at a given offset. * * @param TKey $key * @return TValue */ public function offsetGet($key): mixed { return $this->items[$key]; } /** * Set the item at a given offset. * * @param TKey|null $key * @param TValue $value * @return void */ public function offsetSet($key, $value): void { if (is_null($key)) { $this->items[] = $value; } else { $this->items[$key] = $value; } } /** * Unset the item at a given offset. * * @param TKey $key * @return void */ public function offsetUnset($key): void { unset($this->items[$key]); } } Enumerable.php000064400000106707147536122360007360 0ustar00 * @extends \IteratorAggregate */ interface Enumerable extends Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable { /** * Create a new collection instance if the value isn't one already. * * @template TMakeKey of array-key * @template TMakeValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $items * @return static */ public static function make($items = []); /** * Create a new instance by invoking the callback a given amount of times. * * @param int $number * @param callable|null $callback * @return static */ public static function times($number, ?callable $callback = null); /** * Create a collection with the given range. * * @param int $from * @param int $to * @return static */ public static function range($from, $to); /** * Wrap the given value in a collection if applicable. * * @template TWrapValue * * @param iterable|TWrapValue $value * @return static */ public static function wrap($value); /** * Get the underlying items from the given collection if applicable. * * @template TUnwrapKey of array-key * @template TUnwrapValue * * @param array|static $value * @return array */ public static function unwrap($value); /** * Create a new instance with no items. * * @return static */ public static function empty(); /** * Get all items in the enumerable. * * @return array */ public function all(); /** * Alias for the "avg" method. * * @param (callable(TValue): float|int)|string|null $callback * @return float|int|null */ public function average($callback = null); /** * Get the median of a given key. * * @param string|array|null $key * @return float|int|null */ public function median($key = null); /** * Get the mode of a given key. * * @param string|array|null $key * @return array|null */ public function mode($key = null); /** * Collapse the items into a single enumerable. * * @return static */ public function collapse(); /** * Alias for the "contains" method. * * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool */ public function some($key, $operator = null, $value = null); /** * Determine if an item exists, using strict comparison. * * @param (callable(TValue): bool)|TValue|array-key $key * @param TValue|null $value * @return bool */ public function containsStrict($key, $value = null); /** * Get the average value of a given key. * * @param (callable(TValue): float|int)|string|null $callback * @return float|int|null */ public function avg($callback = null); /** * Determine if an item exists in the enumerable. * * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool */ public function contains($key, $operator = null, $value = null); /** * Determine if an item is not contained in the collection. * * @param mixed $key * @param mixed $operator * @param mixed $value * @return bool */ public function doesntContain($key, $operator = null, $value = null); /** * Cross join with the given lists, returning all possible permutations. * * @template TCrossJoinKey * @template TCrossJoinValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$lists * @return static> */ public function crossJoin(...$lists); /** * Dump the collection and end the script. * * @param mixed ...$args * @return never */ public function dd(...$args); /** * Dump the collection. * * @param mixed ...$args * @return $this */ public function dump(...$args); /** * Get the items that are not present in the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function diff($items); /** * Get the items that are not present in the given items, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TValue, TValue): int $callback * @return static */ public function diffUsing($items, callable $callback); /** * Get the items whose keys and values are not present in the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function diffAssoc($items); /** * Get the items whose keys and values are not present in the given items, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TKey, TKey): int $callback * @return static */ public function diffAssocUsing($items, callable $callback); /** * Get the items whose keys are not present in the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function diffKeys($items); /** * Get the items whose keys are not present in the given items, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TKey, TKey): int $callback * @return static */ public function diffKeysUsing($items, callable $callback); /** * Retrieve duplicate items. * * @param (callable(TValue): bool)|string|null $callback * @param bool $strict * @return static */ public function duplicates($callback = null, $strict = false); /** * Retrieve duplicate items using strict comparison. * * @param (callable(TValue): bool)|string|null $callback * @return static */ public function duplicatesStrict($callback = null); /** * Execute a callback over each item. * * @param callable(TValue, TKey): mixed $callback * @return $this */ public function each(callable $callback); /** * Execute a callback over each nested chunk of items. * * @param callable $callback * @return static */ public function eachSpread(callable $callback); /** * Determine if all items pass the given truth test. * * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool */ public function every($key, $operator = null, $value = null); /** * Get all items except for those with the specified keys. * * @param \Illuminate\Support\Enumerable|array $keys * @return static */ public function except($keys); /** * Run a filter over each of the items. * * @param (callable(TValue): bool)|null $callback * @return static */ public function filter(?callable $callback = null); /** * Apply the callback if the given "value" is (or resolves to) truthy. * * @template TWhenReturnType as null * * @param bool $value * @param (callable($this): TWhenReturnType)|null $callback * @param (callable($this): TWhenReturnType)|null $default * @return $this|TWhenReturnType */ public function when($value, ?callable $callback = null, ?callable $default = null); /** * Apply the callback if the collection is empty. * * @template TWhenEmptyReturnType * * @param (callable($this): TWhenEmptyReturnType) $callback * @param (callable($this): TWhenEmptyReturnType)|null $default * @return $this|TWhenEmptyReturnType */ public function whenEmpty(callable $callback, ?callable $default = null); /** * Apply the callback if the collection is not empty. * * @template TWhenNotEmptyReturnType * * @param callable($this): TWhenNotEmptyReturnType $callback * @param (callable($this): TWhenNotEmptyReturnType)|null $default * @return $this|TWhenNotEmptyReturnType */ public function whenNotEmpty(callable $callback, ?callable $default = null); /** * Apply the callback if the given "value" is (or resolves to) truthy. * * @template TUnlessReturnType * * @param bool $value * @param (callable($this): TUnlessReturnType) $callback * @param (callable($this): TUnlessReturnType)|null $default * @return $this|TUnlessReturnType */ public function unless($value, callable $callback, ?callable $default = null); /** * Apply the callback unless the collection is empty. * * @template TUnlessEmptyReturnType * * @param callable($this): TUnlessEmptyReturnType $callback * @param (callable($this): TUnlessEmptyReturnType)|null $default * @return $this|TUnlessEmptyReturnType */ public function unlessEmpty(callable $callback, ?callable $default = null); /** * Apply the callback unless the collection is not empty. * * @template TUnlessNotEmptyReturnType * * @param callable($this): TUnlessNotEmptyReturnType $callback * @param (callable($this): TUnlessNotEmptyReturnType)|null $default * @return $this|TUnlessNotEmptyReturnType */ public function unlessNotEmpty(callable $callback, ?callable $default = null); /** * Filter items by the given key value pair. * * @param string $key * @param mixed $operator * @param mixed $value * @return static */ public function where($key, $operator = null, $value = null); /** * Filter items where the value for the given key is null. * * @param string|null $key * @return static */ public function whereNull($key = null); /** * Filter items where the value for the given key is not null. * * @param string|null $key * @return static */ public function whereNotNull($key = null); /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param mixed $value * @return static */ public function whereStrict($key, $value); /** * Filter items by the given key value pair. * * @param string $key * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @param bool $strict * @return static */ public function whereIn($key, $values, $strict = false); /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @return static */ public function whereInStrict($key, $values); /** * Filter items such that the value of the given key is between the given values. * * @param string $key * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @return static */ public function whereBetween($key, $values); /** * Filter items such that the value of the given key is not between the given values. * * @param string $key * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @return static */ public function whereNotBetween($key, $values); /** * Filter items by the given key value pair. * * @param string $key * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @param bool $strict * @return static */ public function whereNotIn($key, $values, $strict = false); /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @return static */ public function whereNotInStrict($key, $values); /** * Filter the items, removing any items that don't match the given type(s). * * @template TWhereInstanceOf * * @param class-string|array> $type * @return static */ public function whereInstanceOf($type); /** * Get the first item from the enumerable passing the given truth test. * * @template TFirstDefault * * @param (callable(TValue,TKey): bool)|null $callback * @param TFirstDefault|(\Closure(): TFirstDefault) $default * @return TValue|TFirstDefault */ public function first(?callable $callback = null, $default = null); /** * Get the first item by the given key value pair. * * @param string $key * @param mixed $operator * @param mixed $value * @return TValue|null */ public function firstWhere($key, $operator = null, $value = null); /** * Get a flattened array of the items in the collection. * * @param int $depth * @return static */ public function flatten($depth = INF); /** * Flip the values with their keys. * * @return static */ public function flip(); /** * Get an item from the collection by key. * * @template TGetDefault * * @param TKey $key * @param TGetDefault|(\Closure(): TGetDefault) $default * @return TValue|TGetDefault */ public function get($key, $default = null); /** * Group an associative array by a field or using a callback. * * @param (callable(TValue, TKey): array-key)|array|string $groupBy * @param bool $preserveKeys * @return static> */ public function groupBy($groupBy, $preserveKeys = false); /** * Key an associative array by a field or using a callback. * * @param (callable(TValue, TKey): array-key)|array|string $keyBy * @return static */ public function keyBy($keyBy); /** * Determine if an item exists in the collection by key. * * @param TKey|array $key * @return bool */ public function has($key); /** * Determine if any of the keys exist in the collection. * * @param mixed $key * @return bool */ public function hasAny($key); /** * Concatenate values of a given key as a string. * * @param callable|string $value * @param string|null $glue * @return string */ public function implode($value, $glue = null); /** * Intersect the collection with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function intersect($items); /** * Intersect the collection with the given items, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TValue, TValue): int $callback * @return static */ public function intersectUsing($items, callable $callback); /** * Intersect the collection with the given items with additional index check. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function intersectAssoc($items); /** * Intersect the collection with the given items with additional index check, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TValue, TValue): int $callback * @return static */ public function intersectAssocUsing($items, callable $callback); /** * Intersect the collection with the given items by key. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function intersectByKeys($items); /** * Determine if the collection is empty or not. * * @return bool */ public function isEmpty(); /** * Determine if the collection is not empty. * * @return bool */ public function isNotEmpty(); /** * Determine if the collection contains a single item. * * @return bool */ public function containsOneItem(); /** * Join all items from the collection using a string. The final items can use a separate glue string. * * @param string $glue * @param string $finalGlue * @return string */ public function join($glue, $finalGlue = ''); /** * Get the keys of the collection items. * * @return static */ public function keys(); /** * Get the last item from the collection. * * @template TLastDefault * * @param (callable(TValue, TKey): bool)|null $callback * @param TLastDefault|(\Closure(): TLastDefault) $default * @return TValue|TLastDefault */ public function last(?callable $callback = null, $default = null); /** * Run a map over each of the items. * * @template TMapValue * * @param callable(TValue, TKey): TMapValue $callback * @return static */ public function map(callable $callback); /** * Run a map over each nested chunk of items. * * @param callable $callback * @return static */ public function mapSpread(callable $callback); /** * Run a dictionary map over the items. * * The callback should return an associative array with a single key/value pair. * * @template TMapToDictionaryKey of array-key * @template TMapToDictionaryValue * * @param callable(TValue, TKey): array $callback * @return static> */ public function mapToDictionary(callable $callback); /** * Run a grouping map over the items. * * The callback should return an associative array with a single key/value pair. * * @template TMapToGroupsKey of array-key * @template TMapToGroupsValue * * @param callable(TValue, TKey): array $callback * @return static> */ public function mapToGroups(callable $callback); /** * Run an associative map over each of the items. * * The callback should return an associative array with a single key/value pair. * * @template TMapWithKeysKey of array-key * @template TMapWithKeysValue * * @param callable(TValue, TKey): array $callback * @return static */ public function mapWithKeys(callable $callback); /** * Map a collection and flatten the result by a single level. * * @template TFlatMapKey of array-key * @template TFlatMapValue * * @param callable(TValue, TKey): (\Illuminate\Support\Collection|array) $callback * @return static */ public function flatMap(callable $callback); /** * Map the values into a new class. * * @template TMapIntoValue * * @param class-string $class * @return static */ public function mapInto($class); /** * Merge the collection with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function merge($items); /** * Recursively merge the collection with the given items. * * @template TMergeRecursiveValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function mergeRecursive($items); /** * Create a collection by using this collection for keys and another for its values. * * @template TCombineValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @return static */ public function combine($values); /** * Union the collection with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function union($items); /** * Get the min value of a given key. * * @param (callable(TValue):mixed)|string|null $callback * @return mixed */ public function min($callback = null); /** * Get the max value of a given key. * * @param (callable(TValue):mixed)|string|null $callback * @return mixed */ public function max($callback = null); /** * Create a new collection consisting of every n-th element. * * @param int $step * @param int $offset * @return static */ public function nth($step, $offset = 0); /** * Get the items with the specified keys. * * @param \Illuminate\Support\Enumerable|array|string $keys * @return static */ public function only($keys); /** * "Paginate" the collection by slicing it into a smaller collection. * * @param int $page * @param int $perPage * @return static */ public function forPage($page, $perPage); /** * Partition the collection into two arrays using the given callback or key. * * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return static, static> */ public function partition($key, $operator = null, $value = null); /** * Push all of the given items onto the collection. * * @template TConcatKey of array-key * @template TConcatValue * * @param iterable $source * @return static */ public function concat($source); /** * Get one or a specified number of items randomly from the collection. * * @param int|null $number * @return static|TValue * * @throws \InvalidArgumentException */ public function random($number = null); /** * Reduce the collection to a single value. * * @template TReduceInitial * @template TReduceReturnType * * @param callable(TReduceInitial|TReduceReturnType, TValue, TKey): TReduceReturnType $callback * @param TReduceInitial $initial * @return TReduceReturnType */ public function reduce(callable $callback, $initial = null); /** * Reduce the collection to multiple aggregate values. * * @param callable $callback * @param mixed ...$initial * @return array * * @throws \UnexpectedValueException */ public function reduceSpread(callable $callback, ...$initial); /** * Replace the collection items with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function replace($items); /** * Recursively replace the collection items with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function replaceRecursive($items); /** * Reverse items order. * * @return static */ public function reverse(); /** * Search the collection for a given value and return the corresponding key if successful. * * @param TValue|callable(TValue,TKey): bool $value * @param bool $strict * @return TKey|bool */ public function search($value, $strict = false); /** * Shuffle the items in the collection. * * @return static */ public function shuffle(); /** * Create chunks representing a "sliding window" view of the items in the collection. * * @param int $size * @param int $step * @return static */ public function sliding($size = 2, $step = 1); /** * Skip the first {$count} items. * * @param int $count * @return static */ public function skip($count); /** * Skip items in the collection until the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value * @return static */ public function skipUntil($value); /** * Skip items in the collection while the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value * @return static */ public function skipWhile($value); /** * Get a slice of items from the enumerable. * * @param int $offset * @param int|null $length * @return static */ public function slice($offset, $length = null); /** * Split a collection into a certain number of groups. * * @param int $numberOfGroups * @return static */ public function split($numberOfGroups); /** * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception. * * @param (callable(TValue, TKey): bool)|string $key * @param mixed $operator * @param mixed $value * @return TValue * * @throws \Illuminate\Support\ItemNotFoundException * @throws \Illuminate\Support\MultipleItemsFoundException */ public function sole($key = null, $operator = null, $value = null); /** * Get the first item in the collection but throw an exception if no matching items exist. * * @param (callable(TValue, TKey): bool)|string $key * @param mixed $operator * @param mixed $value * @return TValue * * @throws \Illuminate\Support\ItemNotFoundException */ public function firstOrFail($key = null, $operator = null, $value = null); /** * Chunk the collection into chunks of the given size. * * @param int $size * @return static */ public function chunk($size); /** * Chunk the collection into chunks with a callback. * * @param callable(TValue, TKey, static): bool $callback * @return static> */ public function chunkWhile(callable $callback); /** * Split a collection into a certain number of groups, and fill the first groups completely. * * @param int $numberOfGroups * @return static */ public function splitIn($numberOfGroups); /** * Sort through each item with a callback. * * @param (callable(TValue, TValue): int)|null|int $callback * @return static */ public function sort($callback = null); /** * Sort items in descending order. * * @param int $options * @return static */ public function sortDesc($options = SORT_REGULAR); /** * Sort the collection using the given callback. * * @param array|(callable(TValue, TKey): mixed)|string $callback * @param int $options * @param bool $descending * @return static */ public function sortBy($callback, $options = SORT_REGULAR, $descending = false); /** * Sort the collection in descending order using the given callback. * * @param array|(callable(TValue, TKey): mixed)|string $callback * @param int $options * @return static */ public function sortByDesc($callback, $options = SORT_REGULAR); /** * Sort the collection keys. * * @param int $options * @param bool $descending * @return static */ public function sortKeys($options = SORT_REGULAR, $descending = false); /** * Sort the collection keys in descending order. * * @param int $options * @return static */ public function sortKeysDesc($options = SORT_REGULAR); /** * Sort the collection keys using a callback. * * @param callable(TKey, TKey): int $callback * @return static */ public function sortKeysUsing(callable $callback); /** * Get the sum of the given values. * * @param (callable(TValue): mixed)|string|null $callback * @return mixed */ public function sum($callback = null); /** * Take the first or last {$limit} items. * * @param int $limit * @return static */ public function take($limit); /** * Take items in the collection until the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value * @return static */ public function takeUntil($value); /** * Take items in the collection while the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value * @return static */ public function takeWhile($value); /** * Pass the collection to the given callback and then return it. * * @param callable(TValue): mixed $callback * @return $this */ public function tap(callable $callback); /** * Pass the enumerable to the given callback and return the result. * * @template TPipeReturnType * * @param callable($this): TPipeReturnType $callback * @return TPipeReturnType */ public function pipe(callable $callback); /** * Pass the collection into a new class. * * @template TPipeIntoValue * * @param class-string $class * @return TPipeIntoValue */ public function pipeInto($class); /** * Pass the collection through a series of callable pipes and return the result. * * @param array $pipes * @return mixed */ public function pipeThrough($pipes); /** * Get the values of a given key. * * @param string|array $value * @param string|null $key * @return static */ public function pluck($value, $key = null); /** * Create a collection of all elements that do not pass a given truth test. * * @param (callable(TValue, TKey): bool)|bool|TValue $callback * @return static */ public function reject($callback = true); /** * Convert a flatten "dot" notation array into an expanded array. * * @return static */ public function undot(); /** * Return only unique items from the collection array. * * @param (callable(TValue, TKey): mixed)|string|null $key * @param bool $strict * @return static */ public function unique($key = null, $strict = false); /** * Return only unique items from the collection array using strict comparison. * * @param (callable(TValue, TKey): mixed)|string|null $key * @return static */ public function uniqueStrict($key = null); /** * Reset the keys on the underlying array. * * @return static */ public function values(); /** * Pad collection to the specified length with a value. * * @template TPadValue * * @param int $size * @param TPadValue $value * @return static */ public function pad($size, $value); /** * Get the values iterator. * * @return \Traversable */ public function getIterator(): Traversable; /** * Count the number of items in the collection. * * @return int */ public function count(): int; /** * Count the number of items in the collection by a field or using a callback. * * @param (callable(TValue, TKey): array-key)|string|null $countBy * @return static */ public function countBy($countBy = null); /** * Zip the collection together with one or more arrays. * * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]); * => [[1, 4], [2, 5], [3, 6]] * * @template TZipValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$items * @return static> */ public function zip($items); /** * Collect the values into a collection. * * @return \Illuminate\Support\Collection */ public function collect(); /** * Get the collection of items as a plain array. * * @return array */ public function toArray(); /** * Convert the object into something JSON serializable. * * @return mixed */ public function jsonSerialize(): mixed; /** * Get the collection of items as JSON. * * @param int $options * @return string */ public function toJson($options = 0); /** * Get a CachingIterator instance. * * @param int $flags * @return \CachingIterator */ public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING); /** * Convert the collection to its string representation. * * @return string */ public function __toString(); /** * Indicate that the model's string representation should be escaped when __toString is invoked. * * @param bool $escape * @return $this */ public function escapeWhenCastingToString($escape = true); /** * Add a method to the list of proxied methods. * * @param string $method * @return void */ public static function proxy($method); /** * Dynamically access collection proxies. * * @param string $key * @return mixed * * @throws \Exception */ public function __get($key); } HigherOrderCollectionProxy.php000064400000002600147536122360012544 0ustar00method = $method; $this->collection = $collection; } /** * Proxy accessing an attribute onto the collection items. * * @param string $key * @return mixed */ public function __get($key) { return $this->collection->{$this->method}(function ($value) use ($key) { return is_array($value) ? $value[$key] : $value->{$key}; }); } /** * Proxy a method call onto the collection items. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { return $this->collection->{$this->method}(function ($value) use ($method, $parameters) { return $value->{$method}(...$parameters); }); } } ItemNotFoundException.php000064400000000166147536122360011523 0ustar00 */ class LazyCollection implements CanBeEscapedWhenCastToString, Enumerable { /** * @use \Illuminate\Support\Traits\EnumeratesValues */ use EnumeratesValues, Macroable; /** * The source from which to generate items. * * @var (Closure(): \Generator)|static|array */ public $source; /** * Create a new lazy collection instance. * * @param \Illuminate\Contracts\Support\Arrayable|iterable|(Closure(): \Generator)|self|array|null $source * @return void */ public function __construct($source = null) { if ($source instanceof Closure || $source instanceof self) { $this->source = $source; } elseif (is_null($source)) { $this->source = static::empty(); } elseif ($source instanceof Generator) { throw new InvalidArgumentException( 'Generators should not be passed directly to LazyCollection. Instead, pass a generator function.' ); } else { $this->source = $this->getArrayableItems($source); } } /** * Create a new collection instance if the value isn't one already. * * @template TMakeKey of array-key * @template TMakeValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable|(Closure(): \Generator)|self|array|null $items * @return static */ public static function make($items = []) { return new static($items); } /** * Create a collection with the given range. * * @param int $from * @param int $to * @return static */ public static function range($from, $to) { return new static(function () use ($from, $to) { if ($from <= $to) { for (; $from <= $to; $from++) { yield $from; } } else { for (; $from >= $to; $from--) { yield $from; } } }); } /** * Get all items in the enumerable. * * @return array */ public function all() { if (is_array($this->source)) { return $this->source; } return iterator_to_array($this->getIterator()); } /** * Eager load all items into a new lazy collection backed by an array. * * @return static */ public function eager() { return new static($this->all()); } /** * Cache values as they're enumerated. * * @return static */ public function remember() { $iterator = $this->getIterator(); $iteratorIndex = 0; $cache = []; return new static(function () use ($iterator, &$iteratorIndex, &$cache) { for ($index = 0; true; $index++) { if (array_key_exists($index, $cache)) { yield $cache[$index][0] => $cache[$index][1]; continue; } if ($iteratorIndex < $index) { $iterator->next(); $iteratorIndex++; } if (! $iterator->valid()) { break; } $cache[$index] = [$iterator->key(), $iterator->current()]; yield $cache[$index][0] => $cache[$index][1]; } }); } /** * Get the average value of a given key. * * @param (callable(TValue): float|int)|string|null $callback * @return float|int|null */ public function avg($callback = null) { return $this->collect()->avg($callback); } /** * Get the median of a given key. * * @param string|array|null $key * @return float|int|null */ public function median($key = null) { return $this->collect()->median($key); } /** * Get the mode of a given key. * * @param string|array|null $key * @return array|null */ public function mode($key = null) { return $this->collect()->mode($key); } /** * Collapse the collection of items into a single array. * * @return static */ public function collapse() { return new static(function () { foreach ($this as $values) { if (is_array($values) || $values instanceof Enumerable) { foreach ($values as $value) { yield $value; } } } }); } /** * Determine if an item exists in the enumerable. * * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool */ public function contains($key, $operator = null, $value = null) { if (func_num_args() === 1 && $this->useAsCallable($key)) { $placeholder = new stdClass; /** @var callable $key */ return $this->first($key, $placeholder) !== $placeholder; } if (func_num_args() === 1) { $needle = $key; foreach ($this as $value) { if ($value == $needle) { return true; } } return false; } return $this->contains($this->operatorForWhere(...func_get_args())); } /** * Determine if an item exists, using strict comparison. * * @param (callable(TValue): bool)|TValue|array-key $key * @param TValue|null $value * @return bool */ public function containsStrict($key, $value = null) { if (func_num_args() === 2) { return $this->contains(fn ($item) => data_get($item, $key) === $value); } if ($this->useAsCallable($key)) { return ! is_null($this->first($key)); } foreach ($this as $item) { if ($item === $key) { return true; } } return false; } /** * Determine if an item is not contained in the enumerable. * * @param mixed $key * @param mixed $operator * @param mixed $value * @return bool */ public function doesntContain($key, $operator = null, $value = null) { return ! $this->contains(...func_get_args()); } /** * Cross join the given iterables, returning all possible permutations. * * @template TCrossJoinKey * @template TCrossJoinValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$arrays * @return static> */ public function crossJoin(...$arrays) { return $this->passthru('crossJoin', func_get_args()); } /** * Count the number of items in the collection by a field or using a callback. * * @param (callable(TValue, TKey): array-key)|string|null $countBy * @return static */ public function countBy($countBy = null) { $countBy = is_null($countBy) ? $this->identity() : $this->valueRetriever($countBy); return new static(function () use ($countBy) { $counts = []; foreach ($this as $key => $value) { $group = $countBy($value, $key); if (empty($counts[$group])) { $counts[$group] = 0; } $counts[$group]++; } yield from $counts; }); } /** * Get the items that are not present in the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function diff($items) { return $this->passthru('diff', func_get_args()); } /** * Get the items that are not present in the given items, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TValue, TValue): int $callback * @return static */ public function diffUsing($items, callable $callback) { return $this->passthru('diffUsing', func_get_args()); } /** * Get the items whose keys and values are not present in the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function diffAssoc($items) { return $this->passthru('diffAssoc', func_get_args()); } /** * Get the items whose keys and values are not present in the given items, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TKey, TKey): int $callback * @return static */ public function diffAssocUsing($items, callable $callback) { return $this->passthru('diffAssocUsing', func_get_args()); } /** * Get the items whose keys are not present in the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function diffKeys($items) { return $this->passthru('diffKeys', func_get_args()); } /** * Get the items whose keys are not present in the given items, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TKey, TKey): int $callback * @return static */ public function diffKeysUsing($items, callable $callback) { return $this->passthru('diffKeysUsing', func_get_args()); } /** * Retrieve duplicate items. * * @param (callable(TValue): bool)|string|null $callback * @param bool $strict * @return static */ public function duplicates($callback = null, $strict = false) { return $this->passthru('duplicates', func_get_args()); } /** * Retrieve duplicate items using strict comparison. * * @param (callable(TValue): bool)|string|null $callback * @return static */ public function duplicatesStrict($callback = null) { return $this->passthru('duplicatesStrict', func_get_args()); } /** * Get all items except for those with the specified keys. * * @param \Illuminate\Support\Enumerable|array $keys * @return static */ public function except($keys) { return $this->passthru('except', func_get_args()); } /** * Run a filter over each of the items. * * @param (callable(TValue, TKey): bool)|null $callback * @return static */ public function filter(?callable $callback = null) { if (is_null($callback)) { $callback = fn ($value) => (bool) $value; } return new static(function () use ($callback) { foreach ($this as $key => $value) { if ($callback($value, $key)) { yield $key => $value; } } }); } /** * Get the first item from the enumerable passing the given truth test. * * @template TFirstDefault * * @param (callable(TValue): bool)|null $callback * @param TFirstDefault|(\Closure(): TFirstDefault) $default * @return TValue|TFirstDefault */ public function first(?callable $callback = null, $default = null) { $iterator = $this->getIterator(); if (is_null($callback)) { if (! $iterator->valid()) { return value($default); } return $iterator->current(); } foreach ($iterator as $key => $value) { if ($callback($value, $key)) { return $value; } } return value($default); } /** * Get a flattened list of the items in the collection. * * @param int $depth * @return static */ public function flatten($depth = INF) { $instance = new static(function () use ($depth) { foreach ($this as $item) { if (! is_array($item) && ! $item instanceof Enumerable) { yield $item; } elseif ($depth === 1) { yield from $item; } else { yield from (new static($item))->flatten($depth - 1); } } }); return $instance->values(); } /** * Flip the items in the collection. * * @return static */ public function flip() { return new static(function () { foreach ($this as $key => $value) { yield $value => $key; } }); } /** * Get an item by key. * * @template TGetDefault * * @param TKey|null $key * @param TGetDefault|(\Closure(): TGetDefault) $default * @return TValue|TGetDefault */ public function get($key, $default = null) { if (is_null($key)) { return; } foreach ($this as $outerKey => $outerValue) { if ($outerKey == $key) { return $outerValue; } } return value($default); } /** * Group an associative array by a field or using a callback. * * @param (callable(TValue, TKey): array-key)|array|string $groupBy * @param bool $preserveKeys * @return static> */ public function groupBy($groupBy, $preserveKeys = false) { return $this->passthru('groupBy', func_get_args()); } /** * Key an associative array by a field or using a callback. * * @param (callable(TValue, TKey): array-key)|array|string $keyBy * @return static */ public function keyBy($keyBy) { return new static(function () use ($keyBy) { $keyBy = $this->valueRetriever($keyBy); foreach ($this as $key => $item) { $resolvedKey = $keyBy($item, $key); if (is_object($resolvedKey)) { $resolvedKey = (string) $resolvedKey; } yield $resolvedKey => $item; } }); } /** * Determine if an item exists in the collection by key. * * @param mixed $key * @return bool */ public function has($key) { $keys = array_flip(is_array($key) ? $key : func_get_args()); $count = count($keys); foreach ($this as $key => $value) { if (array_key_exists($key, $keys) && --$count == 0) { return true; } } return false; } /** * Determine if any of the keys exist in the collection. * * @param mixed $key * @return bool */ public function hasAny($key) { $keys = array_flip(is_array($key) ? $key : func_get_args()); foreach ($this as $key => $value) { if (array_key_exists($key, $keys)) { return true; } } return false; } /** * Concatenate values of a given key as a string. * * @param callable|string $value * @param string|null $glue * @return string */ public function implode($value, $glue = null) { return $this->collect()->implode(...func_get_args()); } /** * Intersect the collection with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function intersect($items) { return $this->passthru('intersect', func_get_args()); } /** * Intersect the collection with the given items, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TValue, TValue): int $callback * @return static */ public function intersectUsing($items, callable $callback) { return $this->passthru('intersectUsing', func_get_args()); } /** * Intersect the collection with the given items with additional index check. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function intersectAssoc($items) { return $this->passthru('intersectAssoc', func_get_args()); } /** * Intersect the collection with the given items with additional index check, using the callback. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @param callable(TValue, TValue): int $callback * @return static */ public function intersectAssocUsing($items, callable $callback) { return $this->passthru('intersectAssocUsing', func_get_args()); } /** * Intersect the collection with the given items by key. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function intersectByKeys($items) { return $this->passthru('intersectByKeys', func_get_args()); } /** * Determine if the items are empty or not. * * @return bool */ public function isEmpty() { return ! $this->getIterator()->valid(); } /** * Determine if the collection contains a single item. * * @return bool */ public function containsOneItem() { return $this->take(2)->count() === 1; } /** * Join all items from the collection using a string. The final items can use a separate glue string. * * @param string $glue * @param string $finalGlue * @return string */ public function join($glue, $finalGlue = '') { return $this->collect()->join(...func_get_args()); } /** * Get the keys of the collection items. * * @return static */ public function keys() { return new static(function () { foreach ($this as $key => $value) { yield $key; } }); } /** * Get the last item from the collection. * * @template TLastDefault * * @param (callable(TValue, TKey): bool)|null $callback * @param TLastDefault|(\Closure(): TLastDefault) $default * @return TValue|TLastDefault */ public function last(?callable $callback = null, $default = null) { $needle = $placeholder = new stdClass; foreach ($this as $key => $value) { if (is_null($callback) || $callback($value, $key)) { $needle = $value; } } return $needle === $placeholder ? value($default) : $needle; } /** * Get the values of a given key. * * @param string|array $value * @param string|null $key * @return static */ public function pluck($value, $key = null) { return new static(function () use ($value, $key) { [$value, $key] = $this->explodePluckParameters($value, $key); foreach ($this as $item) { $itemValue = data_get($item, $value); if (is_null($key)) { yield $itemValue; } else { $itemKey = data_get($item, $key); if (is_object($itemKey) && method_exists($itemKey, '__toString')) { $itemKey = (string) $itemKey; } yield $itemKey => $itemValue; } } }); } /** * Run a map over each of the items. * * @template TMapValue * * @param callable(TValue, TKey): TMapValue $callback * @return static */ public function map(callable $callback) { return new static(function () use ($callback) { foreach ($this as $key => $value) { yield $key => $callback($value, $key); } }); } /** * Run a dictionary map over the items. * * The callback should return an associative array with a single key/value pair. * * @template TMapToDictionaryKey of array-key * @template TMapToDictionaryValue * * @param callable(TValue, TKey): array $callback * @return static> */ public function mapToDictionary(callable $callback) { return $this->passthru('mapToDictionary', func_get_args()); } /** * Run an associative map over each of the items. * * The callback should return an associative array with a single key/value pair. * * @template TMapWithKeysKey of array-key * @template TMapWithKeysValue * * @param callable(TValue, TKey): array $callback * @return static */ public function mapWithKeys(callable $callback) { return new static(function () use ($callback) { foreach ($this as $key => $value) { yield from $callback($value, $key); } }); } /** * Merge the collection with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function merge($items) { return $this->passthru('merge', func_get_args()); } /** * Recursively merge the collection with the given items. * * @template TMergeRecursiveValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function mergeRecursive($items) { return $this->passthru('mergeRecursive', func_get_args()); } /** * Create a collection by using this collection for keys and another for its values. * * @template TCombineValue * * @param \IteratorAggregate|array|(callable(): \Generator) $values * @return static */ public function combine($values) { return new static(function () use ($values) { $values = $this->makeIterator($values); $errorMessage = 'Both parameters should have an equal number of elements'; foreach ($this as $key) { if (! $values->valid()) { trigger_error($errorMessage, E_USER_WARNING); break; } yield $key => $values->current(); $values->next(); } if ($values->valid()) { trigger_error($errorMessage, E_USER_WARNING); } }); } /** * Union the collection with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function union($items) { return $this->passthru('union', func_get_args()); } /** * Create a new collection consisting of every n-th element. * * @param int $step * @param int $offset * @return static */ public function nth($step, $offset = 0) { return new static(function () use ($step, $offset) { $position = 0; foreach ($this->slice($offset) as $item) { if ($position % $step === 0) { yield $item; } $position++; } }); } /** * Get the items with the specified keys. * * @param \Illuminate\Support\Enumerable|array|string $keys * @return static */ public function only($keys) { if ($keys instanceof Enumerable) { $keys = $keys->all(); } elseif (! is_null($keys)) { $keys = is_array($keys) ? $keys : func_get_args(); } return new static(function () use ($keys) { if (is_null($keys)) { yield from $this; } else { $keys = array_flip($keys); foreach ($this as $key => $value) { if (array_key_exists($key, $keys)) { yield $key => $value; unset($keys[$key]); if (empty($keys)) { break; } } } } }); } /** * Select specific values from the items within the collection. * * @param \Illuminate\Support\Enumerable|array|string $keys * @return static */ public function select($keys) { if ($keys instanceof Enumerable) { $keys = $keys->all(); } elseif (! is_null($keys)) { $keys = is_array($keys) ? $keys : func_get_args(); } return new static(function () use ($keys) { if (is_null($keys)) { yield from $this; } else { foreach ($this as $item) { $result = []; foreach ($keys as $key) { if (Arr::accessible($item) && Arr::exists($item, $key)) { $result[$key] = $item[$key]; } elseif (is_object($item) && isset($item->{$key})) { $result[$key] = $item->{$key}; } } yield $result; } } }); } /** * Push all of the given items onto the collection. * * @template TConcatKey of array-key * @template TConcatValue * * @param iterable $source * @return static */ public function concat($source) { return (new static(function () use ($source) { yield from $this; yield from $source; }))->values(); } /** * Get one or a specified number of items randomly from the collection. * * @param int|null $number * @return static|TValue * * @throws \InvalidArgumentException */ public function random($number = null) { $result = $this->collect()->random(...func_get_args()); return is_null($number) ? $result : new static($result); } /** * Replace the collection items with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function replace($items) { return new static(function () use ($items) { $items = $this->getArrayableItems($items); foreach ($this as $key => $value) { if (array_key_exists($key, $items)) { yield $key => $items[$key]; unset($items[$key]); } else { yield $key => $value; } } foreach ($items as $key => $value) { yield $key => $value; } }); } /** * Recursively replace the collection items with the given items. * * @param \Illuminate\Contracts\Support\Arrayable|iterable $items * @return static */ public function replaceRecursive($items) { return $this->passthru('replaceRecursive', func_get_args()); } /** * Reverse items order. * * @return static */ public function reverse() { return $this->passthru('reverse', func_get_args()); } /** * Search the collection for a given value and return the corresponding key if successful. * * @param TValue|(callable(TValue,TKey): bool) $value * @param bool $strict * @return TKey|false */ public function search($value, $strict = false) { /** @var (callable(TValue,TKey): bool) $predicate */ $predicate = $this->useAsCallable($value) ? $value : function ($item) use ($value, $strict) { return $strict ? $item === $value : $item == $value; }; foreach ($this as $key => $item) { if ($predicate($item, $key)) { return $key; } } return false; } /** * Shuffle the items in the collection. * * @return static */ public function shuffle() { return $this->passthru('shuffle', []); } /** * Create chunks representing a "sliding window" view of the items in the collection. * * @param int $size * @param int $step * @return static */ public function sliding($size = 2, $step = 1) { return new static(function () use ($size, $step) { $iterator = $this->getIterator(); $chunk = []; while ($iterator->valid()) { $chunk[$iterator->key()] = $iterator->current(); if (count($chunk) == $size) { yield (new static($chunk))->tap(function () use (&$chunk, $step) { $chunk = array_slice($chunk, $step, null, true); }); // If the $step between chunks is bigger than each chunk's $size // we will skip the extra items (which should never be in any // chunk) before we continue to the next chunk in the loop. if ($step > $size) { $skip = $step - $size; for ($i = 0; $i < $skip && $iterator->valid(); $i++) { $iterator->next(); } } } $iterator->next(); } }); } /** * Skip the first {$count} items. * * @param int $count * @return static */ public function skip($count) { return new static(function () use ($count) { $iterator = $this->getIterator(); while ($iterator->valid() && $count--) { $iterator->next(); } while ($iterator->valid()) { yield $iterator->key() => $iterator->current(); $iterator->next(); } }); } /** * Skip items in the collection until the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value * @return static */ public function skipUntil($value) { $callback = $this->useAsCallable($value) ? $value : $this->equality($value); return $this->skipWhile($this->negate($callback)); } /** * Skip items in the collection while the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value * @return static */ public function skipWhile($value) { $callback = $this->useAsCallable($value) ? $value : $this->equality($value); return new static(function () use ($callback) { $iterator = $this->getIterator(); while ($iterator->valid() && $callback($iterator->current(), $iterator->key())) { $iterator->next(); } while ($iterator->valid()) { yield $iterator->key() => $iterator->current(); $iterator->next(); } }); } /** * Get a slice of items from the enumerable. * * @param int $offset * @param int|null $length * @return static */ public function slice($offset, $length = null) { if ($offset < 0 || $length < 0) { return $this->passthru('slice', func_get_args()); } $instance = $this->skip($offset); return is_null($length) ? $instance : $instance->take($length); } /** * Split a collection into a certain number of groups. * * @param int $numberOfGroups * @return static */ public function split($numberOfGroups) { return $this->passthru('split', func_get_args()); } /** * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception. * * @param (callable(TValue, TKey): bool)|string $key * @param mixed $operator * @param mixed $value * @return TValue * * @throws \Illuminate\Support\ItemNotFoundException * @throws \Illuminate\Support\MultipleItemsFoundException */ public function sole($key = null, $operator = null, $value = null) { $filter = func_num_args() > 1 ? $this->operatorForWhere(...func_get_args()) : $key; return $this ->unless($filter == null) ->filter($filter) ->take(2) ->collect() ->sole(); } /** * Get the first item in the collection but throw an exception if no matching items exist. * * @param (callable(TValue, TKey): bool)|string $key * @param mixed $operator * @param mixed $value * @return TValue * * @throws \Illuminate\Support\ItemNotFoundException */ public function firstOrFail($key = null, $operator = null, $value = null) { $filter = func_num_args() > 1 ? $this->operatorForWhere(...func_get_args()) : $key; return $this ->unless($filter == null) ->filter($filter) ->take(1) ->collect() ->firstOrFail(); } /** * Chunk the collection into chunks of the given size. * * @param int $size * @return static */ public function chunk($size) { if ($size <= 0) { return static::empty(); } return new static(function () use ($size) { $iterator = $this->getIterator(); while ($iterator->valid()) { $chunk = []; while (true) { $chunk[$iterator->key()] = $iterator->current(); if (count($chunk) < $size) { $iterator->next(); if (! $iterator->valid()) { break; } } else { break; } } yield new static($chunk); $iterator->next(); } }); } /** * Split a collection into a certain number of groups, and fill the first groups completely. * * @param int $numberOfGroups * @return static */ public function splitIn($numberOfGroups) { return $this->chunk(ceil($this->count() / $numberOfGroups)); } /** * Chunk the collection into chunks with a callback. * * @param callable(TValue, TKey, Collection): bool $callback * @return static> */ public function chunkWhile(callable $callback) { return new static(function () use ($callback) { $iterator = $this->getIterator(); $chunk = new Collection; if ($iterator->valid()) { $chunk[$iterator->key()] = $iterator->current(); $iterator->next(); } while ($iterator->valid()) { if (! $callback($iterator->current(), $iterator->key(), $chunk)) { yield new static($chunk); $chunk = new Collection; } $chunk[$iterator->key()] = $iterator->current(); $iterator->next(); } if ($chunk->isNotEmpty()) { yield new static($chunk); } }); } /** * Sort through each item with a callback. * * @param (callable(TValue, TValue): int)|null|int $callback * @return static */ public function sort($callback = null) { return $this->passthru('sort', func_get_args()); } /** * Sort items in descending order. * * @param int $options * @return static */ public function sortDesc($options = SORT_REGULAR) { return $this->passthru('sortDesc', func_get_args()); } /** * Sort the collection using the given callback. * * @param array|(callable(TValue, TKey): mixed)|string $callback * @param int $options * @param bool $descending * @return static */ public function sortBy($callback, $options = SORT_REGULAR, $descending = false) { return $this->passthru('sortBy', func_get_args()); } /** * Sort the collection in descending order using the given callback. * * @param array|(callable(TValue, TKey): mixed)|string $callback * @param int $options * @return static */ public function sortByDesc($callback, $options = SORT_REGULAR) { return $this->passthru('sortByDesc', func_get_args()); } /** * Sort the collection keys. * * @param int $options * @param bool $descending * @return static */ public function sortKeys($options = SORT_REGULAR, $descending = false) { return $this->passthru('sortKeys', func_get_args()); } /** * Sort the collection keys in descending order. * * @param int $options * @return static */ public function sortKeysDesc($options = SORT_REGULAR) { return $this->passthru('sortKeysDesc', func_get_args()); } /** * Sort the collection keys using a callback. * * @param callable(TKey, TKey): int $callback * @return static */ public function sortKeysUsing(callable $callback) { return $this->passthru('sortKeysUsing', func_get_args()); } /** * Take the first or last {$limit} items. * * @param int $limit * @return static */ public function take($limit) { if ($limit < 0) { return new static(function () use ($limit) { $limit = abs($limit); $ringBuffer = []; $position = 0; foreach ($this as $key => $value) { $ringBuffer[$position] = [$key, $value]; $position = ($position + 1) % $limit; } for ($i = 0, $end = min($limit, count($ringBuffer)); $i < $end; $i++) { $pointer = ($position + $i) % $limit; yield $ringBuffer[$pointer][0] => $ringBuffer[$pointer][1]; } }); } return new static(function () use ($limit) { $iterator = $this->getIterator(); while ($limit--) { if (! $iterator->valid()) { break; } yield $iterator->key() => $iterator->current(); if ($limit) { $iterator->next(); } } }); } /** * Take items in the collection until the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value * @return static */ public function takeUntil($value) { /** @var callable(TValue, TKey): bool $callback */ $callback = $this->useAsCallable($value) ? $value : $this->equality($value); return new static(function () use ($callback) { foreach ($this as $key => $item) { if ($callback($item, $key)) { break; } yield $key => $item; } }); } /** * Take items in the collection until a given point in time. * * @param \DateTimeInterface $timeout * @return static */ public function takeUntilTimeout(DateTimeInterface $timeout) { $timeout = $timeout->getTimestamp(); return new static(function () use ($timeout) { if ($this->now() >= $timeout) { return; } foreach ($this as $key => $value) { yield $key => $value; if ($this->now() >= $timeout) { break; } } }); } /** * Take items in the collection while the given condition is met. * * @param TValue|callable(TValue,TKey): bool $value * @return static */ public function takeWhile($value) { /** @var callable(TValue, TKey): bool $callback */ $callback = $this->useAsCallable($value) ? $value : $this->equality($value); return $this->takeUntil(fn ($item, $key) => ! $callback($item, $key)); } /** * Pass each item in the collection to the given callback, lazily. * * @param callable(TValue, TKey): mixed $callback * @return static */ public function tapEach(callable $callback) { return new static(function () use ($callback) { foreach ($this as $key => $value) { $callback($value, $key); yield $key => $value; } }); } /** * Throttle the values, releasing them at most once per the given seconds. * * @return static */ public function throttle(float $seconds) { return new static(function () use ($seconds) { $microseconds = $seconds * 1_000_000; foreach ($this as $key => $value) { $fetchedAt = $this->preciseNow(); yield $key => $value; $sleep = $microseconds - ($this->preciseNow() - $fetchedAt); $this->usleep((int) $sleep); } }); } /** * Flatten a multi-dimensional associative array with dots. * * @return static */ public function dot() { return $this->passthru('dot', []); } /** * Convert a flatten "dot" notation array into an expanded array. * * @return static */ public function undot() { return $this->passthru('undot', []); } /** * Return only unique items from the collection array. * * @param (callable(TValue, TKey): mixed)|string|null $key * @param bool $strict * @return static */ public function unique($key = null, $strict = false) { $callback = $this->valueRetriever($key); return new static(function () use ($callback, $strict) { $exists = []; foreach ($this as $key => $item) { if (! in_array($id = $callback($item, $key), $exists, $strict)) { yield $key => $item; $exists[] = $id; } } }); } /** * Reset the keys on the underlying array. * * @return static */ public function values() { return new static(function () { foreach ($this as $item) { yield $item; } }); } /** * Zip the collection together with one or more arrays. * * e.g. new LazyCollection([1, 2, 3])->zip([4, 5, 6]); * => [[1, 4], [2, 5], [3, 6]] * * @template TZipValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable ...$items * @return static> */ public function zip($items) { $iterables = func_get_args(); return new static(function () use ($iterables) { $iterators = Collection::make($iterables)->map(function ($iterable) { return $this->makeIterator($iterable); })->prepend($this->getIterator()); while ($iterators->contains->valid()) { yield new static($iterators->map->current()); $iterators->each->next(); } }); } /** * Pad collection to the specified length with a value. * * @template TPadValue * * @param int $size * @param TPadValue $value * @return static */ public function pad($size, $value) { if ($size < 0) { return $this->passthru('pad', func_get_args()); } return new static(function () use ($size, $value) { $yielded = 0; foreach ($this as $index => $item) { yield $index => $item; $yielded++; } while ($yielded++ < $size) { yield $value; } }); } /** * Get the values iterator. * * @return \Traversable */ public function getIterator(): Traversable { return $this->makeIterator($this->source); } /** * Count the number of items in the collection. * * @return int */ public function count(): int { if (is_array($this->source)) { return count($this->source); } return iterator_count($this->getIterator()); } /** * Make an iterator from the given source. * * @template TIteratorKey of array-key * @template TIteratorValue * * @param \IteratorAggregate|array|(callable(): \Generator) $source * @return \Traversable */ protected function makeIterator($source) { if ($source instanceof IteratorAggregate) { return $source->getIterator(); } if (is_array($source)) { return new ArrayIterator($source); } if (is_callable($source)) { $maybeTraversable = $source(); return $maybeTraversable instanceof Traversable ? $maybeTraversable : new ArrayIterator(Arr::wrap($maybeTraversable)); } return new ArrayIterator((array) $source); } /** * Explode the "value" and "key" arguments passed to "pluck". * * @param string|string[] $value * @param string|string[]|null $key * @return array{string[],string[]|null} */ protected function explodePluckParameters($value, $key) { $value = is_string($value) ? explode('.', $value) : $value; $key = is_null($key) || is_array($key) ? $key : explode('.', $key); return [$value, $key]; } /** * Pass this lazy collection through a method on the collection class. * * @param string $method * @param array $params * @return static */ protected function passthru($method, array $params) { return new static(function () use ($method, $params) { yield from $this->collect()->$method(...$params); }); } /** * Get the current time. * * @return int */ protected function now() { return class_exists(Carbon::class) ? Carbon::now()->timestamp : time(); } /** * Get the precise current time. * * @return float */ protected function preciseNow() { return class_exists(Carbon::class) ? Carbon::now()->getPreciseTimestamp() : microtime(true) * 1_000_000; } /** * Sleep for the given amount of microseconds. * * @return void */ protected function usleep(int $microseconds) { if ($microseconds <= 0) { return; } class_exists(Sleep::class) ? Sleep::usleep($microseconds) : usleep($microseconds); } } MultipleItemsFoundException.php000064400000001340147536122360012734 0ustar00count = $count; parent::__construct("$count items were found.", $code, $previous); } /** * Get the number of items found. * * @return int */ public function getCount() { return $this->count; } } Traits/EnumeratesValues.php000064400000076036147536122360012040 0ustar00 */ protected static $proxies = [ 'average', 'avg', 'contains', 'doesntContain', 'each', 'every', 'filter', 'first', 'flatMap', 'groupBy', 'keyBy', 'map', 'max', 'min', 'partition', 'percentage', 'reject', 'skipUntil', 'skipWhile', 'some', 'sortBy', 'sortByDesc', 'sum', 'takeUntil', 'takeWhile', 'unique', 'unless', 'until', 'when', ]; /** * Create a new collection instance if the value isn't one already. * * @template TMakeKey of array-key * @template TMakeValue * * @param \Illuminate\Contracts\Support\Arrayable|iterable|null $items * @return static */ public static function make($items = []) { return new static($items); } /** * Wrap the given value in a collection if applicable. * * @template TWrapValue * * @param iterable|TWrapValue $value * @return static */ public static function wrap($value) { return $value instanceof Enumerable ? new static($value) : new static(Arr::wrap($value)); } /** * Get the underlying items from the given collection if applicable. * * @template TUnwrapKey of array-key * @template TUnwrapValue * * @param array|static $value * @return array */ public static function unwrap($value) { return $value instanceof Enumerable ? $value->all() : $value; } /** * Create a new instance with no items. * * @return static */ public static function empty() { return new static([]); } /** * Create a new collection by invoking the callback a given amount of times. * * @template TTimesValue * * @param int $number * @param (callable(int): TTimesValue)|null $callback * @return static */ public static function times($number, ?callable $callback = null) { if ($number < 1) { return new static; } return static::range(1, $number) ->unless($callback == null) ->map($callback); } /** * Alias for the "avg" method. * * @param (callable(TValue): float|int)|string|null $callback * @return float|int|null */ public function average($callback = null) { return $this->avg($callback); } /** * Alias for the "contains" method. * * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool */ public function some($key, $operator = null, $value = null) { return $this->contains(...func_get_args()); } /** * Dump the given arguments and terminate execution. * * @param mixed ...$args * @return never */ public function dd(...$args) { $this->dump(...$args); dd(); } /** * Dump the items. * * @param mixed ...$args * @return $this */ public function dump(...$args) { dump($this->all(), ...$args); return $this; } /** * Execute a callback over each item. * * @param callable(TValue, TKey): mixed $callback * @return $this */ public function each(callable $callback) { foreach ($this as $key => $item) { if ($callback($item, $key) === false) { break; } } return $this; } /** * Execute a callback over each nested chunk of items. * * @param callable(...mixed): mixed $callback * @return static */ public function eachSpread(callable $callback) { return $this->each(function ($chunk, $key) use ($callback) { $chunk[] = $key; return $callback(...$chunk); }); } /** * Determine if all items pass the given truth test. * * @param (callable(TValue, TKey): bool)|TValue|string $key * @param mixed $operator * @param mixed $value * @return bool */ public function every($key, $operator = null, $value = null) { if (func_num_args() === 1) { $callback = $this->valueRetriever($key); foreach ($this as $k => $v) { if (! $callback($v, $k)) { return false; } } return true; } return $this->every($this->operatorForWhere(...func_get_args())); } /** * Get the first item by the given key value pair. * * @param callable|string $key * @param mixed $operator * @param mixed $value * @return TValue|null */ public function firstWhere($key, $operator = null, $value = null) { return $this->first($this->operatorForWhere(...func_get_args())); } /** * Get a single key's value from the first matching item in the collection. * * @template TValueDefault * * @param string $key * @param TValueDefault|(\Closure(): TValueDefault) $default * @return TValue|TValueDefault */ public function value($key, $default = null) { if ($value = $this->firstWhere($key)) { return data_get($value, $key, $default); } return value($default); } /** * Ensure that every item in the collection is of the expected type. * * @template TEnsureOfType * * @param class-string|array> $type * @return static * * @throws \UnexpectedValueException */ public function ensure($type) { $allowedTypes = is_array($type) ? $type : [$type]; return $this->each(function ($item, $index) use ($allowedTypes) { $itemType = get_debug_type($item); foreach ($allowedTypes as $allowedType) { if ($itemType === $allowedType || $item instanceof $allowedType) { return true; } } throw new UnexpectedValueException( sprintf("Collection should only include [%s] items, but '%s' found at position %d.", implode(', ', $allowedTypes), $itemType, $index) ); }); } /** * Determine if the collection is not empty. * * @return bool */ public function isNotEmpty() { return ! $this->isEmpty(); } /** * Run a map over each nested chunk of items. * * @template TMapSpreadValue * * @param callable(mixed...): TMapSpreadValue $callback * @return static */ public function mapSpread(callable $callback) { return $this->map(function ($chunk, $key) use ($callback) { $chunk[] = $key; return $callback(...$chunk); }); } /** * Run a grouping map over the items. * * The callback should return an associative array with a single key/value pair. * * @template TMapToGroupsKey of array-key * @template TMapToGroupsValue * * @param callable(TValue, TKey): array $callback * @return static> */ public function mapToGroups(callable $callback) { $groups = $this->mapToDictionary($callback); return $groups->map([$this, 'make']); } /** * Map a collection and flatten the result by a single level. * * @template TFlatMapKey of array-key * @template TFlatMapValue * * @param callable(TValue, TKey): (\Illuminate\Support\Collection|array) $callback * @return static */ public function flatMap(callable $callback) { return $this->map($callback)->collapse(); } /** * Map the values into a new class. * * @template TMapIntoValue * * @param class-string $class * @return static */ public function mapInto($class) { if (is_subclass_of($class, BackedEnum::class)) { return $this->map(fn ($value, $key) => $class::from($value)); } return $this->map(fn ($value, $key) => new $class($value, $key)); } /** * Get the min value of a given key. * * @param (callable(TValue):mixed)|string|null $callback * @return mixed */ public function min($callback = null) { $callback = $this->valueRetriever($callback); return $this->map(fn ($value) => $callback($value)) ->filter(fn ($value) => ! is_null($value)) ->reduce(fn ($result, $value) => is_null($result) || $value < $result ? $value : $result); } /** * Get the max value of a given key. * * @param (callable(TValue):mixed)|string|null $callback * @return mixed */ public function max($callback = null) { $callback = $this->valueRetriever($callback); return $this->filter(fn ($value) => ! is_null($value))->reduce(function ($result, $item) use ($callback) { $value = $callback($item); return is_null($result) || $value > $result ? $value : $result; }); } /** * "Paginate" the collection by slicing it into a smaller collection. * * @param int $page * @param int $perPage * @return static */ public function forPage($page, $perPage) { $offset = max(0, ($page - 1) * $perPage); return $this->slice($offset, $perPage); } /** * Partition the collection into two arrays using the given callback or key. * * @param (callable(TValue, TKey): bool)|TValue|string $key * @param TValue|string|null $operator * @param TValue|null $value * @return static, static> */ public function partition($key, $operator = null, $value = null) { $passed = []; $failed = []; $callback = func_num_args() === 1 ? $this->valueRetriever($key) : $this->operatorForWhere(...func_get_args()); foreach ($this as $key => $item) { if ($callback($item, $key)) { $passed[$key] = $item; } else { $failed[$key] = $item; } } return new static([new static($passed), new static($failed)]); } /** * Calculate the percentage of items that pass a given truth test. * * @param (callable(TValue, TKey): bool) $callback * @param int $precision * @return float|null */ public function percentage(callable $callback, int $precision = 2) { if ($this->isEmpty()) { return null; } return round( $this->filter($callback)->count() / $this->count() * 100, $precision ); } /** * Get the sum of the given values. * * @param (callable(TValue): mixed)|string|null $callback * @return mixed */ public function sum($callback = null) { $callback = is_null($callback) ? $this->identity() : $this->valueRetriever($callback); return $this->reduce(fn ($result, $item) => $result + $callback($item), 0); } /** * Apply the callback if the collection is empty. * * @template TWhenEmptyReturnType * * @param (callable($this): TWhenEmptyReturnType) $callback * @param (callable($this): TWhenEmptyReturnType)|null $default * @return $this|TWhenEmptyReturnType */ public function whenEmpty(callable $callback, ?callable $default = null) { return $this->when($this->isEmpty(), $callback, $default); } /** * Apply the callback if the collection is not empty. * * @template TWhenNotEmptyReturnType * * @param callable($this): TWhenNotEmptyReturnType $callback * @param (callable($this): TWhenNotEmptyReturnType)|null $default * @return $this|TWhenNotEmptyReturnType */ public function whenNotEmpty(callable $callback, ?callable $default = null) { return $this->when($this->isNotEmpty(), $callback, $default); } /** * Apply the callback unless the collection is empty. * * @template TUnlessEmptyReturnType * * @param callable($this): TUnlessEmptyReturnType $callback * @param (callable($this): TUnlessEmptyReturnType)|null $default * @return $this|TUnlessEmptyReturnType */ public function unlessEmpty(callable $callback, ?callable $default = null) { return $this->whenNotEmpty($callback, $default); } /** * Apply the callback unless the collection is not empty. * * @template TUnlessNotEmptyReturnType * * @param callable($this): TUnlessNotEmptyReturnType $callback * @param (callable($this): TUnlessNotEmptyReturnType)|null $default * @return $this|TUnlessNotEmptyReturnType */ public function unlessNotEmpty(callable $callback, ?callable $default = null) { return $this->whenEmpty($callback, $default); } /** * Filter items by the given key value pair. * * @param callable|string $key * @param mixed $operator * @param mixed $value * @return static */ public function where($key, $operator = null, $value = null) { return $this->filter($this->operatorForWhere(...func_get_args())); } /** * Filter items where the value for the given key is null. * * @param string|null $key * @return static */ public function whereNull($key = null) { return $this->whereStrict($key, null); } /** * Filter items where the value for the given key is not null. * * @param string|null $key * @return static */ public function whereNotNull($key = null) { return $this->where($key, '!==', null); } /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param mixed $value * @return static */ public function whereStrict($key, $value) { return $this->where($key, '===', $value); } /** * Filter items by the given key value pair. * * @param string $key * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @param bool $strict * @return static */ public function whereIn($key, $values, $strict = false) { $values = $this->getArrayableItems($values); return $this->filter(fn ($item) => in_array(data_get($item, $key), $values, $strict)); } /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @return static */ public function whereInStrict($key, $values) { return $this->whereIn($key, $values, true); } /** * Filter items such that the value of the given key is between the given values. * * @param string $key * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @return static */ public function whereBetween($key, $values) { return $this->where($key, '>=', reset($values))->where($key, '<=', end($values)); } /** * Filter items such that the value of the given key is not between the given values. * * @param string $key * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @return static */ public function whereNotBetween($key, $values) { return $this->filter( fn ($item) => data_get($item, $key) < reset($values) || data_get($item, $key) > end($values) ); } /** * Filter items by the given key value pair. * * @param string $key * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @param bool $strict * @return static */ public function whereNotIn($key, $values, $strict = false) { $values = $this->getArrayableItems($values); return $this->reject(fn ($item) => in_array(data_get($item, $key), $values, $strict)); } /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param \Illuminate\Contracts\Support\Arrayable|iterable $values * @return static */ public function whereNotInStrict($key, $values) { return $this->whereNotIn($key, $values, true); } /** * Filter the items, removing any items that don't match the given type(s). * * @template TWhereInstanceOf * * @param class-string|array> $type * @return static */ public function whereInstanceOf($type) { return $this->filter(function ($value) use ($type) { if (is_array($type)) { foreach ($type as $classType) { if ($value instanceof $classType) { return true; } } return false; } return $value instanceof $type; }); } /** * Pass the collection to the given callback and return the result. * * @template TPipeReturnType * * @param callable($this): TPipeReturnType $callback * @return TPipeReturnType */ public function pipe(callable $callback) { return $callback($this); } /** * Pass the collection into a new class. * * @template TPipeIntoValue * * @param class-string $class * @return TPipeIntoValue */ public function pipeInto($class) { return new $class($this); } /** * Pass the collection through a series of callable pipes and return the result. * * @param array $callbacks * @return mixed */ public function pipeThrough($callbacks) { return Collection::make($callbacks)->reduce( fn ($carry, $callback) => $callback($carry), $this, ); } /** * Reduce the collection to a single value. * * @template TReduceInitial * @template TReduceReturnType * * @param callable(TReduceInitial|TReduceReturnType, TValue, TKey): TReduceReturnType $callback * @param TReduceInitial $initial * @return TReduceReturnType */ public function reduce(callable $callback, $initial = null) { $result = $initial; foreach ($this as $key => $value) { $result = $callback($result, $value, $key); } return $result; } /** * Reduce the collection to multiple aggregate values. * * @param callable $callback * @param mixed ...$initial * @return array * * @throws \UnexpectedValueException */ public function reduceSpread(callable $callback, ...$initial) { $result = $initial; foreach ($this as $key => $value) { $result = call_user_func_array($callback, array_merge($result, [$value, $key])); if (! is_array($result)) { throw new UnexpectedValueException(sprintf( "%s::reduceSpread expects reducer to return an array, but got a '%s' instead.", class_basename(static::class), gettype($result) )); } } return $result; } /** * Reduce an associative collection to a single value. * * @template TReduceWithKeysInitial * @template TReduceWithKeysReturnType * * @param callable(TReduceWithKeysInitial|TReduceWithKeysReturnType, TValue, TKey): TReduceWithKeysReturnType $callback * @param TReduceWithKeysInitial $initial * @return TReduceWithKeysReturnType */ public function reduceWithKeys(callable $callback, $initial = null) { return $this->reduce($callback, $initial); } /** * Create a collection of all elements that do not pass a given truth test. * * @param (callable(TValue, TKey): bool)|bool|TValue $callback * @return static */ public function reject($callback = true) { $useAsCallable = $this->useAsCallable($callback); return $this->filter(function ($value, $key) use ($callback, $useAsCallable) { return $useAsCallable ? ! $callback($value, $key) : $value != $callback; }); } /** * Pass the collection to the given callback and then return it. * * @param callable($this): mixed $callback * @return $this */ public function tap(callable $callback) { $callback($this); return $this; } /** * Return only unique items from the collection array. * * @param (callable(TValue, TKey): mixed)|string|null $key * @param bool $strict * @return static */ public function unique($key = null, $strict = false) { $callback = $this->valueRetriever($key); $exists = []; return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) { if (in_array($id = $callback($item, $key), $exists, $strict)) { return true; } $exists[] = $id; }); } /** * Return only unique items from the collection array using strict comparison. * * @param (callable(TValue, TKey): mixed)|string|null $key * @return static */ public function uniqueStrict($key = null) { return $this->unique($key, true); } /** * Collect the values into a collection. * * @return \Illuminate\Support\Collection */ public function collect() { return new Collection($this->all()); } /** * Get the collection of items as a plain array. * * @return array */ public function toArray() { return $this->map(fn ($value) => $value instanceof Arrayable ? $value->toArray() : $value)->all(); } /** * Convert the object into something JSON serializable. * * @return array */ public function jsonSerialize(): array { return array_map(function ($value) { if ($value instanceof JsonSerializable) { return $value->jsonSerialize(); } elseif ($value instanceof Jsonable) { return json_decode($value->toJson(), true); } elseif ($value instanceof Arrayable) { return $value->toArray(); } return $value; }, $this->all()); } /** * Get the collection of items as JSON. * * @param int $options * @return string */ public function toJson($options = 0) { return json_encode($this->jsonSerialize(), $options); } /** * Get a CachingIterator instance. * * @param int $flags * @return \CachingIterator */ public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING) { return new CachingIterator($this->getIterator(), $flags); } /** * Convert the collection to its string representation. * * @return string */ public function __toString() { return $this->escapeWhenCastingToString ? e($this->toJson()) : $this->toJson(); } /** * Indicate that the model's string representation should be escaped when __toString is invoked. * * @param bool $escape * @return $this */ public function escapeWhenCastingToString($escape = true) { $this->escapeWhenCastingToString = $escape; return $this; } /** * Add a method to the list of proxied methods. * * @param string $method * @return void */ public static function proxy($method) { static::$proxies[] = $method; } /** * Dynamically access collection proxies. * * @param string $key * @return mixed * * @throws \Exception */ public function __get($key) { if (! in_array($key, static::$proxies)) { throw new Exception("Property [{$key}] does not exist on this collection instance."); } return new HigherOrderCollectionProxy($this, $key); } /** * Results array of items from Collection or Arrayable. * * @param mixed $items * @return array */ protected function getArrayableItems($items) { if (is_array($items)) { return $items; } return match (true) { $items instanceof WeakMap => throw new InvalidArgumentException('Collections can not be created using instances of WeakMap.'), $items instanceof Enumerable => $items->all(), $items instanceof Arrayable => $items->toArray(), $items instanceof Traversable => iterator_to_array($items), $items instanceof Jsonable => json_decode($items->toJson(), true), $items instanceof JsonSerializable => (array) $items->jsonSerialize(), $items instanceof UnitEnum => [$items], default => (array) $items, }; } /** * Get an operator checker callback. * * @param callable|string $key * @param string|null $operator * @param mixed $value * @return \Closure */ protected function operatorForWhere($key, $operator = null, $value = null) { if ($this->useAsCallable($key)) { return $key; } if (func_num_args() === 1) { $value = true; $operator = '='; } if (func_num_args() === 2) { $value = $operator; $operator = '='; } return function ($item) use ($key, $operator, $value) { $retrieved = data_get($item, $key); $strings = array_filter([$retrieved, $value], function ($value) { return is_string($value) || (is_object($value) && method_exists($value, '__toString')); }); if (count($strings) < 2 && count(array_filter([$retrieved, $value], 'is_object')) == 1) { return in_array($operator, ['!=', '<>', '!==']); } switch ($operator) { default: case '=': case '==': return $retrieved == $value; case '!=': case '<>': return $retrieved != $value; case '<': return $retrieved < $value; case '>': return $retrieved > $value; case '<=': return $retrieved <= $value; case '>=': return $retrieved >= $value; case '===': return $retrieved === $value; case '!==': return $retrieved !== $value; case '<=>': return $retrieved <=> $value; } }; } /** * Determine if the given value is callable, but not a string. * * @param mixed $value * @return bool */ protected function useAsCallable($value) { return ! is_string($value) && is_callable($value); } /** * Get a value retrieving callback. * * @param callable|string|null $value * @return callable */ protected function valueRetriever($value) { if ($this->useAsCallable($value)) { return $value; } return fn ($item) => data_get($item, $value); } /** * Make a function to check an item's equality. * * @param mixed $value * @return \Closure(mixed): bool */ protected function equality($value) { return fn ($item) => $item === $value; } /** * Make a function using another function, by negating its result. * * @param \Closure $callback * @return \Closure */ protected function negate(Closure $callback) { return fn (...$params) => ! $callback(...$params); } /** * Make a function that returns what's passed to it. * * @return \Closure(TValue): TValue */ protected function identity() { return fn ($value) => $value; } } composer.json000064400000002004147536122360007273 0ustar00{ "name": "illuminate/collections", "description": "The Illuminate Collections package.", "license": "MIT", "homepage": "https://laravel.com", "support": { "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, "authors": [ { "name": "Taylor Otwell", "email": "taylor@laravel.com" } ], "require": { "php": "^8.2", "illuminate/conditionable": "^11.0", "illuminate/contracts": "^11.0", "illuminate/macroable": "^11.0" }, "autoload": { "psr-4": { "Illuminate\\Support\\": "" }, "files": [ "helpers.php" ] }, "extra": { "branch-alias": { "dev-master": "11.x-dev" } }, "suggest": { "symfony/var-dumper": "Required to use the dump method (^7.0)." }, "config": { "sort-packages": true }, "minimum-stability": "dev" } helpers.php000064400000014646147536122360006743 0ustar00|iterable|null $value * @return \Illuminate\Support\Collection */ function collect($value = []) { return new Collection($value); } } if (! function_exists('data_fill')) { /** * Fill in data where it's missing. * * @param mixed $target * @param string|array $key * @param mixed $value * @return mixed */ function data_fill(&$target, $key, $value) { return data_set($target, $key, $value, false); } } if (! function_exists('data_get')) { /** * Get an item from an array or object using "dot" notation. * * @param mixed $target * @param string|array|int|null $key * @param mixed $default * @return mixed */ function data_get($target, $key, $default = null) { if (is_null($key)) { return $target; } $key = is_array($key) ? $key : explode('.', $key); foreach ($key as $i => $segment) { unset($key[$i]); if (is_null($segment)) { return $target; } if ($segment === '*') { if ($target instanceof Collection) { $target = $target->all(); } elseif (! is_iterable($target)) { return value($default); } $result = []; foreach ($target as $item) { $result[] = data_get($item, $key); } return in_array('*', $key) ? Arr::collapse($result) : $result; } $segment = match ($segment) { '\*' => '*', '\{first}' => '{first}', '{first}' => array_key_first(is_array($target) ? $target : collect($target)->all()), '\{last}' => '{last}', '{last}' => array_key_last(is_array($target) ? $target : collect($target)->all()), default => $segment, }; if (Arr::accessible($target) && Arr::exists($target, $segment)) { $target = $target[$segment]; } elseif (is_object($target) && isset($target->{$segment})) { $target = $target->{$segment}; } else { return value($default); } } return $target; } } if (! function_exists('data_set')) { /** * Set an item on an array or object using dot notation. * * @param mixed $target * @param string|array $key * @param mixed $value * @param bool $overwrite * @return mixed */ function data_set(&$target, $key, $value, $overwrite = true) { $segments = is_array($key) ? $key : explode('.', $key); if (($segment = array_shift($segments)) === '*') { if (! Arr::accessible($target)) { $target = []; } if ($segments) { foreach ($target as &$inner) { data_set($inner, $segments, $value, $overwrite); } } elseif ($overwrite) { foreach ($target as &$inner) { $inner = $value; } } } elseif (Arr::accessible($target)) { if ($segments) { if (! Arr::exists($target, $segment)) { $target[$segment] = []; } data_set($target[$segment], $segments, $value, $overwrite); } elseif ($overwrite || ! Arr::exists($target, $segment)) { $target[$segment] = $value; } } elseif (is_object($target)) { if ($segments) { if (! isset($target->{$segment})) { $target->{$segment} = []; } data_set($target->{$segment}, $segments, $value, $overwrite); } elseif ($overwrite || ! isset($target->{$segment})) { $target->{$segment} = $value; } } else { $target = []; if ($segments) { data_set($target[$segment], $segments, $value, $overwrite); } elseif ($overwrite) { $target[$segment] = $value; } } return $target; } } if (! function_exists('data_forget')) { /** * Remove / unset an item from an array or object using "dot" notation. * * @param mixed $target * @param string|array|int|null $key * @return mixed */ function data_forget(&$target, $key) { $segments = is_array($key) ? $key : explode('.', $key); if (($segment = array_shift($segments)) === '*' && Arr::accessible($target)) { if ($segments) { foreach ($target as &$inner) { data_forget($inner, $segments); } } } elseif (Arr::accessible($target)) { if ($segments && Arr::exists($target, $segment)) { data_forget($target[$segment], $segments); } else { Arr::forget($target, $segment); } } elseif (is_object($target)) { if ($segments && isset($target->{$segment})) { data_forget($target->{$segment}, $segments); } elseif (isset($target->{$segment})) { unset($target->{$segment}); } } return $target; } } if (! function_exists('head')) { /** * Get the first element of an array. Useful for method chaining. * * @param array $array * @return mixed */ function head($array) { return reset($array); } } if (! function_exists('last')) { /** * Get the last element from an array. * * @param array $array * @return mixed */ function last($array) { return end($array); } } if (! function_exists('value')) { /** * Return the default value of the given value. * * @param mixed $value * @param mixed ...$args * @return mixed */ function value($value, ...$args) { return $value instanceof Closure ? $value(...$args) : $value; } }