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. * * @param int $number * @param callable|null $callback * @return static */ public static function times($number, callable $callback = null) { if ($number < 1) { return new static; } return static::range(1, $number) ->when($callback) ->map($callback); } /** * Alias for the "avg" method. * * @param callable|string|null $callback * @return mixed */ public function average($callback = null) { return $this->avg($callback); } /** * Alias for the "contains" method. * * @param mixed $key * @param mixed $operator * @param mixed $value * @return bool */ public function some($key, $operator = null, $value = null) { return $this->contains(...func_get_args()); } /** * Determine if an item exists, using strict comparison. * * @param mixed $key * @param mixed $value * @return bool */ public function containsStrict($key, $value = null) { if (func_num_args() === 2) { return $this->contains(function ($item) use ($key, $value) { return 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; } /** * Dump the items and end the script. * * @param mixed ...$args * @return void */ public function dd(...$args) { $this->dump(...$args); exit(1); } /** * Dump the items. * * @return $this */ public function dump() { (new Collection(func_get_args())) ->push($this->all()) ->each(function ($item) { VarDumper::dump($item); }); return $this; } /** * Execute a callback over each item. * * @param callable $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 $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 string|callable $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 string $key * @param mixed $operator * @param mixed $value * @return mixed */ public function firstWhere($key, $operator = null, $value = null) { return $this->first($this->operatorForWhere(...func_get_args())); } /** * Determine if the collection is not empty. * * @return bool */ public function isNotEmpty() { return ! $this->isEmpty(); } /** * Run a map over each nested chunk of items. * * @param callable $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. * * @param callable $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. * * @param callable $callback * @return static */ public function flatMap(callable $callback) { return $this->map($callback)->collapse(); } /** * Map the values into a new class. * * @param string $class * @return static */ public function mapInto($class) { return $this->map(function ($value, $key) use ($class) { return new $class($value, $key); }); } /** * Get the min value of a given key. * * @param callable|string|null $callback * @return mixed */ public function min($callback = null) { $callback = $this->valueRetriever($callback); return $this->map(function ($value) use ($callback) { return $callback($value); })->filter(function ($value) { return ! is_null($value); })->reduce(function ($result, $value) { return is_null($result) || $value < $result ? $value : $result; }); } /** * Get the max value of a given key. * * @param callable|string|null $callback * @return mixed */ public function max($callback = null) { $callback = $this->valueRetriever($callback); return $this->filter(function ($value) { return ! 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|string $key * @param mixed $operator * @param mixed $value * @return 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)]); } /** * Get the sum of the given values. * * @param callable|string|null $callback * @return mixed */ public function sum($callback = null) { $callback = is_null($callback) ? $this->identity() : $this->valueRetriever($callback); return $this->reduce(function ($result, $item) use ($callback) { return $result + $callback($item); }, 0); } /** * Apply the callback if the value is truthy. * * @param bool|mixed $value * @param callable|null $callback * @param callable|null $default * @return static|mixed */ public function when($value, callable $callback = null, callable $default = null) { if (! $callback) { return new HigherOrderWhenProxy($this, $value); } if ($value) { return $callback($this, $value); } elseif ($default) { return $default($this, $value); } return $this; } /** * Apply the callback if the collection is empty. * * @param callable $callback * @param callable|null $default * @return static|mixed */ public function whenEmpty(callable $callback, callable $default = null) { return $this->when($this->isEmpty(), $callback, $default); } /** * Apply the callback if the collection is not empty. * * @param callable $callback * @param callable|null $default * @return static|mixed */ public function whenNotEmpty(callable $callback, callable $default = null) { return $this->when($this->isNotEmpty(), $callback, $default); } /** * Apply the callback if the value is falsy. * * @param bool $value * @param callable $callback * @param callable|null $default * @return static|mixed */ public function unless($value, callable $callback, callable $default = null) { return $this->when(! $value, $callback, $default); } /** * Apply the callback unless the collection is empty. * * @param callable $callback * @param callable|null $default * @return static|mixed */ public function unlessEmpty(callable $callback, callable $default = null) { return $this->whenNotEmpty($callback, $default); } /** * Apply the callback unless the collection is not empty. * * @param callable $callback * @param callable|null $default * @return static|mixed */ public function unlessNotEmpty(callable $callback, callable $default = null) { return $this->whenEmpty($callback, $default); } /** * 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) { 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 mixed $values * @param bool $strict * @return static */ public function whereIn($key, $values, $strict = false) { $values = $this->getArrayableItems($values); return $this->filter(function ($item) use ($key, $values, $strict) { return in_array(data_get($item, $key), $values, $strict); }); } /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param mixed $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 array $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 array $values * @return static */ public function whereNotBetween($key, $values) { return $this->filter(function ($item) use ($key, $values) { return data_get($item, $key) < reset($values) || data_get($item, $key) > end($values); }); } /** * Filter items by the given key value pair. * * @param string $key * @param mixed $values * @param bool $strict * @return static */ public function whereNotIn($key, $values, $strict = false) { $values = $this->getArrayableItems($values); return $this->reject(function ($item) use ($key, $values, $strict) { return in_array(data_get($item, $key), $values, $strict); }); } /** * Filter items by the given key value pair using strict comparison. * * @param string $key * @param mixed $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). * * @param string|string[] $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. * * @param callable $callback * @return mixed */ public function pipe(callable $callback) { return $callback($this); } /** * Pass the collection into a new class. * * @param string $class * @return mixed */ public function pipeInto($class) { return new $class($this); } /** * Pass the collection to the given callback and then return it. * * @param callable $callback * @return $this */ public function tap(callable $callback) { $callback(clone $this); return $this; } /** * Reduce the collection to a single value. * * @param callable $callback * @param mixed $initial * @return mixed */ public function reduce(callable $callback, $initial = null) { $result = $initial; foreach ($this as $key => $value) { $result = $callback($result, $value, $key); } return $result; } /** * Reduce an associative collection to a single value. * * @param callable $callback * @param mixed $initial * @return mixed */ 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|mixed $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; }); } /** * Return only unique items from the collection array. * * @param string|callable|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 string|callable|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(function ($value) { return $value instanceof Arrayable ? $value->toArray() : $value; })->all(); } /** * Convert the object into something JSON serializable. * * @return array */ public function jsonSerialize() { 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->toJson(); } /** * 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; } elseif ($items instanceof Enumerable) { return $items->all(); } elseif ($items instanceof Arrayable) { return $items->toArray(); } elseif ($items instanceof Jsonable) { return json_decode($items->toJson(), true); } elseif ($items instanceof JsonSerializable) { return (array) $items->jsonSerialize(); } elseif ($items instanceof Traversable) { return iterator_to_array($items); } return (array) $items; } /** * Get an operator checker callback. * * @param string $key * @param string|null $operator * @param mixed $value * @return \Closure */ protected function operatorForWhere($key, $operator = null, $value = null) { 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; } }; } /** * 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 function ($item) use ($value) { return data_get($item, $value); }; } /** * Make a function to check an item's equality. * * @param mixed $value * @return \Closure */ protected function equality($value) { return function ($item) use ($value) { return $item === $value; }; } /** * Make a function using another function, by negating its result. * * @param \Closure $callback * @return \Closure */ protected function negate(Closure $callback) { return function (...$params) use ($callback) { return ! $callback(...$params); }; } /** * Make a function that returns what's passed to it. * * @return \Closure */ protected function identity() { return function ($value) { return $value; }; } }