diff --git a/src/FakeJoinCallback.php b/src/FakeJoinCallback.php new file mode 100644 index 0000000..fac5583 --- /dev/null +++ b/src/FakeJoinCallback.php @@ -0,0 +1,22 @@ +alias; + } + + public function __call($name, $arguments) + { + if ($name === 'as') { + $this->alias = $arguments[0]; + } + + return $this; + } +} diff --git a/src/PowerJoins.php b/src/PowerJoins.php index b8bc64d..d3dbc13 100644 --- a/src/PowerJoins.php +++ b/src/PowerJoins.php @@ -6,6 +6,7 @@ use Illuminate\Support\Str; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Query\Expression; +use Kirschbaum\PowerJoins\FakeJoinCallback; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasManyThrough; @@ -53,15 +54,19 @@ public function scopeJoinRelationship(Builder $query, $relationName, $callback = return; } - $relationQuery = $query->getModel()->{$relationName}()->getQuery(); - $relationJoinCache = "{$relationQuery->getModel()->getTable()}.{$relationName}"; + $relation = $query->getModel()->{$relationName}(); + $relationQuery = $relation->getQuery(); + $alias = $this->getAliasName($useAlias, $relation, $relationName, $callback); + $aliasString = is_array($alias) ? implode('.', $alias) : $alias; + + $relationJoinCache = $alias + ? "{$aliasString}.{$relationQuery->getModel()->getTable()}.{$relationName}" + : "{$relationQuery->getModel()->getTable()}.{$relationName}"; if ($this->relationshipAlreadyJoined($relationJoinCache)) { return; } - $relation = $query->getModel()->{$relationName}(); - $alias = $useAlias ? $this->generateAliasForRelationship($relation, $relationName) : null; $relation->performJoinForEloquentPowerJoins($query, $joinType, $callback, $alias, $disableExtraConditions); $this->markRelationshipAsAlreadyJoined($relationJoinCache); @@ -200,7 +205,6 @@ public function scopeOrderByPowerJoins(Builder $query, $sort, $direction = 'asc' ->orderBy(sprintf('%s_aggregation', $latestRelationshipName), $direction); } else { if ($column instanceof Expression) { - // dd($column); $query->orderBy($column, $direction); } else { $query->orderBy( @@ -405,4 +409,25 @@ protected function formatJoinCallback(string $relationName, $callback) return $callback; } + + /** + * Get the join alias name from all the different options. + */ + protected function getAliasName($useAlias, $relation, $relationName, $callback) + { + if ($callback) { + if (is_callable($callback)) { + $fakeJoinCallback = new FakeJoinCallback(); + $callback($fakeJoinCallback); + + if ($fakeJoinCallback->getAlias()) { + return $fakeJoinCallback->getAlias(); + } + } + } + + return $useAlias + ? $this->generateAliasForRelationship($relation, $relationName) + : null; + } } diff --git a/tests/JoinRelationshipTest.php b/tests/JoinRelationshipTest.php index 471a371..226b723 100644 --- a/tests/JoinRelationshipTest.php +++ b/tests/JoinRelationshipTest.php @@ -576,4 +576,42 @@ public function test_nested_join_with_aliases() ]) ->get(); } + + /** @test */ + public function test_join_same_relationship_using_named_alias() + { + $query = Post::query() + ->where('posts.id', '>', 10) + ->joinRelationship('category', function ($join) { + $join->as('category_1'); + }) + ->joinRelationship('category', function ($join) { + $join->as('category_2'); + }) + ->toSql(); + + $this->assertStringContainsString('inner join "categories" as "category_1" on "posts"."category_id" = "category_1"."id"', $query); + $this->assertStringContainsString('inner join "categories" as "category_2" on "posts"."category_id" = "category_2"."id"', $query); + } + + /** @test */ + public function test_join_same_nested_relationship_using_named_alias() + { + $this->markTestSkipped('Still to implement this using the array syntax'); + + $query = Post::query() + ->where('posts.id', '>', 10) + ->joinRelationship('category.parent', [ + 'category' => fn ($join) => $join->as('category_alias_1'), + 'parent' => fn ($join) => $join->as('parent_alias_1'), + ]) + ->joinRelationship('category.parent', [ + 'category' => fn ($join) => $join->as('category_alias_2'), + 'parent' => fn ($join) => $join->as('parent_alias_2'), + ]) + ->toSql(); + + $this->assertStringContainsString('inner join "categories" as "category_alias_1" on "posts"."category_id" = "category_alias_1"."id"', $query); + $this->assertStringContainsString('inner join "categories" as "category_alias_2" on "posts"."category_id" = "category_alias_2"."id"', $query); + } }