From 9ac4664edb7fa577943100456ceec8abe8a81d84 Mon Sep 17 00:00:00 2001 From: Salah Alkhwlani Date: Wed, 28 Feb 2018 16:47:08 +0300 Subject: [PATCH] access to parent model from withDefault closure (#23334) 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);