From 6d4b995774af4cff72529f31deb0b0d16156f451 Mon Sep 17 00:00:00 2001 From: Salah Alkhwlani Date: Wed, 28 Feb 2018 16:10:42 +0300 Subject: [PATCH] access to parent model from withDefault closure Sometimes, you may wish to return default value of relations using advanced logic and condition base of parent values This already support but not work for lazy eager loading for example ```php // Message model public function user() { return $this->belongsTo(User::class)->withDefault(function ($user) { $user->name = $this->getAttribute('username'); $user->email = $this->getAttribute('email'); return $user; }); } // single record. $message = Message::first(); $message->user->name; // return username from message model as except. // but i we try access to user info use lazy eager loading $messages = Message::with('user')->get(); $messages->first()->user->name; // return null ``` This PR support pass parent model to closure to make sure the parent model available in all cases. ```php public function user() { return $this->belongsTo(User::class)->withDefault(function ($user, $parent) { $user->name = $parent->getAttribute('username'); $user->email = $parent->getAttribute('email'); return $user; }); } ``` thanks --- .../Concerns/SupportsDefaultModels.php | 2 +- tests/Database/DatabaseEloquentHasOneTest.php | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/SupportsDefaultModels.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/SupportsDefaultModels.php index 00efd507edb4..74e758f58571 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/SupportsDefaultModels.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/SupportsDefaultModels.php @@ -51,7 +51,7 @@ protected function getDefaultFor(Model $parent) $instance = $this->newRelatedInstanceFor($parent); if (is_callable($this->withDefault)) { - return call_user_func($this->withDefault, $instance) ?: $instance; + return call_user_func($this->withDefault, $instance, $parent) ?: $instance; } if (is_array($this->withDefault)) { diff --git a/tests/Database/DatabaseEloquentHasOneTest.php b/tests/Database/DatabaseEloquentHasOneTest.php index d345be740e08..44910f720bbe 100755 --- a/tests/Database/DatabaseEloquentHasOneTest.php +++ b/tests/Database/DatabaseEloquentHasOneTest.php @@ -54,6 +54,25 @@ public function testHasOneWithDynamicDefault() $this->assertSame(1, $newModel->getAttribute('foreign_key')); } + public function testHasOneWithDynamicDefaultUseParentModel() + { + $relation = $this->getRelation()->withDefault(function ($newModel, $parentModel) { + $newModel->username = $parentModel->username; + }); + + $this->builder->shouldReceive('first')->once()->andReturnNull(); + + $newModel = new EloquentHasOneModelStub; + + $this->related->shouldReceive('newInstance')->once()->andReturn($newModel); + + $this->assertSame($newModel, $relation->getResults()); + + $this->assertSame('taylor', $newModel->username); + + $this->assertSame(1, $newModel->getAttribute('foreign_key')); + } + public function testHasOneWithArrayDefault() { $attributes = ['username' => 'taylor']; @@ -191,6 +210,7 @@ protected function getRelation() $this->builder->shouldReceive('getModel')->andReturn($this->related); $this->parent = m::mock('Illuminate\Database\Eloquent\Model'); $this->parent->shouldReceive('getAttribute')->with('id')->andReturn(1); + $this->parent->shouldReceive('getAttribute')->with('username')->andReturn('taylor'); $this->parent->shouldReceive('getCreatedAtColumn')->andReturn('created_at'); $this->parent->shouldReceive('getUpdatedAtColumn')->andReturn('updated_at'); $this->parent->shouldReceive('newQueryWithoutScopes')->andReturn($this->builder);