diff --git a/src/Illuminate/Contracts/Database/ModelIdentifier.php b/src/Illuminate/Contracts/Database/ModelIdentifier.php index 587044a8dab3..cdd4b9cc91a2 100644 --- a/src/Illuminate/Contracts/Database/ModelIdentifier.php +++ b/src/Illuminate/Contracts/Database/ModelIdentifier.php @@ -27,18 +27,27 @@ class ModelIdentifier */ public $connection; + /** + * The relationships loaded on the model. + * + * @var array + */ + public $relations; + /** * Create a new model identifier. * * @param string $class * @param mixed $id * @param mixed $connection + * @param array $relations * @return void */ - public function __construct($class, $id, $connection) + public function __construct($class, $id, $connection, $relations) { $this->id = $id; $this->class = $class; $this->connection = $connection; + $this->relations = $relations; } } diff --git a/src/Illuminate/Contracts/Queue/QueueableCollection.php b/src/Illuminate/Contracts/Queue/QueueableCollection.php index 0331b814f04b..a26fa57ab4d3 100644 --- a/src/Illuminate/Contracts/Queue/QueueableCollection.php +++ b/src/Illuminate/Contracts/Queue/QueueableCollection.php @@ -24,4 +24,11 @@ public function getQueueableIds(); * @return string|null */ public function getQueueableConnection(); + + /** + * Get the relationships of the entities being queued. + * + * @return array + */ + public function getQueueableRelations(); } diff --git a/src/Illuminate/Contracts/Queue/QueueableEntity.php b/src/Illuminate/Contracts/Queue/QueueableEntity.php index 00e28f8a070f..2388e1e2183c 100644 --- a/src/Illuminate/Contracts/Queue/QueueableEntity.php +++ b/src/Illuminate/Contracts/Queue/QueueableEntity.php @@ -17,4 +17,11 @@ public function getQueueableId(); * @return string|null */ public function getQueueableConnection(); + + /** + * Get the relationships for the entity. + * + * @return array + */ + public function getQueueableRelations(); } diff --git a/src/Illuminate/Database/Eloquent/Collection.php b/src/Illuminate/Database/Eloquent/Collection.php index 62e25c6dabd9..914e480f49ae 100755 --- a/src/Illuminate/Database/Eloquent/Collection.php +++ b/src/Illuminate/Database/Eloquent/Collection.php @@ -419,4 +419,14 @@ public function getQueueableConnection() return $connection; } + + /** + * Get the relationships of the entities being queued. + * + * @return array + */ + public function getQueueableRelations() + { + return $this->isNotEmpty() ? $this->first()->getRelations() : []; + } } diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index bee9bf0e47fb..43a5b93c0b13 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -13,6 +13,7 @@ use Illuminate\Contracts\Routing\UrlRoutable; use Illuminate\Contracts\Queue\QueueableEntity; use Illuminate\Database\Eloquent\Relations\Pivot; +use Illuminate\Contracts\Queue\QueueableCollection; use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\ConnectionResolverInterface as Resolver; @@ -1250,6 +1251,37 @@ public function getQueueableConnection() return $this->getConnectionName(); } + /** + * Get the queueable relationships for the entity. + * + * @return array + */ + public function getQueueableRelations() + { + $relations = []; + + foreach ($this->getRelations() as $key => $relation){ + + $relations[] = $key; + + if ($relation instanceof QueueableCollection) + { + foreach($relation->getQueueableRelations() as $collectionKey => $collectionValue){ + $relations[] = $key . '.' . $collectionKey; + } + } + + if ($relation instanceof QueueableEntity) + { + foreach($relation->getQueueableRelations() as $entityKey => $entityValue){ + $relations[] = $key . '.' . $entityValue; + } + } + } + + return $relations; + } + /** * Get the value of the model's route key. * diff --git a/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php b/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php index 6bb677aee8ac..e90a0b8ea3b3 100644 --- a/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php +++ b/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php @@ -21,7 +21,8 @@ protected function getSerializedPropertyValue($value) return new ModelIdentifier( $value->getQueueableClass(), $value->getQueueableIds(), - $value->getQueueableConnection() + $value->getQueueableConnection(), + $value->getQueueableRelations() ); } @@ -29,7 +30,8 @@ protected function getSerializedPropertyValue($value) return new ModelIdentifier( get_class($value), $value->getQueueableId(), - $value->getQueueableConnection() + $value->getQueueableConnection(), + $value->getQueueableRelations() ); } @@ -50,8 +52,7 @@ protected function getRestoredPropertyValue($value) return is_array($value->id) ? $this->restoreCollection($value) - : $this->getQueryForModelRestoration((new $value->class)->setConnection($value->connection)) - ->useWritePdo()->findOrFail($value->id); + : $this->restoreModel($value); } /** @@ -72,6 +73,18 @@ protected function restoreCollection($value) ->whereIn($model->getQualifiedKeyName(), $value->id)->get(); } + /** + * @param \Illuminate\Contracts\Database\ModelIdentifier $value + * @return \Illuminate\Database\Eloquent\Model + */ + public function restoreModel($value) + { + $model = $this->getQueryForModelRestoration((new $value->class)->setConnection($value->connection)) + ->useWritePdo()->findOrFail($value->id); + + return $model->load($value->relations); + } + /** * Get the query for restoration. * diff --git a/tests/Integration/Queue/ModelSerializationTest.php b/tests/Integration/Queue/ModelSerializationTest.php index 0949b683f78c..1cfe302bd7c3 100644 --- a/tests/Integration/Queue/ModelSerializationTest.php +++ b/tests/Integration/Queue/ModelSerializationTest.php @@ -43,6 +43,21 @@ public function setUp() $table->increments('id'); $table->string('email'); }); + + Schema::create('orders', function ($table) { + $table->increments('id'); + }); + + Schema::create('lines', function ($table) { + $table->increments('id'); + $table->unsignedInteger('order_id'); + $table->unsignedInteger('product_id'); + }); + + Schema::create('products', function ($table) { + $table->increments('id'); + + }); } /** @@ -126,6 +141,50 @@ public function it_fails_if_models_on_multi_connections() unserialize($serialized); } + + /** + * @test + */ + public function it_reloads_relationships() + { + $order = Order::create(); + + $product1 = Product::create(); + $product2 = Product::create(); + + Line::create(['order_id' => $order->id, 'product_id' => $product1->id]); + Line::create(['order_id' => $order->id, 'product_id' => $product2->id]); + Line::create(['order_id' => $order->id, 'product_id' => $product1->id]); + + $order->load('lines'); + + $serialized = serialize(new ModelRelationSerializationTestClass($order)); + $unSerialized = unserialize($serialized); + + $this->assertEquals($unSerialized->order->getRelations(), $order->getRelations()); + } + + /** + * @test + */ + public function it_reloads_nested_relationships() + { + $order = Order::create(); + + $product1 = Product::create(); + $product2 = Product::create(); + + Line::create(['order_id' => $order->id, 'product_id' => $product1->id]); + Line::create(['order_id' => $order->id, 'product_id' => $product2->id]); + Line::create(['order_id' => $order->id, 'product_id' => $product1->id]); + + $order->load('lines', 'lines.product'); + + $nestedSerialized = serialize(new ModelRelationSerializationTestClass($order)); + $nestedUnSerialized = unserialize($nestedSerialized); + + $this->assertEquals($nestedUnSerialized->order->getRelations(), $order->getRelations()); + } } class ModelSerializationTestUser extends Model @@ -135,6 +194,34 @@ class ModelSerializationTestUser extends Model public $timestamps = false; } +class Order extends Model +{ + public $guarded = ['id']; + public $timestamps = false; + + public function lines() + { + return $this->hasMany(Line::class); + } +} + +class Line extends Model +{ + public $guarded = ['id']; + public $timestamps = false; + + public function product() + { + return $this->belongsTo(Product::class); + } +} + +class Product extends Model +{ + public $guarded = ['id']; + public $timestamps = false; +} + class ModelSerializationTestClass { use \Illuminate\Queue\SerializesModels; @@ -146,3 +233,15 @@ public function __construct($user) $this->user = $user; } } + +class ModelRelationSerializationTestClass +{ + use \Illuminate\Queue\SerializesModels; + + public $order; + + public function __construct($order) + { + $this->order = $order; + } +} diff --git a/tests/Queue/QueueSyncQueueTest.php b/tests/Queue/QueueSyncQueueTest.php index 8d533c8b197f..cbbac59c9c4a 100755 --- a/tests/Queue/QueueSyncQueueTest.php +++ b/tests/Queue/QueueSyncQueueTest.php @@ -61,6 +61,11 @@ public function getQueueableConnection() { // } + + public function getQueueableRelations() + { + // + } } class SyncQueueTestHandler