From bacdf91d40a30517d2dc2200fc1d3115854af57c Mon Sep 17 00:00:00 2001 From: Mark Beech Date: Mon, 30 Oct 2017 20:52:24 +0000 Subject: [PATCH 1/3] Use table aliases when calling self-referencing HasManyThrough relation --- .../Eloquent/Relations/HasManyThrough.php | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index 13f2b70a09fd..1675e9e82448 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -52,6 +52,13 @@ class HasManyThrough extends Relation */ protected $secondLocalKey; + /** + * The count of self joins. + * + * @var int + */ + protected static $selfJoinCount = 0; + /** * Create a new has many through relationship instance. * @@ -427,11 +434,46 @@ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, { $this->performJoin($query); + if ($parentQuery->getQuery()->from == $query->getQuery()->from) { + return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns); + } + return $query->select($columns)->whereColumn( $this->getExistenceCompareKey(), '=', $this->getQualifiedFirstKeyName() ); } + /** + * Add the constraints for a relationship query on the same table. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param \Illuminate\Database\Eloquent\Builder $parentQuery + * @param array|mixed $columns + * @return \Illuminate\Database\Eloquent\Builder + */ + public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*']) + { + $parentQuery->select($columns)->from( + $query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash() + ); + + $parentQuery->getModel()->setTable($hash); + + return $query->whereColumn( + $hash.'.'.$query->getModel()->getKeyName(), '=', $this->getQualifiedFirstKeyName() + ); + } + + /** + * Get a relationship join table hash. + * + * @return string + */ + public function getRelationCountHash() + { + return 'laravel_reserved_'.static::$selfJoinCount++; + } + /** * Get the key for comparing against the parent key in "has" query. * From 021efba0dec024365a97ac93fb9f11263b88bd78 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 31 Oct 2017 11:03:19 +0200 Subject: [PATCH 2/3] alias the sub query table --- .../Eloquent/Relations/HasManyThrough.php | 20 +++++++++++-------- .../Database/EloquentHasManyThroughTest.php | 2 ++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index 1675e9e82448..d59d62bc11d6 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -432,12 +432,12 @@ protected function shouldSelect(array $columns = ['*']) */ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) { - $this->performJoin($query); - if ($parentQuery->getQuery()->from == $query->getQuery()->from) { return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns); } + $this->performJoin($query); + return $query->select($columns)->whereColumn( $this->getExistenceCompareKey(), '=', $this->getQualifiedFirstKeyName() ); @@ -453,14 +453,18 @@ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, */ public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*']) { - $parentQuery->select($columns)->from( - $query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash() - ); + $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash()); - $parentQuery->getModel()->setTable($hash); + $query->join($this->throughParent->getTable(), $this->getQualifiedParentKeyName(), '=', $hash.'.'.$this->secondLocalKey); - return $query->whereColumn( - $hash.'.'.$query->getModel()->getKeyName(), '=', $this->getQualifiedFirstKeyName() + if ($this->throughParentSoftDeletes()) { + $query->whereNull($this->throughParent->getQualifiedDeletedAtColumn()); + } + + $query->getModel()->setTable($hash); + + return $query->select($columns)->whereColumn( + $parentQuery->getQuery()->from.'.'.$query->getModel()->getKeyName(), '=', $this->getQualifiedFirstKeyName() ); } diff --git a/tests/Integration/Database/EloquentHasManyThroughTest.php b/tests/Integration/Database/EloquentHasManyThroughTest.php index 7ea296bf284c..a0522df89a8c 100644 --- a/tests/Integration/Database/EloquentHasManyThroughTest.php +++ b/tests/Integration/Database/EloquentHasManyThroughTest.php @@ -55,7 +55,9 @@ public function basic_create_and_retrieve() $notMember = User::create(['name' => str_random()]); + $this->assertEquals([$mate1->id, $mate2->id], $user->teamMates->pluck('id')->toArray()); + $this->assertEquals([$user->id], User::has('teamMates')->pluck('id')->toArray()); } } From 7296a58b811c2b7144ba1817ada362b15c1f4330 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 31 Oct 2017 11:13:58 +0200 Subject: [PATCH 3/3] fix style --- tests/Integration/Database/EloquentHasManyThroughTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Integration/Database/EloquentHasManyThroughTest.php b/tests/Integration/Database/EloquentHasManyThroughTest.php index a0522df89a8c..1bf63db74db8 100644 --- a/tests/Integration/Database/EloquentHasManyThroughTest.php +++ b/tests/Integration/Database/EloquentHasManyThroughTest.php @@ -55,7 +55,6 @@ public function basic_create_and_retrieve() $notMember = User::create(['name' => str_random()]); - $this->assertEquals([$mate1->id, $mate2->id], $user->teamMates->pluck('id')->toArray()); $this->assertEquals([$user->id], User::has('teamMates')->pluck('id')->toArray()); }