Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0fe9031

Browse files
committed
Merge pull request laravel#7079 from bryceray1121/forceRelationQueryWithNoScopes
[4.2] Ignore parent global scopes when relation grabs its parent's query builder in order to avoid loop
2 parents 91236c9 + cbb2fa4 commit 0fe9031

3 files changed

Lines changed: 45 additions & 3 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ public function relatedUpdatedAt()
266266
*/
267267
public function wrap($value)
268268
{
269-
return $this->parent->getQuery()->getGrammar()->wrap($value);
269+
return $this->parent->newQueryWithoutScopes()->getQuery()->getGrammar()->wrap($value);
270270
}
271271

272272
/**

tests/Database/DatabaseEloquentHasOneTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public function testRelationCountQueryCanBeBuilt()
102102
$query->shouldReceive('select')->once()->with(m::type('Illuminate\Database\Query\Expression'));
103103
$relation->getParent()->shouldReceive('getTable')->andReturn('table');
104104
$query->shouldReceive('where')->once()->with('table.foreign_key', '=', m::type('Illuminate\Database\Query\Expression'));
105-
$relation->getParent()->shouldReceive('getQuery')->andReturn($parentQuery = m::mock('StdClass'));
105+
$relation->getQuery()->shouldReceive('getQuery')->andReturn($parentQuery = m::mock('StdClass'));
106106
$parentQuery->shouldReceive('getGrammar')->once()->andReturn($grammar = m::mock('StdClass'));
107107
$grammar->shouldReceive('wrap')->once()->with('table.id');
108108

@@ -120,6 +120,7 @@ protected function getRelation()
120120
$parent->shouldReceive('getAttribute')->with('id')->andReturn(1);
121121
$parent->shouldReceive('getCreatedAtColumn')->andReturn('created_at');
122122
$parent->shouldReceive('getUpdatedAtColumn')->andReturn('updated_at');
123+
$parent->shouldReceive('newQueryWithoutScopes')->andReturn($builder);
123124
return new HasOne($builder, $parent, 'table.foreign_key', 'id');
124125
}
125126

tests/Database/DatabaseEloquentRelationTest.php

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,42 @@ public function testTouchMethodUpdatesRelatedTimestamps()
3737
$relation->touch();
3838
}
3939

40+
/**
41+
* Testing to ensure loop does not occur during relational queries in global scopes
42+
*
43+
* Executing parent model's global scopes could result in an infinite loop when the
44+
* parent model's global scope utilizes a relation in a query like has or whereHas
45+
*/
46+
public function testDonNotRunParentModelGlobalScopes()
47+
{
48+
/** @var Mockery\MockInterface $parent */
49+
$eloquentBuilder = m::mock('Illuminate\Database\Eloquent\Builder');
50+
$queryBuilder = m::mock('Illuminate\Database\Query\Builder');
51+
$parent = m::mock('EloquentRelationResetModelStub')->makePartial();
52+
$grammar = m::mock('\Illuminate\Database\Grammar');
53+
54+
$eloquentBuilder->shouldReceive('getModel')->andReturn($related = m::mock('StdClass'));
55+
$eloquentBuilder->shouldReceive('getQuery')->andReturn($queryBuilder);
56+
$queryBuilder->shouldReceive('getGrammar')->andReturn($grammar);
57+
$grammar->shouldReceive('wrap');
58+
$parent->shouldReceive('newQueryWithoutScopes')->andReturn($eloquentBuilder);
59+
60+
//Test Condition
61+
$parent->shouldReceive('applyGlobalScopes')->andReturn($eloquentBuilder)->never();
62+
63+
$relation = new EloquentRelationStub($eloquentBuilder, $parent);
64+
$relation->wrap('test');
65+
}
66+
4067
}
4168

42-
class EloquentRelationResetModelStub extends Illuminate\Database\Eloquent\Model {}
69+
class EloquentRelationResetModelStub extends Illuminate\Database\Eloquent\Model {
70+
//Override method call which would normally go through __call()
71+
public function getQuery()
72+
{
73+
return $this->newQuery()->getQuery();
74+
}
75+
}
4376

4477

4578
class EloquentRelationResetStub extends Illuminate\Database\Eloquent\Builder {
@@ -51,3 +84,11 @@ public function getModel() { return new EloquentRelationResetModelStub; }
5184
class EloquentRelationQueryStub extends Illuminate\Database\Query\Builder {
5285
public function __construct() {}
5386
}
87+
88+
class EloquentRelationStub extends \Illuminate\Database\Eloquent\Relations\Relation {
89+
public function addConstraints() {}
90+
public function addEagerConstraints(array $models) {}
91+
public function initRelation(array $models, $relation) {}
92+
public function match(array $models, \Illuminate\Database\Eloquent\Collection $results, $relation) {}
93+
public function getResults() {}
94+
}

0 commit comments

Comments
 (0)