diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 9ca41981484d..d0e140566473 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -2087,9 +2087,42 @@ public function fresh($with = []) return; } - return $this->setKeysForSelectQuery($this->newQueryWithoutScopes()) + return $this->freshUsingQuery( + $this->newQueryWithoutScopes(), + is_string($with) ? func_get_args() : $with + ); + } + + /** + * Reload a fresh model instance from the database while locking it for updating. + * + * @param array|string $with + * @return static|null + */ + public function freshForUpdate($with = []) + { + if (! $this->exists) { + return; + } + + return $this->freshUsingQuery( + $this->newQueryWithoutScopes()->lockForUpdate(), + is_string($with) ? func_get_args() : $with + ); + } + + /** + * Reload a fresh model instance using the given query. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param array $with + * @return static|null + */ + protected function freshUsingQuery(Builder $query, array $with = []) + { + return $this->setKeysForSelectQuery($query) ->useWritePdo() - ->with(is_string($with) ? func_get_args() : $with) + ->with($with) ->first(); } diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index 5ab5cdc92c38..258695e5ae2c 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -2190,6 +2190,42 @@ public function testFreshMethodOnModel() $this->assertNull($freshNotStoredUser); } + public function testFreshForUpdateMethodOnModel() + { + $user = EloquentTestUser::create([ + 'id' => 1, + 'email' => 'taylorotwell@gmail.com', + ]); + + EloquentTestPost::create([ + 'user_id' => 1, + 'name' => 'First Post', + ]); + + EloquentTestUser::whereKey($user)->update(['name' => 'Abigail Otwell']); + + $fresh = EloquentTestUser::resolveConnection()->transaction(function () use ($user) { + return $user->freshForUpdate(); + }); + + $this->assertNotSame($user, $fresh); + $this->assertSame('Abigail Otwell', $fresh->name); + $this->assertNull($user->name); + $this->assertFalse($fresh->relationLoaded('posts')); + + $freshWithRelations = EloquentTestUser::resolveConnection()->transaction(function () use ($user) { + return $user->freshForUpdate('posts'); + }); + + $this->assertNotSame($user, $freshWithRelations); + $this->assertSame('Abigail Otwell', $freshWithRelations->name); + $this->assertTrue($freshWithRelations->relationLoaded('posts')); + $this->assertCount(1, $freshWithRelations->posts); + + $notStoredUser = new EloquentTestUser(['id' => 2]); + $this->assertNull($notStoredUser->freshForUpdate()); + } + public function testFreshMethodOnCollection() { EloquentTestUser::insert([['id' => 1, 'email' => 'taylorotwell@gmail.com'], ['id' => 2, 'email' => 'taylorotwell@gmail.com']]); diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index caea7c2fd716..77191ad63232 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -745,6 +745,29 @@ public function testRefreshForUpdateUsesLockForUpdate() $this->assertSame('Abigail', $model->getOriginal('name')); } + public function testFreshForUpdateUsesLockForUpdate() + { + $model = Mockery::mock(EloquentModelStub::class.'[newQueryWithoutScopes]'); + $model->exists = true; + $model->setRawAttributes(['id' => 1, 'name' => 'Taylor'], true); + + $freshModel = new EloquentModelStub; + $freshModel->setRawAttributes(['id' => 1, 'name' => 'Abigail']); + + $query = Mockery::mock(Builder::class); + $model->expects('newQueryWithoutScopes')->once()->andReturn($query); + $query->expects('lockForUpdate')->once()->andReturnSelf(); + $query->expects('where')->once()->with('id', '=', 1)->andReturnSelf(); + $query->expects('useWritePdo')->once()->andReturnSelf(); + $query->expects('with')->once()->with([])->andReturnSelf(); + $query->expects('first')->once()->andReturn($freshModel); + + $result = $model->freshForUpdate(); + + $this->assertSame($freshModel, $result); + $this->assertSame('Taylor', $model->name); + } + public function testDestroyMethodCallsQueryBuilderCorrectly() { EloquentModelDestroyStub::destroy(1, 2, 3);