Skip to content

Commit 2f88a30

Browse files
[10.x] Fix duplicate conditions on retrying SELECT calls under createOrFirst() (#48725)
* fix: duplicate conditions with `firstOrCreate` and `createOrFirst` * fix: missing mocks due to additional code
1 parent 1bae4cd commit 2f88a30

8 files changed

+17
-19
lines changed

src/Illuminate/Database/Eloquent/Builder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ public function firstOrNew(array $attributes = [], array $values = [])
563563
*/
564564
public function firstOrCreate(array $attributes = [], array $values = [])
565565
{
566-
if (! is_null($instance = $this->where($attributes)->first())) {
566+
if (! is_null($instance = (clone $this)->where($attributes)->first())) {
567567
return $instance;
568568
}
569569

src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ public function firstOrNew(array $attributes = [], array $values = [])
273273
*/
274274
public function firstOrCreate(array $attributes = [], array $values = [])
275275
{
276-
if (! is_null($instance = $this->where($attributes)->first())) {
276+
if (! is_null($instance = (clone $this)->where($attributes)->first())) {
277277
return $instance;
278278
}
279279

src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ public function firstOrNew(array $attributes = [], array $values = [])
235235
*/
236236
public function firstOrCreate(array $attributes = [], array $values = [])
237237
{
238-
if (is_null($instance = $this->where($attributes)->first())) {
238+
if (is_null($instance = (clone $this)->where($attributes)->first())) {
239239
$instance = $this->createOrFirst($attributes, $values);
240240
}
241241

tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void
165165

166166
$model->getConnection()
167167
->expects('select')
168-
// FIXME: duplicate conditions
169-
->with('select * from "table" where ("attr" = ?) and ("attr" = ?) limit 1', ['foo', 'foo'], false)
168+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false)
170169
->andReturn([[
171170
'id' => 123,
172171
'attr' => 'foo',
@@ -273,8 +272,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void
273272

274273
$model->getConnection()
275274
->expects('select')
276-
// FIXME: duplicate conditions
277-
->with('select * from "table" where ("attr" = ?) and ("attr" = ?) limit 1', ['foo', 'foo'], false)
275+
->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false)
278276
->andReturn([[
279277
'id' => 123,
280278
'attr' => 'foo',

tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void
177177

178178
$model->getConnection()
179179
->expects('select')
180-
// FIXME: duplicate conditions
181-
->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) and ("attr" = ?) limit 1', [123, 'foo', 'foo'], false)
180+
->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false)
182181
->andReturn([[
183182
'id' => 456,
184183
'parent_id' => 123,
@@ -290,8 +289,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void
290289

291290
$model->getConnection()
292291
->expects('select')
293-
// FIXME: duplicate conditions
294-
->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) and ("attr" = ?) limit 1', [123, 'foo', 'foo'], false)
292+
->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false)
295293
->andReturn([[
296294
'id' => 456,
297295
'parent_id' => 123,

tests/Database/DatabaseEloquentHasManyTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Illuminate\Database\Eloquent\Collection;
88
use Illuminate\Database\Eloquent\Model;
99
use Illuminate\Database\Eloquent\Relations\HasMany;
10+
use Illuminate\Database\Query\Builder as QueryBuilder;
1011
use Illuminate\Database\UniqueConstraintViolationException;
1112
use Mockery as m;
1213
use PHPUnit\Framework\TestCase;
@@ -343,7 +344,8 @@ public function testCreateManyCreatesARelatedModelForEachRecord()
343344

344345
protected function getRelation()
345346
{
346-
$builder = m::mock(Builder::class);
347+
$queryBuilder = m::mock(QueryBuilder::class);
348+
$builder = m::mock(Builder::class, [$queryBuilder]);
347349
$builder->shouldReceive('whereNotNull')->with('table.foreign_key');
348350
$builder->shouldReceive('where')->with('table.foreign_key', '=', 1);
349351
$related = m::mock(Model::class);

tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,9 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void
196196

197197
$parent->getConnection()
198198
->expects('select')
199-
// FIXME: duplicate conditions
200199
->with(
201-
'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) and ("attr" = ? and "val" = ?) limit 1',
202-
[123, 'foo', 'foo', 'bar'],
200+
'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ? and "val" = ?) limit 1',
201+
[123, 'foo', 'bar'],
203202
true,
204203
)
205204
->andReturn([[
@@ -334,10 +333,9 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void
334333

335334
$parent->getConnection()
336335
->expects('select')
337-
// FIXME: duplicate conditions
338336
->with(
339-
'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) and ("attr" = ? and "val" = ?) limit 1',
340-
[123, 'foo', 'foo', 'bar'],
337+
'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ? and "val" = ?) limit 1',
338+
[123, 'foo', 'bar'],
341339
true,
342340
)
343341
->andReturn([[

tests/Database/DatabaseEloquentMorphTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Illuminate\Database\Eloquent\Relations\MorphMany;
1010
use Illuminate\Database\Eloquent\Relations\MorphOne;
1111
use Illuminate\Database\Eloquent\Relations\Relation;
12+
use Illuminate\Database\Query\Builder as QueryBuilder;
1213
use Illuminate\Database\UniqueConstraintViolationException;
1314
use Mockery as m;
1415
use PHPUnit\Framework\TestCase;
@@ -443,7 +444,8 @@ public function testIsNotModelWithAnotherConnection()
443444

444445
protected function getOneRelation()
445446
{
446-
$builder = m::mock(Builder::class);
447+
$queryBuilder = m::mock(QueryBuilder::class);
448+
$builder = m::mock(Builder::class, [$queryBuilder]);
447449
$builder->shouldReceive('whereNotNull')->once()->with('table.morph_id');
448450
$builder->shouldReceive('where')->once()->with('table.morph_id', '=', 1);
449451
$related = m::mock(Model::class);

0 commit comments

Comments
 (0)