Skip to content

Commit e6c7011

Browse files
authored
Merge pull request #11 from kirschbaum-development/feature/relation-alias
Feature: Table aliases
2 parents 5e9fb72 + 2db2b77 commit e6c7011

File tree

11 files changed

+497
-42
lines changed

11 files changed

+497
-42
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,24 @@ User::joinRelationship('posts', function ($join) {
118118

119119
When using model scopes inside a join clause, you **can't** type hint the `$query` parameter in your scope. Also, keep in mind you are inside a join, so you are limited to use only conditions supported by joins.
120120

121+
**Using aliases**
122+
123+
Sometimes, you are going to need to use table aliases on your joins because you are joining the same table more than once. One option to accomplish this is to use the `joinRelationshipUsingAlias` method.
124+
125+
```php
126+
Post::joinRelationshipUsingAlias('category.parent')->get();
127+
```
128+
129+
Or, you can also call the `as` function inside the join callback.
130+
131+
```php
132+
Post::joinRelationship('category.parent', [
133+
'parent' => function ($join) {
134+
$join->as('category_parent');
135+
},
136+
])->get()
137+
```
138+
121139
**Select * from table**
122140

123141
When making joins, using `select * from ...` can be dangerous as fields with the same name between the parent and the joined tables could conflict. Thinking on that, if you call the `joinRelationship` method without previously selecting any specific columns, Eloquent Power Joins will automatically include that for you. For instance, take a look at the following examples:

src/Mixins/JoinRelationship.php

Lines changed: 100 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
use Closure;
66
use Illuminate\Database\Eloquent\Model;
7+
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
8+
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
79
use Illuminate\Database\Query\Builder as QueryBuilder;
810
use Illuminate\Support\Str;
911
use KirschbaumDevelopment\EloquentJoins\PowerJoinClause;
@@ -17,6 +19,13 @@ class JoinRelationship
1719
*/
1820
public static $joinRelationshipCache = [];
1921

22+
/**
23+
* Cache to not join the same relationship twice.
24+
*
25+
* @var array
26+
*/
27+
public static $powerJoinAliasesCache = [];
28+
2029
/**
2130
* Join method map.
2231
*/
@@ -31,30 +40,62 @@ class JoinRelationship
3140
*/
3241
public function joinRelationship()
3342
{
34-
return function ($relationName, $callback = null, $joinType = 'join') {
43+
return function ($relationName, $callback = null, $joinType = 'join', $useAlias = false) {
3544
$joinType = JoinRelationship::$joinMethodsMap[$joinType] ?? $joinType;
3645

3746
if (is_null($this->getSelect())) {
3847
$this->select(sprintf('%s.*', $this->getModel()->getTable()));
3948
}
4049

4150
if (Str::contains($relationName, '.')) {
42-
return $this->joinNestedRelationship($relationName, $callback, $joinType);
51+
return $this->joinNestedRelationship($relationName, $callback, $joinType, $useAlias);
4352
}
4453

4554
if ($this->relationshipAlreadyJoined($relationName)) {
4655
return $this;
4756
}
4857

4958
$relation = $this->getModel()->{$relationName}();
50-
$relation->performJoinForEloquentPowerJoins($this, $joinType, $callback);
59+
$alias = $useAlias ? $this->generateAliasForRelationship($relation, $relationName) : null;
60+
$relation->performJoinForEloquentPowerJoins($this, $joinType, $callback, $alias);
5161

5262
$this->markRelationshipAsAlreadyJoined($relationName);
63+
$this->clearPowerJoinCaches();
5364

5465
return $this;
5566
};
5667
}
5768

69+
/**
70+
* Join the relationship(s) using table aliases.
71+
*/
72+
public function joinRelationshipUsingAlias()
73+
{
74+
return function ($relationName, $callback = null) {
75+
return $this->joinRelationship($relationName, $callback, 'join', true);
76+
};
77+
}
78+
79+
/**
80+
* Left join the relationship(s) using table aliases.
81+
*/
82+
public function leftJoinRelationshipUsingAlias()
83+
{
84+
return function ($relationName, $callback = null) {
85+
return $this->joinRelationship($relationName, $callback, 'leftJoin', true);
86+
};
87+
}
88+
89+
/**
90+
* Right join the relationship(s) using table aliases.
91+
*/
92+
public function rightJoinRelationshipUsingAlias()
93+
{
94+
return function ($relationName, $callback = null) {
95+
return $this->joinRelationship($relationName, $callback, 'rightJoin', true);
96+
};
97+
}
98+
5899
public function joinRelation()
59100
{
60101
return function ($relationName, $callback = null, $joinType = 'join') {
@@ -64,29 +105,29 @@ public function joinRelation()
64105

65106
public function leftJoinRelationship()
66107
{
67-
return function ($relation, $callback = null) {
68-
return $this->joinRelationship($relation, $callback, 'leftJoin');
108+
return function ($relation, $callback = null, $useAlias = false) {
109+
return $this->joinRelationship($relation, $callback, 'leftJoin', $useAlias);
69110
};
70111
}
71112

72113
public function leftJoinRelation()
73114
{
74-
return function ($relation, $callback = null) {
75-
return $this->joinRelationship($relation, $callback, 'leftJoin');
115+
return function ($relation, $callback = null, $useAlias = false) {
116+
return $this->joinRelationship($relation, $callback, 'leftJoin', $useAlias);
76117
};
77118
}
78119

79120
public function rightJoinRelationship()
80121
{
81-
return function ($relation, $callback = null) {
82-
return $this->joinRelationship($relation, $callback, 'rightJoin');
122+
return function ($relation, $callback = null, $useAlias = false) {
123+
return $this->joinRelationship($relation, $callback, 'rightJoin', $useAlias);
83124
};
84125
}
85126

86127
public function rightJoinRelation()
87128
{
88-
return function ($relation, $callback = null) {
89-
return $this->joinRelationship($relation, $callback, 'rightJoin');
129+
return function ($relation, $callback = null, $useAlias = false) {
130+
return $this->joinRelationship($relation, $callback, 'rightJoin', $useAlias);
90131
};
91132
}
92133

@@ -95,15 +136,20 @@ public function rightJoinRelation()
95136
*/
96137
public function joinNestedRelationship()
97138
{
98-
return function ($relations, $callback = null, $joinType = 'join') {
139+
return function ($relations, $callback = null, $joinType = 'join', $useAlias = false) {
99140
$relations = explode('.', $relations);
100141
$latestRelation = null;
101142

102143
foreach ($relations as $index => $relationName) {
103144
$currentModel = $latestRelation ? $latestRelation->getModel() : $this->getModel();
104145
$relation = $currentModel->{$relationName}();
146+
$alias = $useAlias ? $this->generateAliasForRelationship($relation, $relationName) : null;
105147
$relationCallback = null;
106148

149+
if ($useAlias) {
150+
$this->cachePowerJoinAlias($relation->getModel(), $alias);
151+
}
152+
107153
if ($callback && is_array($callback) && isset($callback[$relationName])) {
108154
$relationCallback = $callback[$relationName];
109155
}
@@ -116,13 +162,16 @@ public function joinNestedRelationship()
116162
$relation->performJoinForEloquentPowerJoins(
117163
$this,
118164
$joinType,
119-
$relationCallback
165+
$relationCallback,
166+
$alias
120167
);
121168

122169
$latestRelation = $relation;
123170
$this->markRelationshipAsAlreadyJoined($relationName);
124171
}
125172

173+
$this->clearPowerJoinCaches();
174+
126175
return $this;
127176
};
128177
}
@@ -217,7 +266,7 @@ public function orderByMaxUsingJoins()
217266
public function relationshipAlreadyJoined()
218267
{
219268
return function ($relation) {
220-
return isset(JoinRelationship::$joinRelationshipCache[spl_object_hash($this)][$relation]);
269+
return isset(JoinRelationship::$joinRelationshipCache[spl_object_id($this)][$relation]);
221270
};
222271
}
223272

@@ -227,7 +276,7 @@ public function relationshipAlreadyJoined()
227276
public function markRelationshipAsAlreadyJoined()
228277
{
229278
return function ($relation) {
230-
JoinRelationship::$joinRelationshipCache[spl_object_hash($this)][$relation] = true;
279+
JoinRelationship::$joinRelationshipCache[spl_object_id($this)][$relation] = true;
231280
};
232281
}
233282

@@ -292,4 +341,40 @@ public function newPowerJoinClause()
292341
return new PowerJoinClause($parentQuery, $type, $table, $model);
293342
};
294343
}
344+
345+
public function generateAliasForRelationship()
346+
{
347+
return function ($relation, $relationName) {
348+
if ($relation instanceof BelongsToMany || $relation instanceof HasManyThrough) {
349+
return [
350+
md5($relationName.'table1'.time()),
351+
md5($relationName.'table2'.time()),
352+
];
353+
}
354+
355+
return md5($relationName.time());
356+
};
357+
}
358+
359+
/**
360+
* Cache the power join table alias used for the power join.
361+
*/
362+
public function cachePowerJoinAlias()
363+
{
364+
return function ($model, $alias) {
365+
JoinRelationship::$powerJoinAliasesCache[spl_object_id($model)] = $alias;
366+
};
367+
}
368+
369+
/**
370+
* Clear the power join caches.
371+
*/
372+
public function clearPowerJoinCaches()
373+
{
374+
return function () {
375+
JoinRelationship::$powerJoinAliasesCache = [];
376+
377+
return $this;
378+
};
379+
}
295380
}

0 commit comments

Comments
 (0)