123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 |
- <?php
-
- namespace Illuminate\Database\Eloquent;
-
- use LogicException;
- use Illuminate\Support\Arr;
- use Illuminate\Support\Str;
- use Illuminate\Contracts\Support\Arrayable;
- use Illuminate\Database\Eloquent\Relations\Pivot;
- use Illuminate\Contracts\Queue\QueueableCollection;
- use Illuminate\Support\Collection as BaseCollection;
-
- class Collection extends BaseCollection implements QueueableCollection
- {
- /**
- * Find a model in the collection by key.
- *
- * @param mixed $key
- * @param mixed $default
- * @return \Illuminate\Database\Eloquent\Model|static
- */
- public function find($key, $default = null)
- {
- if ($key instanceof Model) {
- $key = $key->getKey();
- }
-
- if ($key instanceof Arrayable) {
- $key = $key->toArray();
- }
-
- if (is_array($key)) {
- if ($this->isEmpty()) {
- return new static;
- }
-
- return $this->whereIn($this->first()->getKeyName(), $key);
- }
-
- return Arr::first($this->items, function ($model) use ($key) {
- return $model->getKey() == $key;
- }, $default);
- }
-
- /**
- * Load a set of relationships onto the collection.
- *
- * @param array|string $relations
- * @return $this
- */
- public function load($relations)
- {
- if ($this->isNotEmpty()) {
- if (is_string($relations)) {
- $relations = func_get_args();
- }
-
- $query = $this->first()->newQueryWithoutRelationships()->with($relations);
-
- $this->items = $query->eagerLoadRelations($this->items);
- }
-
- return $this;
- }
-
- /**
- * Load a set of relationships onto the collection if they are not already eager loaded.
- *
- * @param array|string $relations
- * @return $this
- */
- public function loadMissing($relations)
- {
- if (is_string($relations)) {
- $relations = func_get_args();
- }
-
- foreach ($relations as $key => $value) {
- if (is_numeric($key)) {
- $key = $value;
- }
-
- $segments = explode('.', explode(':', $key)[0]);
-
- if (Str::contains($key, ':')) {
- $segments[count($segments) - 1] .= ':'.explode(':', $key)[1];
- }
-
- $path = array_combine($segments, $segments);
-
- if (is_callable($value)) {
- $path[end($segments)] = $value;
- }
-
- $this->loadMissingRelation($this, $path);
- }
-
- return $this;
- }
-
- /**
- * Load a relationship path if it is not already eager loaded.
- *
- * @param \Illuminate\Database\Eloquent\Collection $models
- * @param array $path
- * @return void
- */
- protected function loadMissingRelation(Collection $models, array $path)
- {
- $relation = array_splice($path, 0, 1);
-
- $name = explode(':', key($relation))[0];
-
- if (is_string(reset($relation))) {
- $relation = reset($relation);
- }
-
- $models->filter(function ($model) use ($name) {
- return ! is_null($model) && ! $model->relationLoaded($name);
- })->load($relation);
-
- if (empty($path)) {
- return;
- }
-
- $models = $models->pluck($name);
-
- if ($models->first() instanceof BaseCollection) {
- $models = $models->collapse();
- }
-
- $this->loadMissingRelation(new static($models), $path);
- }
-
- /**
- * Load a set of relationships onto the mixed relationship collection.
- *
- * @param string $relation
- * @param array $relations
- * @return $this
- */
- public function loadMorph($relation, $relations)
- {
- $this->pluck($relation)
- ->filter()
- ->groupBy(function ($model) {
- return get_class($model);
- })
- ->filter(function ($models, $className) use ($relations) {
- return Arr::has($relations, $className);
- })
- ->each(function ($models, $className) use ($relations) {
- $className::with($relations[$className])
- ->eagerLoadRelations($models->all());
- });
-
- return $this;
- }
-
- /**
- * Add an item to the collection.
- *
- * @param mixed $item
- * @return $this
- */
- public function add($item)
- {
- $this->items[] = $item;
-
- return $this;
- }
-
- /**
- * Determine if a key exists in the collection.
- *
- * @param mixed $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)) {
- return parent::contains(...func_get_args());
- }
-
- if ($key instanceof Model) {
- return parent::contains(function ($model) use ($key) {
- return $model->is($key);
- });
- }
-
- return parent::contains(function ($model) use ($key) {
- return $model->getKey() == $key;
- });
- }
-
- /**
- * Get the array of primary keys.
- *
- * @return array
- */
- public function modelKeys()
- {
- return array_map(function ($model) {
- return $model->getKey();
- }, $this->items);
- }
-
- /**
- * Merge the collection with the given items.
- *
- * @param \ArrayAccess|array $items
- * @return static
- */
- public function merge($items)
- {
- $dictionary = $this->getDictionary();
-
- foreach ($items as $item) {
- $dictionary[$item->getKey()] = $item;
- }
-
- return new static(array_values($dictionary));
- }
-
- /**
- * Run a map over each of the items.
- *
- * @param callable $callback
- * @return \Illuminate\Support\Collection|static
- */
- public function map(callable $callback)
- {
- $result = parent::map($callback);
-
- return $result->contains(function ($item) {
- return ! $item instanceof Model;
- }) ? $result->toBase() : $result;
- }
-
- /**
- * Reload a fresh model instance from the database for all the entities.
- *
- * @param array|string $with
- * @return static
- */
- public function fresh($with = [])
- {
- if ($this->isEmpty()) {
- return new static;
- }
-
- $model = $this->first();
-
- $freshModels = $model->newQueryWithoutScopes()
- ->with(is_string($with) ? func_get_args() : $with)
- ->whereIn($model->getKeyName(), $this->modelKeys())
- ->get()
- ->getDictionary();
-
- return $this->map(function ($model) use ($freshModels) {
- return $model->exists && isset($freshModels[$model->getKey()])
- ? $freshModels[$model->getKey()] : null;
- });
- }
-
- /**
- * Diff the collection with the given items.
- *
- * @param \ArrayAccess|array $items
- * @return static
- */
- public function diff($items)
- {
- $diff = new static;
-
- $dictionary = $this->getDictionary($items);
-
- foreach ($this->items as $item) {
- if (! isset($dictionary[$item->getKey()])) {
- $diff->add($item);
- }
- }
-
- return $diff;
- }
-
- /**
- * Intersect the collection with the given items.
- *
- * @param \ArrayAccess|array $items
- * @return static
- */
- public function intersect($items)
- {
- $intersect = new static;
-
- $dictionary = $this->getDictionary($items);
-
- foreach ($this->items as $item) {
- if (isset($dictionary[$item->getKey()])) {
- $intersect->add($item);
- }
- }
-
- return $intersect;
- }
-
- /**
- * Return only unique items from the collection.
- *
- * @param string|callable|null $key
- * @param bool $strict
- * @return static|\Illuminate\Support\Collection
- */
- public function unique($key = null, $strict = false)
- {
- if (! is_null($key)) {
- return parent::unique($key, $strict);
- }
-
- return new static(array_values($this->getDictionary()));
- }
-
- /**
- * Returns only the models from the collection with the specified keys.
- *
- * @param mixed $keys
- * @return static
- */
- public function only($keys)
- {
- if (is_null($keys)) {
- return new static($this->items);
- }
-
- $dictionary = Arr::only($this->getDictionary(), $keys);
-
- return new static(array_values($dictionary));
- }
-
- /**
- * Returns all models in the collection except the models with specified keys.
- *
- * @param mixed $keys
- * @return static
- */
- public function except($keys)
- {
- $dictionary = Arr::except($this->getDictionary(), $keys);
-
- return new static(array_values($dictionary));
- }
-
- /**
- * Make the given, typically visible, attributes hidden across the entire collection.
- *
- * @param array|string $attributes
- * @return $this
- */
- public function makeHidden($attributes)
- {
- return $this->each(function ($model) use ($attributes) {
- $model->addHidden($attributes);
- });
- }
-
- /**
- * Make the given, typically hidden, attributes visible across the entire collection.
- *
- * @param array|string $attributes
- * @return $this
- */
- public function makeVisible($attributes)
- {
- return $this->each(function ($model) use ($attributes) {
- $model->makeVisible($attributes);
- });
- }
-
- /**
- * Get a dictionary keyed by primary keys.
- *
- * @param \ArrayAccess|array|null $items
- * @return array
- */
- public function getDictionary($items = null)
- {
- $items = is_null($items) ? $this->items : $items;
-
- $dictionary = [];
-
- foreach ($items as $value) {
- $dictionary[$value->getKey()] = $value;
- }
-
- return $dictionary;
- }
-
- /**
- * The following methods are intercepted to always return base collections.
- */
-
- /**
- * Get an array with the values of a given key.
- *
- * @param string $value
- * @param string|null $key
- * @return \Illuminate\Support\Collection
- */
- public function pluck($value, $key = null)
- {
- return $this->toBase()->pluck($value, $key);
- }
-
- /**
- * Get the keys of the collection items.
- *
- * @return \Illuminate\Support\Collection
- */
- public function keys()
- {
- return $this->toBase()->keys();
- }
-
- /**
- * Zip the collection together with one or more arrays.
- *
- * @param mixed ...$items
- * @return \Illuminate\Support\Collection
- */
- public function zip($items)
- {
- return call_user_func_array([$this->toBase(), 'zip'], func_get_args());
- }
-
- /**
- * Collapse the collection of items into a single array.
- *
- * @return \Illuminate\Support\Collection
- */
- public function collapse()
- {
- return $this->toBase()->collapse();
- }
-
- /**
- * Get a flattened array of the items in the collection.
- *
- * @param int $depth
- * @return \Illuminate\Support\Collection
- */
- public function flatten($depth = INF)
- {
- return $this->toBase()->flatten($depth);
- }
-
- /**
- * Flip the items in the collection.
- *
- * @return \Illuminate\Support\Collection
- */
- public function flip()
- {
- return $this->toBase()->flip();
- }
-
- /**
- * Pad collection to the specified length with a value.
- *
- * @param int $size
- * @param mixed $value
- * @return \Illuminate\Support\Collection
- */
- public function pad($size, $value)
- {
- return $this->toBase()->pad($size, $value);
- }
-
- /**
- * Get the type of the entities being queued.
- *
- * @return string|null
- * @throws \LogicException
- */
- public function getQueueableClass()
- {
- if ($this->isEmpty()) {
- return;
- }
-
- $class = get_class($this->first());
-
- $this->each(function ($model) use ($class) {
- if (get_class($model) !== $class) {
- throw new LogicException('Queueing collections with multiple model types is not supported.');
- }
- });
-
- return $class;
- }
-
- /**
- * Get the identifiers for all of the entities.
- *
- * @return array
- */
- public function getQueueableIds()
- {
- if ($this->isEmpty()) {
- return [];
- }
-
- return $this->first() instanceof Pivot
- ? $this->map->getQueueableId()->all()
- : $this->modelKeys();
- }
-
- /**
- * Get the relationships of the entities being queued.
- *
- * @return array
- */
- public function getQueueableRelations()
- {
- return $this->isNotEmpty() ? $this->first()->getQueueableRelations() : [];
- }
-
- /**
- * Get the connection of the entities being queued.
- *
- * @return string|null
- * @throws \LogicException
- */
- public function getQueueableConnection()
- {
- if ($this->isEmpty()) {
- return;
- }
-
- $connection = $this->first()->getConnectionName();
-
- $this->each(function ($model) use ($connection) {
- if ($model->getConnectionName() !== $connection) {
- throw new LogicException('Queueing collections with multiple model connections is not supported.');
- }
- });
-
- return $connection;
- }
- }
|