Skip to content

Commit 684fc68

Browse files
committed
Foreign table joins by relation name alias
1 parent 5754d28 commit 684fc68

File tree

5 files changed

+119
-42
lines changed

5 files changed

+119
-42
lines changed

CHANGELOG

+10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
CHANGELOG
22
=========
33

4+
2014-11-13, v1.0.1
5+
------------------
6+
7+
* Foreign table joins by relation name alias:
8+
```
9+
Model::include('street')->where('street.id', '=', $id);
10+
Model::include('street.type')->orderBy('type.id', 'asc');
11+
```
12+
13+
414
2014-11-12, v1.0.0
515
------------------
616

README.md

+47-12
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,48 @@ Model::with('other')->references('other')->orderBy('other.title', 'asc')->get();
99
# this will make one sql-query with left join of 'other' relation
1010
# result object will be the same object
1111

12-
Model::includes('other', 'another')->where('other.title', '=', 'my title')->get();
13-
# will be the same as Model::with('other', 'another')->references('other', 'another')->…
12+
Model::includes('first', 'second')->where('first.title', '=', 'my title')->get();
13+
# will be the same as Model::with('first', 'second')->references('first', 'second')->…
1414

15-
Model::with('other')->orderBy('field', 'asc')->get();
15+
Model::with('foreign')->orderBy('field', 'asc')->get();
1616
# this will work with default behaviour (perform 2 sql-queries)
1717
```
1818

19+
### Example
20+
21+
#### New Behaviour
22+
23+
```php
24+
StreetImage::includes('street')->first()
25+
```
26+
27+
will perform the following sql-query:
28+
29+
```sql
30+
select
31+
`street`.`<…>` as `__f__street.<…>`,
32+
`street_images`.*
33+
from
34+
`street_images`
35+
left join
36+
`streets` as `street` on `street`.`id` = `street_images`.`street_id`
37+
order by `sort` asc
38+
limit 1
39+
```
40+
41+
#### Default Behaviour
42+
43+
```php
44+
StreetImage::with('street')->first()
45+
```
46+
47+
will perform the following sql-queries:
48+
49+
```sql
50+
select `street_images`.* from `street_images` order by `sort` asc limit 1
51+
select `streets`.* from `streets` where `streets`.`id` in (?) order by `title` asc
52+
```
53+
1954
### Object Structure
2055

2156
You will get the same object if you will use `includes()` method. For example:
@@ -64,20 +99,20 @@ StreetImage::includes('street.type', 'street.district')->first();
6499
will perform a following sql-query (*<…> will be replaced with all table columns*):
65100

66101
```sql
67-
select
68-
`streets`.`<…>` as `_foreign_street.<…>`,
69-
`street_types`.`<…>` as `_foreign_street._foreign_type.<…>`,
70-
`districts`.`<…>` as `_foreign_street._foreign_district.<…>`,
71-
`street_images`.*
102+
select
103+
`street`.`<…>` as `__f__street.<…>`,
104+
`type`.`<…>` as `__f__street.__f__type.<…>`,
105+
`district`.`<…>` as `__f__street.__f__district.<…>`,
106+
`street_images`.*
72107
from
73108
`street_images`
74109
left join
75-
`streets` on `streets`.`id` = `street_images`.`street_id`
110+
`streets` as `street` on `street`.`id` = `street_images`.`street_id`
76111
left join
77-
`street_types` on `street_types`.`id` = `streets`.`street_type_id`
112+
`street_types` as `type` on `type`.`id` = `street`.`street_type_id`
78113
left join
79-
`districts` on `districts`.`id` = `streets`.`district_id`
80-
order by `sort` asc
114+
`districts` as `district` on `district`.`id` = `street`.`district_id`
115+
order by `sort` asc
81116
limit 1
82117
```
83118
instead of performing 4 sql-queries by default Eloquent behaviour:

composer.json

+25-19
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
11
{
2-
"name": "sleeping-owl/with-join",
3-
"description": "Package to convert Eloquent BelongsTo subqueries into one query with left join.",
4-
"keywords": ["laravel", "activerecord", "eloquent", "with", "join"],
2+
"name": "sleeping-owl/with-join",
3+
"description": "Package to convert Eloquent BelongsTo subqueries into one query with left join.",
4+
"keywords": [
5+
"laravel",
6+
"activerecord",
7+
"eloquent",
8+
"with",
9+
"join"
10+
],
511
"license": "MIT",
6-
"authors": [
7-
{
8-
"name": "Sleeping Owl",
9-
"email": "owl.sleeping@yahoo.com"
10-
}
11-
],
12-
"require": {
13-
"php": ">=5.4.0",
14-
"illuminate/support": "4.2.*"
15-
},
16-
"autoload": {
17-
"psr-0": {
18-
"SleepingOwl\\WithJoin": "src/"
19-
}
20-
},
21-
"minimum-stability": "stable"
12+
"authors": [
13+
{
14+
"name": "Sleeping Owl",
15+
"email": "owl.sleeping@yahoo.com"
16+
}
17+
],
18+
"require": {
19+
"php": ">=5.4.0",
20+
"illuminate/support": "4.2.*"
21+
},
22+
"autoload": {
23+
"psr-0": {
24+
"SleepingOwl\\WithJoin": "src/"
25+
}
26+
},
27+
"minimum-stability": "stable"
2228
}

src/SleepingOwl/WithJoin/WithJoinEloquentBuilder.php

+36-10
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@
33
use Cache;
44
use Illuminate\Database\Eloquent\Builder;
55
use Illuminate\Database\Eloquent\Relations\BelongsTo;
6+
use Illuminate\Database\Eloquent\Relations\Relation;
67

78
class WithJoinEloquentBuilder extends Builder
89
{
10+
11+
/**
12+
* @var string
13+
*/
14+
public static $prefix = '__f__';
15+
916
/**
1017
* @var array
1118
*/
@@ -46,8 +53,9 @@ protected function isNestedRelation($relation)
4653

4754
/**
4855
* @param $name
56+
* @param Relation $relation
4957
*/
50-
protected function addNestedRelations($name, BelongsTo $relation)
58+
protected function addNestedRelations($name, Relation $relation)
5159
{
5260
$nestedRelations = $this->nestedRelations($name);
5361
if (count($nestedRelations) <= 0) return;
@@ -56,23 +64,41 @@ protected function addNestedRelations($name, BelongsTo $relation)
5664
foreach ($nestedRelations as $nestedName => $nestedConstraints)
5765
{
5866
$relation = $class->$nestedName();
59-
$this->addJoinToQuery($nestedName, $class->getTable(), $relation, $name . '._foreign_');
67+
$this->addJoinToQuery($nestedName, $name, $relation, $name . '.' . static::$prefix);
6068
}
6169
}
6270

6371
/**
64-
* @param $name
65-
* @param BelongsTo $relation
72+
* @param $joinTableAlias
73+
* @param $currentTableAlias
74+
* @param BelongsTo|Relation $relation
75+
* @param string $columnsPrefix
6676
*/
67-
protected function addJoinToQuery($name, $currentTable, BelongsTo $relation, $prefix = '')
77+
protected function addJoinToQuery($joinTableAlias, $currentTableAlias, Relation $relation, $columnsPrefix = '')
6878
{
69-
$foreignTable = $relation->getRelated()->getTable();
70-
$columns = $this->getColumns($foreignTable);
71-
$this->query->leftJoin($foreignTable, $foreignTable . '.' . $relation->getOtherKey(), '=', $currentTable . '.' . $relation->getForeignKey());
79+
$joinTableName = $relation->getRelated()->getTable();
80+
81+
$joinTable = implode(' as ', [
82+
$joinTableName,
83+
$joinTableAlias
84+
]);
85+
$joinLeftCondition = implode('.', [
86+
$joinTableAlias,
87+
$relation->getOtherKey()
88+
]);
89+
$joinRightCondition = implode('.', [
90+
$currentTableAlias,
91+
$relation->getForeignKey()
92+
]);
93+
94+
$this->query->leftJoin($joinTable, $joinLeftCondition, '=', $joinRightCondition);
95+
96+
$columns = $this->getColumns($joinTableName);
97+
$prefix = static::$prefix . $columnsPrefix . $joinTableAlias . '.';
7298
foreach ($columns as $column)
7399
{
74-
$this->selectFromQuery($foreignTable, $column, '_foreign_' . $prefix . $name . '.' . $column);
75-
};
100+
$this->selectFromQuery($joinTableAlias, $column, $prefix . $column);
101+
}
76102
}
77103

78104
/**

src/SleepingOwl/WithJoin/WithJoinTrait.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ trait WithJoinTrait
1313
public function newFromBuilder($attributes = [])
1414
{
1515
$attributes = (array) $attributes;
16-
$prefix = '_foreign_';
16+
$prefix = WithJoinEloquentBuilder::$prefix;
1717
$foreignData = [];
1818
foreach ($attributes as $key => $value)
1919
{

0 commit comments

Comments
 (0)