diff --git a/src/Illuminate/Contracts/Database/ModelIdentifier.php b/src/Illuminate/Contracts/Database/ModelIdentifier.php index b44f05d997b3..c4069fd7b10e 100644 --- a/src/Illuminate/Contracts/Database/ModelIdentifier.php +++ b/src/Illuminate/Contracts/Database/ModelIdentifier.php @@ -14,6 +14,8 @@ class ModelIdentifier /** * The unique identifier of the model. * + * This may be either a single ID or an array of IDs. + * * @var mixed */ public $id; diff --git a/src/Illuminate/Database/Eloquent/Collection.php b/src/Illuminate/Database/Eloquent/Collection.php index 04ea2e601f68..1ce1b368ad6c 100755 --- a/src/Illuminate/Database/Eloquent/Collection.php +++ b/src/Illuminate/Database/Eloquent/Collection.php @@ -2,10 +2,12 @@ namespace Illuminate\Database\Eloquent; +use LogicException; use Illuminate\Support\Arr; +use Illuminate\Contracts\Queue\QueueableCollection; use Illuminate\Support\Collection as BaseCollection; -class Collection extends BaseCollection +class Collection extends BaseCollection implements QueueableCollection { /** * Find a model in the collection by key. @@ -321,6 +323,38 @@ public function flip() return $this->toBase()->flip(); } + /** + * Get the type of the entities being queued. + * + * @return string|null + */ + public function getQueueableClass() + { + if ($this->count() === 0) { + 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() + { + return $this->modelKeys(); + } + /** * Get a base Support collection instance from this collection. * diff --git a/src/Illuminate/Queue/SerializesModels.php b/src/Illuminate/Queue/SerializesModels.php index 9ad9cf79a6ec..9630f1022cc7 100644 --- a/src/Illuminate/Queue/SerializesModels.php +++ b/src/Illuminate/Queue/SerializesModels.php @@ -6,6 +6,8 @@ use ReflectionProperty; use Illuminate\Contracts\Queue\QueueableEntity; use Illuminate\Contracts\Database\ModelIdentifier; +use Illuminate\Contracts\Queue\QueueableCollection; +use Illuminate\Database\Eloquent\Collection as EloquentCollection; trait SerializesModels { @@ -51,8 +53,15 @@ public function __wakeup() */ protected function getSerializedPropertyValue($value) { - return $value instanceof QueueableEntity - ? new ModelIdentifier(get_class($value), $value->getQueueableId()) : $value; + if ($value instanceof QueueableCollection) { + return new ModelIdentifier($value->getQueueableClass(), $value->getQueueableIds()); + } + + if ($value instanceof QueueableEntity) { + return new ModelIdentifier(get_class($value), $value->getQueueableId()); + } + + return $value; } /** @@ -63,9 +72,31 @@ protected function getSerializedPropertyValue($value) */ protected function getRestoredPropertyValue($value) { - return $value instanceof ModelIdentifier - ? (new $value->class)->newQuery()->useWritePdo()->findOrFail($value->id) - : $value; + if (! $value instanceof ModelIdentifier) { + return $value; + } + + return is_array($value->id) + ? $this->restoreCollection($value) + : (new $value->class)->newQuery()->useWritePdo()->findOrFail($value->id); + } + + /** + * Restore a queueable collection instance. + * + * @param \Illuminate\Contracts\Database\ModelIdentifier $value + * @return \Illuminate\Database\Eloquent\Collection + */ + protected function restoreCollection($value) + { + if (! $value->class || count($value->id) === 0) { + return new EloquentCollection; + } + + $model = new $value->class; + + return $model->newQuery()->useWritePdo() + ->whereIn($model->getKeyName(), $value->id)->get(); } /** diff --git a/tests/Database/DatabaseEloquentCollectionTest.php b/tests/Database/DatabaseEloquentCollectionTest.php index 5432783b7fa7..94619a9f3e9d 100755 --- a/tests/Database/DatabaseEloquentCollectionTest.php +++ b/tests/Database/DatabaseEloquentCollectionTest.php @@ -263,6 +263,21 @@ public function testMakeVisibleRemovesHiddenAndIncludesVisible() $this->assertEquals([], $c[0]->getHidden()); $this->assertEquals(['visible', 'hidden'], $c[0]->getVisible()); } + + public function testQueueableCollectionImplementation() + { + $c = new Collection([new TestEloquentCollectionModel, new TestEloquentCollectionModel]); + $this->assertEquals(TestEloquentCollectionModel::class, $c->getQueueableClass()); + } + + /** + * @expectedException LogicException + */ + public function testQueueableCollectionImplementationThrowsExceptionOnMultipleModelTypes() + { + $c = new Collection([new TestEloquentCollectionModel, (object) ['id' => 'something']]); + $c->getQueueableClass(); + } } class TestEloquentCollectionModel extends Illuminate\Database\Eloquent\Model