From ac1eeccd9df91f908d15d1d560971f53fcefeafd Mon Sep 17 00:00:00 2001 From: Kacper Pruszynski Date: Sun, 7 Apr 2024 21:46:29 +0200 Subject: [PATCH] [11.x] Remove scopes from BelongsToMany relation (#50945) --- .../Eloquent/Relations/BelongsToMany.php | 2 +- ...aseEloquentBelongsToManyExpressionTest.php | 26 +++++++++++++++++++ ...tBelongsToManyWithCastedAttributesTest.php | 5 ++-- ...BelongsToManyWithDefaultAttributesTest.php | 7 ++--- ...oquentBelongsToManyWithoutTouchingTest.php | 5 +++- .../DatabaseEloquentMorphToManyTest.php | 13 +++++----- 6 files changed, 44 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 70290c4da557..26ca5b44a8b9 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -1563,7 +1563,7 @@ public function getPivotColumns() */ public function qualifyPivotColumn($column) { - if ($this->getGrammar()->isExpression($column)) { + if ($this->query->getQuery()->getGrammar()->isExpression($column)) { return $column; } diff --git a/tests/Database/DatabaseEloquentBelongsToManyExpressionTest.php b/tests/Database/DatabaseEloquentBelongsToManyExpressionTest.php index 647757bb3ff3..53e09cfb82f6 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyExpressionTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyExpressionTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Database; +use Exception; use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Database\Eloquent\Model as Eloquent; use Illuminate\Database\Eloquent\Relations\MorphToMany; @@ -52,6 +53,31 @@ public function testQualifiedColumnExpression(): void $this->assertEquals(3, $tags->first()->getKey()); } + public function testGlobalScopesAreAppliedToBelongsToManyRelation(): void + { + $this->seedData(); + $post = DatabaseEloquentBelongsToManyExpressionTestTestPost::query()->firstOrFail(); + DatabaseEloquentBelongsToManyExpressionTestTestTag::addGlobalScope( + 'default', + static fn () => throw new Exception('Default global scope.') + ); + + $this->expectExceptionMessage('Default global scope.'); + $post->tags()->get(); + } + + public function testGlobalScopesCanBeRemovedFromBelongsToManyRelation(): void + { + $this->seedData(); + $post = DatabaseEloquentBelongsToManyExpressionTestTestPost::query()->firstOrFail(); + DatabaseEloquentBelongsToManyExpressionTestTestTag::addGlobalScope( + 'default', + static fn () => throw new Exception('Default global scope.') + ); + + $this->assertNotEmpty($post->tags()->withoutGlobalScopes()->get()); + } + /** * Setup the database schema. * diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php index 96c3e24b2a48..d0e917a4583b 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyWithCastedAttributesTest.php @@ -9,6 +9,7 @@ use Illuminate\Database\Query\Grammars\Grammar; use Mockery as m; use PHPUnit\Framework\TestCase; +use stdClass; class DatabaseEloquentBelongsToManyWithCastedAttributesTest extends TestCase { @@ -64,8 +65,8 @@ protected function getRelation() $builder->shouldReceive('getModel')->andReturn($related); $related->shouldReceive('qualifyColumn'); $builder->shouldReceive('join', 'where'); - $builder->shouldReceive('getGrammar')->andReturn( - m::mock(Grammar::class, ['isExpression' => false]) + $builder->shouldReceive('getQuery')->andReturn( + m::mock(stdClass::class, ['getGrammar' => m::mock(Grammar::class, ['isExpression' => false])]) ); return new BelongsToMany( diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithDefaultAttributesTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithDefaultAttributesTest.php index 90174ce3e771..1910dce8c1c3 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyWithDefaultAttributesTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyWithDefaultAttributesTest.php @@ -31,8 +31,7 @@ public function testWithPivotValueMethodSetsDefaultArgumentsForInsertion() $query = m::mock(stdClass::class); $query->shouldReceive('from')->once()->with('club_user')->andReturn($query); $query->shouldReceive('insert')->once()->with([['club_id' => 1, 'user_id' => 1, 'is_admin' => 1]])->andReturn(true); - $relation->getQuery()->shouldReceive('getQuery')->andReturn($mockQueryBuilder = m::mock(stdClass::class)); - $mockQueryBuilder->shouldReceive('newQuery')->once()->andReturn($query); + $relation->getQuery()->getQuery()->shouldReceive('newQuery')->once()->andReturn($query); $relation->attach(1); } @@ -56,7 +55,9 @@ public function getRelationArguments() $builder->shouldReceive('join')->once()->with('club_user', 'users.id', '=', 'club_user.user_id'); $builder->shouldReceive('where')->once()->with('club_user.club_id', '=', 1); $builder->shouldReceive('where')->once()->with('club_user.is_admin', '=', 1, 'and'); - $builder->shouldReceive('getGrammar')->andReturn(m::mock(Grammar::class, ['isExpression' => false])); + + $builder->shouldReceive('getQuery')->andReturn($mockQueryBuilder = m::mock(stdClass::class)); + $mockQueryBuilder->shouldReceive('getGrammar')->andReturn(m::mock(Grammar::class, ['isExpression' => false])); return [$builder, $parent, 'club_user', 'club_id', 'user_id', 'id', 'id', null, false]; } diff --git a/tests/Database/DatabaseEloquentBelongsToManyWithoutTouchingTest.php b/tests/Database/DatabaseEloquentBelongsToManyWithoutTouchingTest.php index 6eafa9668671..7b6ad7b510f8 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyWithoutTouchingTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyWithoutTouchingTest.php @@ -10,6 +10,7 @@ use Illuminate\Database\Query\Grammars\Grammar; use Mockery as m; use PHPUnit\Framework\TestCase; +use stdClass; class DatabaseEloquentBelongsToManyWithoutTouchingTest extends TestCase { @@ -32,7 +33,9 @@ public function testItWillNotTouchRelatedModelsWhenUpdatingChild(): void $parent->shouldReceive('getAttribute')->with('id')->andReturn(1); $builder->shouldReceive('getModel')->andReturn($related); $builder->shouldReceive('where'); - $builder->shouldReceive('getGrammar')->andReturn(m::mock(Grammar::class, ['isExpression' => false])); + $builder->shouldReceive('getQuery')->andReturn( + m::mock(stdClass::class, ['getGrammar' => m::mock(Grammar::class, ['isExpression' => false])]) + ); $relation = new BelongsToMany($builder, $parent, 'article_users', 'user_id', 'article_id', 'id', 'id'); $builder->shouldReceive('update')->never(); diff --git a/tests/Database/DatabaseEloquentMorphToManyTest.php b/tests/Database/DatabaseEloquentMorphToManyTest.php index 36f4466ee943..b5f747133d87 100644 --- a/tests/Database/DatabaseEloquentMorphToManyTest.php +++ b/tests/Database/DatabaseEloquentMorphToManyTest.php @@ -33,8 +33,7 @@ public function testAttachInsertsPivotTableRecord(): void $query = m::mock(stdClass::class); $query->shouldReceive('from')->once()->with('taggables')->andReturn($query); $query->shouldReceive('insert')->once()->with([['taggable_id' => 1, 'taggable_type' => get_class($relation->getParent()), 'tag_id' => 2, 'foo' => 'bar']])->andReturn(true); - $relation->getQuery()->shouldReceive('getQuery')->andReturn($mockQueryBuilder = m::mock(stdClass::class)); - $mockQueryBuilder->shouldReceive('newQuery')->once()->andReturn($query); + $relation->getQuery()->getQuery()->shouldReceive('newQuery')->once()->andReturn($query); $relation->expects($this->once())->method('touchIfTouching'); $relation->attach(2, ['foo' => 'bar']); @@ -49,8 +48,7 @@ public function testDetachRemovesPivotTableRecord(): void $query->shouldReceive('where')->once()->with('taggable_type', get_class($relation->getParent()))->andReturn($query); $query->shouldReceive('whereIn')->once()->with('taggables.tag_id', [1, 2, 3]); $query->shouldReceive('delete')->once()->andReturn(true); - $relation->getQuery()->shouldReceive('getQuery')->andReturn($mockQueryBuilder = m::mock(stdClass::class)); - $mockQueryBuilder->shouldReceive('newQuery')->once()->andReturn($query); + $relation->getQuery()->getQuery()->shouldReceive('newQuery')->once()->andReturn($query); $relation->expects($this->once())->method('touchIfTouching'); $this->assertTrue($relation->detach([1, 2, 3])); @@ -65,8 +63,7 @@ public function testDetachMethodClearsAllPivotRecordsWhenNoIDsAreGiven(): void $query->shouldReceive('where')->once()->with('taggable_type', get_class($relation->getParent()))->andReturn($query); $query->shouldReceive('whereIn')->never(); $query->shouldReceive('delete')->once()->andReturn(true); - $relation->getQuery()->shouldReceive('getQuery')->andReturn($mockQueryBuilder = m::mock(stdClass::class)); - $mockQueryBuilder->shouldReceive('newQuery')->once()->andReturn($query); + $relation->getQuery()->getQuery()->shouldReceive('newQuery')->once()->andReturn($query); $relation->expects($this->once())->method('touchIfTouching'); $this->assertTrue($relation->detach()); @@ -130,7 +127,9 @@ public function getRelationArguments(): array $grammar = m::mock(Grammar::class); $grammar->shouldReceive('isExpression')->with(m::type(Expression::class))->andReturnTrue(); $grammar->shouldReceive('isExpression')->with(m::type('string'))->andReturnFalse(); - $builder->shouldReceive('getGrammar')->andReturn($grammar); + $builder->shouldReceive('getQuery')->andReturn( + m::mock(stdClass::class, ['getGrammar' => $grammar]) + ); return [$builder, $parent, 'taggable', 'taggables', 'taggable_id', 'tag_id', 'id', 'id', 'relation_name', false]; }