Skip to content

Commit

Permalink
[10.x] Revert from using createOrFirst in other *OrCreate methods (
Browse files Browse the repository at this point in the history
…laravel#48531)

* Avoid using createOrFirst inside other *OrCreate methods

* Revert "[10.x] Make the `updateOrCreate` methods in relations use `firstOrCreate` behind the scenes (laravel#48213)"

This reverts commit e1ae507.

* Revert "Enhancing `updateOrCreate()` to Use `firstOrCreate()` (laravel#48160)"

This reverts commit 80e0262.

* Fix mocked firstOrCreate tests
  • Loading branch information
tonysm authored Sep 25, 2023
1 parent 283326d commit 408a3e3
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 44 deletions.
8 changes: 3 additions & 5 deletions src/Illuminate/Database/Eloquent/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ public function firstOrCreate(array $attributes = [], array $values = [])
return $instance;
}

return $this->createOrFirst($attributes, $values);
return $this->create(array_merge($attributes, $values));
}

/**
Expand Down Expand Up @@ -595,10 +595,8 @@ public function createOrFirst(array $attributes = [], array $values = [])
*/
public function updateOrCreate(array $attributes, array $values = [])
{
return tap($this->firstOrCreate($attributes, $values), function ($instance) use ($values) {
if (! $instance->wasRecentlyCreated) {
$instance->fill($values)->save();
}
return tap($this->firstOrNew($attributes), function ($instance) use ($values) {
$instance->fill($values)->save();
});
}

Expand Down
20 changes: 13 additions & 7 deletions src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ public function firstOrCreate(array $attributes = [], array $values = [], array
{
if (is_null($instance = (clone $this)->where($attributes)->first())) {
if (is_null($instance = $this->related->where($attributes)->first())) {
$instance = $this->createOrFirst($attributes, $values, $joining, $touch);
$instance = $this->create(array_merge($attributes, $values), $joining, $touch);
} else {
try {
$this->getQuery()->withSavepointIfNeeded(fn () => $this->attach($instance, $joining, $touch));
Expand Down Expand Up @@ -672,13 +672,19 @@ public function createOrFirst(array $attributes = [], array $values = [], array
*/
public function updateOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true)
{
return tap($this->firstOrCreate($attributes, $values, $joining, $touch), function ($instance) use ($values) {
if (! $instance->wasRecentlyCreated) {
$instance->fill($values);

$instance->save(['touch' => false]);
if (is_null($instance = (clone $this)->where($attributes)->first())) {
if (is_null($instance = $this->related->where($attributes)->first())) {
return $this->create(array_merge($attributes, $values), $joining, $touch);
} else {
$this->attach($instance, $joining, $touch);
}
});
}

$instance->fill($values);

$instance->save(['touch' => false]);

return $instance;
}

/**
Expand Down
10 changes: 5 additions & 5 deletions src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,11 @@ public function firstOrNew(array $attributes)
*/
public function updateOrCreate(array $attributes, array $values = [])
{
return tap($this->firstOrCreate($attributes, $values), function ($instance) use ($values) {
if (! $instance->wasRecentlyCreated) {
$instance->fill($values)->save();
}
});
$instance = $this->firstOrNew($attributes);

$instance->fill($values)->save();

return $instance;
}

/**
Expand Down
10 changes: 5 additions & 5 deletions src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public function firstOrNew(array $attributes = [], array $values = [])
public function firstOrCreate(array $attributes = [], array $values = [])
{
if (is_null($instance = $this->where($attributes)->first())) {
$instance = $this->createOrFirst($attributes, $values);
$instance = $this->create(array_merge($attributes, $values));
}

return $instance;
Expand Down Expand Up @@ -267,10 +267,10 @@ public function createOrFirst(array $attributes = [], array $values = [])
*/
public function updateOrCreate(array $attributes, array $values = [])
{
return tap($this->firstOrCreate($attributes, $values), function ($instance) use ($values) {
if (! $instance->wasRecentlyCreated) {
$instance->fill($values)->save();
}
return tap($this->firstOrNew($attributes), function ($instance) use ($values) {
$instance->fill($values);

$instance->save();
});
}

Expand Down
14 changes: 3 additions & 11 deletions tests/Database/DatabaseEloquentHasManyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ public function testFirstOrCreateMethodCreatesNewModelWithForeignKeySet()
$relation = $this->getRelation();
$relation->getQuery()->shouldReceive('where')->once()->with(['foo'])->andReturn($relation->getQuery());
$relation->getQuery()->shouldReceive('first')->once()->with()->andReturn(null);
$relation->getQuery()->shouldReceive('withSavepointIfNeeded')->once()->andReturnUsing(fn ($scope) => $scope());
$model = $this->expectCreatedModel($relation, ['foo']);

$this->assertEquals($model, $relation->firstOrCreate(['foo']));
Expand All @@ -166,7 +165,6 @@ public function testFirstOrCreateMethodWithValuesCreatesNewModelWithForeignKeySe
$relation = $this->getRelation();
$relation->getQuery()->shouldReceive('where')->once()->with(['foo' => 'bar'])->andReturn($relation->getQuery());
$relation->getQuery()->shouldReceive('first')->once()->with()->andReturn(null);
$relation->getQuery()->shouldReceive('withSavepointIfNeeded')->once()->andReturnUsing(fn ($scope) => $scope());
$model = $this->expectCreatedModel($relation, ['foo' => 'bar', 'baz' => 'qux']);

$this->assertEquals($model, $relation->firstOrCreate(['foo' => 'bar'], ['baz' => 'qux']));
Expand Down Expand Up @@ -227,9 +225,7 @@ public function testUpdateOrCreateMethodFindsFirstModelAndUpdates()
$relation->getQuery()->shouldReceive('where')->once()->with(['foo'])->andReturn($relation->getQuery());
$relation->getQuery()->shouldReceive('first')->once()->with()->andReturn($model = m::mock(stdClass::class));
$relation->getRelated()->shouldReceive('newInstance')->never();

$model->wasRecentlyCreated = false;
$model->shouldReceive('fill')->once()->with(['bar'])->andReturn($model);
$model->shouldReceive('fill')->once()->with(['bar']);
$model->shouldReceive('save')->once();

$this->assertInstanceOf(stdClass::class, $relation->updateOrCreate(['foo'], ['bar']));
Expand All @@ -238,15 +234,11 @@ public function testUpdateOrCreateMethodFindsFirstModelAndUpdates()
public function testUpdateOrCreateMethodCreatesNewModelWithForeignKeySet()
{
$relation = $this->getRelation();
$relation->getQuery()->shouldReceive('withSavepointIfNeeded')->once()->andReturnUsing(function ($scope) {
return $scope();
});
$relation->getQuery()->shouldReceive('where')->once()->with(['foo'])->andReturn($relation->getQuery());
$relation->getQuery()->shouldReceive('first')->once()->with()->andReturn(null);
$relation->getRelated()->shouldReceive('newInstance')->once()->with(['foo', 'bar'])->andReturn($model = m::mock(Model::class));

$model->wasRecentlyCreated = true;
$relation->getRelated()->shouldReceive('newInstance')->once()->with(['foo'])->andReturn($model = m::mock(Model::class));
$model->shouldReceive('save')->once()->andReturn(true);
$model->shouldReceive('fill')->once()->with(['bar']);
$model->shouldReceive('setAttribute')->once()->with('foreign_key', 1);

$this->assertInstanceOf(Model::class, $relation->updateOrCreate(['foo'], ['bar']));
Expand Down
14 changes: 3 additions & 11 deletions tests/Database/DatabaseEloquentMorphTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ public function testFirstOrCreateMethodCreatesNewMorphModel()
$relation = $this->getOneRelation();
$relation->getQuery()->shouldReceive('where')->once()->with(['foo'])->andReturn($relation->getQuery());
$relation->getQuery()->shouldReceive('first')->once()->with()->andReturn(null);
$relation->getQuery()->shouldReceive('withSavepointIfNeeded')->once()->andReturnUsing(fn ($scope) => $scope());
$relation->getRelated()->shouldReceive('newInstance')->once()->with(['foo'])->andReturn($model = m::mock(Model::class));
$model->shouldReceive('setAttribute')->once()->with('morph_id', 1);
$model->shouldReceive('setAttribute')->once()->with('morph_type', get_class($relation->getParent()));
Expand All @@ -209,7 +208,6 @@ public function testFirstOrCreateMethodWithValuesCreatesNewMorphModel()
$relation = $this->getOneRelation();
$relation->getQuery()->shouldReceive('where')->once()->with(['foo' => 'bar'])->andReturn($relation->getQuery());
$relation->getQuery()->shouldReceive('first')->once()->with()->andReturn(null);
$relation->getQuery()->shouldReceive('withSavepointIfNeeded')->once()->andReturnUsing(fn ($scope) => $scope());
$relation->getRelated()->shouldReceive('newInstance')->once()->with(['foo' => 'bar', 'baz' => 'qux'])->andReturn($model = m::mock(Model::class));
$model->shouldReceive('setAttribute')->once()->with('morph_id', 1);
$model->shouldReceive('setAttribute')->once()->with('morph_type', get_class($relation->getParent()));
Expand Down Expand Up @@ -302,10 +300,8 @@ public function testUpdateOrCreateMethodFindsFirstModelAndUpdates()
$relation->getQuery()->shouldReceive('where')->once()->with(['foo'])->andReturn($relation->getQuery());
$relation->getQuery()->shouldReceive('first')->once()->with()->andReturn($model = m::mock(Model::class));
$relation->getRelated()->shouldReceive('newInstance')->never();

$model->wasRecentlyCreated = false;
$model->shouldReceive('setAttribute')->never();
$model->shouldReceive('fill')->once()->with(['bar'])->andReturn($model);
$model->shouldReceive('fill')->once()->with(['bar']);
$model->shouldReceive('save')->once();

$this->assertInstanceOf(Model::class, $relation->updateOrCreate(['foo'], ['bar']));
Expand All @@ -314,17 +310,13 @@ public function testUpdateOrCreateMethodFindsFirstModelAndUpdates()
public function testUpdateOrCreateMethodCreatesNewMorphModel()
{
$relation = $this->getOneRelation();
$relation->getQuery()->shouldReceive('withSavepointIfNeeded')->once()->andReturnUsing(function ($scope) {
return $scope();
});
$relation->getQuery()->shouldReceive('where')->once()->with(['foo'])->andReturn($relation->getQuery());
$relation->getQuery()->shouldReceive('first')->once()->with()->andReturn(null);
$relation->getRelated()->shouldReceive('newInstance')->once()->with(['foo', 'bar'])->andReturn($model = m::mock(Model::class));

$model->wasRecentlyCreated = true;
$relation->getRelated()->shouldReceive('newInstance')->once()->with(['foo'])->andReturn($model = m::mock(Model::class));
$model->shouldReceive('setAttribute')->once()->with('morph_id', 1);
$model->shouldReceive('setAttribute')->once()->with('morph_type', get_class($relation->getParent()));
$model->shouldReceive('save')->once()->andReturn(true);
$model->shouldReceive('fill')->once()->with(['bar']);

$this->assertInstanceOf(Model::class, $relation->updateOrCreate(['foo'], ['bar']));
}
Expand Down

0 comments on commit 408a3e3

Please sign in to comment.