Skip to content
This repository was archived by the owner on Nov 26, 2022. It is now read-only.

Commit c8d8b48

Browse files
author
Daniel Opitz
committed
Add advanced join clauses
1 parent 803fb90 commit c8d8b48

File tree

4 files changed

+148
-11
lines changed

4 files changed

+148
-11
lines changed

docs/readme.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,12 +250,19 @@ CROSS JOIN `posts` ON `users`.`id` = `posts`.`user_id`;
250250
#### Advanced Join Clauses
251251

252252
You may also specify more advanced join clauses.
253-
To get started, pass a Closure as the second argument into
254-
the join method. The Closure will receive a JoinClause object
255-
which allows you to specify constraints on the join clause:
253+
To get started, pass a RawExp as the second argument into
254+
the `joinRaw` and `leftJoinRaw` method.
256255

256+
```php
257+
$users = $this->select()
258+
->from('users AS u')
259+
->joinRaw('posts AS p', new RawExp('p.user_id=u.id AND u.enabled=1 OR p.published IS NULL'))
260+
->execute()
261+
->fetchAll();
257262
```
258-
Not supported.
263+
264+
```sql
265+
SELECT `id` FROM `users` AS `u` INNER JOIN `posts` AS `p` ON (p.user_id=u.id AND u.enabled=1 OR p.published IS NULL);
259266
```
260267

261268
### Unions

src/Database/SelectQuery.php

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class SelectQuery extends SelectQueryBuilder implements QueryInterface
1717
public function distinct(): self
1818
{
1919
$this->distinct = 'DISTINCT';
20+
2021
return $this;
2122
}
2223

@@ -28,6 +29,7 @@ public function distinct(): self
2829
public function distinctRow(): self
2930
{
3031
$this->distinct = 'DISTINCTROW';
32+
3133
return $this;
3234
}
3335

@@ -39,6 +41,7 @@ public function distinctRow(): self
3941
public function straightJoin(): self
4042
{
4143
$this->straightJoin = 'STRAIGHT_JOIN';
44+
4245
return $this;
4346
}
4447

@@ -50,6 +53,7 @@ public function straightJoin(): self
5053
public function highPriority(): self
5154
{
5255
$this->highPriority = 'HIGH_PRIORITY';
56+
5357
return $this;
5458
}
5559

@@ -61,6 +65,7 @@ public function highPriority(): self
6165
public function smallResult(): self
6266
{
6367
$this->resultSize = 'SQL_SMALL_RESULT';
68+
6469
return $this;
6570
}
6671

@@ -72,6 +77,7 @@ public function smallResult(): self
7277
public function bigResult(): self
7378
{
7479
$this->resultSize = 'SQL_BIG_RESULT';
80+
7581
return $this;
7682
}
7783

@@ -83,6 +89,7 @@ public function bigResult(): self
8389
public function bufferResult(): self
8490
{
8591
$this->bufferResult = 'SQL_BUFFER_RESULT';
92+
8693
return $this;
8794
}
8895

@@ -94,6 +101,7 @@ public function bufferResult(): self
94101
public function calcFoundRows(): self
95102
{
96103
$this->calcFoundRows = 'SQL_CALC_FOUND_ROWS';
104+
97105
return $this;
98106
}
99107

@@ -106,6 +114,7 @@ public function calcFoundRows(): self
106114
public function columns(...$columns): self
107115
{
108116
$this->columns = $columns;
117+
109118
return $this;
110119
}
111120

@@ -118,6 +127,7 @@ public function columns(...$columns): self
118127
public function alias(string $alias): self
119128
{
120129
$this->alias = $alias;
130+
121131
return $this;
122132
}
123133

@@ -130,6 +140,7 @@ public function alias(string $alias): self
130140
public function from(string $table): self
131141
{
132142
$this->from = $table;
143+
133144
return $this;
134145
}
135146

@@ -143,6 +154,7 @@ public function from(string $table): self
143154
public function union(SelectQuery $query): self
144155
{
145156
$this->union[] = ['', $query->build(false)];
157+
146158
return $this;
147159
}
148160

@@ -156,6 +168,7 @@ public function union(SelectQuery $query): self
156168
public function unionAll(SelectQuery $query): self
157169
{
158170
$this->union[] = ['ALL', $query->build(false)];
171+
159172
return $this;
160173
}
161174

@@ -169,6 +182,7 @@ public function unionAll(SelectQuery $query): self
169182
public function unionDistinct(SelectQuery $query): self
170183
{
171184
$this->union[] = ['DISTINCT', $query->build(false)];
185+
172186
return $this;
173187
}
174188

@@ -184,6 +198,7 @@ public function unionDistinct(SelectQuery $query): self
184198
public function join(string $table, string $leftField, string $comparison, $rightField): self
185199
{
186200
$this->join[] = ['inner', $table, $leftField, $comparison, $rightField];
201+
187202
return $this;
188203
}
189204

@@ -199,6 +214,7 @@ public function join(string $table, string $leftField, string $comparison, $righ
199214
public function leftJoin(string $table, string $leftField, string $comparison, $rightField): self
200215
{
201216
$this->join[] = ['left', $table, $leftField, $comparison, $rightField];
217+
202218
return $this;
203219
}
204220

@@ -214,6 +230,49 @@ public function leftJoin(string $table, string $leftField, string $comparison, $
214230
public function crossJoin(string $table, string $leftField, string $comparison, $rightField): self
215231
{
216232
$this->join[] = ['cross', $table, $leftField, $comparison, $rightField];
233+
234+
return $this;
235+
}
236+
237+
/**
238+
* Join with complex conditions.
239+
*
240+
* @param string $table Table name
241+
* @param RawExp $raw
242+
* @return self
243+
*/
244+
public function joinRaw(string $table, RawExp $raw): self
245+
{
246+
$this->join[] = ['inner', $table, $raw, null, null, null];
247+
248+
return $this;
249+
}
250+
251+
/**
252+
* Left join with complex conditions.
253+
*
254+
* @param string $table Table name
255+
* @param RawExp $raw
256+
* @return self
257+
*/
258+
public function leftJoinRaw(string $table, RawExp $raw): self
259+
{
260+
$this->join[] = ['left', $table, $raw, null, null, null];
261+
262+
return $this;
263+
}
264+
265+
/**
266+
* Cross join with complex conditions.
267+
*
268+
* @param string $table Table name
269+
* @param RawExp $raw
270+
* @return self
271+
*/
272+
public function crossJoinRaw(string $table, RawExp $raw): self
273+
{
274+
$this->join[] = ['cross', $table, $raw, null, null, null];
275+
217276
return $this;
218277
}
219278

@@ -228,6 +287,7 @@ public function crossJoin(string $table, string $leftField, string $comparison,
228287
public function where(...$conditions): self
229288
{
230289
$this->condition->where($conditions);
290+
231291
return $this;
232292
}
233293

@@ -242,6 +302,7 @@ public function where(...$conditions): self
242302
public function orWhere(...$conditions): self
243303
{
244304
$this->condition->orWhere($conditions);
305+
245306
return $this;
246307
}
247308

@@ -257,6 +318,7 @@ public function whereColumn(string $column, string $comparison, string $secondCo
257318
{
258319
$secondColumn = $this->quoter->quoteName($secondColumn);
259320
$this->condition->where([$column, $comparison, new RawExp($secondColumn)]);
321+
260322
return $this;
261323
}
262324

@@ -272,6 +334,7 @@ public function orWhereColumn(string $column, string $comparison, string $second
272334
{
273335
$secondColumn = $this->quoter->quoteName($secondColumn);
274336
$this->condition->orWhere([$column, $comparison, new RawExp($secondColumn)]);
337+
275338
return $this;
276339
}
277340

@@ -284,6 +347,7 @@ public function orWhereColumn(string $column, string $comparison, string $second
284347
public function orderBy(...$fields): self
285348
{
286349
$this->orderBy = $fields;
350+
287351
return $this;
288352
}
289353

@@ -296,6 +360,7 @@ public function orderBy(...$fields): self
296360
public function groupBy(...$fields): self
297361
{
298362
$this->groupBy = $fields;
363+
299364
return $this;
300365
}
301366

@@ -310,6 +375,7 @@ public function groupBy(...$fields): self
310375
public function having(...$conditions): self
311376
{
312377
$this->condition->having($conditions);
378+
313379
return $this;
314380
}
315381

@@ -324,6 +390,7 @@ public function having(...$conditions): self
324390
public function orHaving(...$conditions): self
325391
{
326392
$this->condition->orHaving($conditions);
393+
327394
return $this;
328395
}
329396

@@ -336,6 +403,7 @@ public function orHaving(...$conditions): self
336403
public function limit(float $rowCount): self
337404
{
338405
$this->limit = $rowCount;
406+
339407
return $this;
340408
}
341409

@@ -348,6 +416,7 @@ public function limit(float $rowCount): self
348416
public function offset(float $offset): self
349417
{
350418
$this->offset = $offset;
419+
351420
return $this;
352421
}
353422

src/Database/SelectQueryBuilder.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,13 @@ protected function getJoinSql(array $sql): array
208208
list($type, $table, $leftField, $operator, $rightField) = $item;
209209
$joinType = strtoupper($type) . ' JOIN';
210210
$table = $this->quoter->quoteName($table);
211-
$leftField = $this->quoter->quoteName($leftField);
212-
$rightField = $this->quoter->quoteName($rightField);
213-
$sql[] = sprintf('%s %s ON %s %s %s', $joinType, $table, $leftField, $operator, $rightField);
211+
if($leftField instanceof RawExp) {
212+
$sql[] = sprintf('%s %s ON (%s)', $joinType, $table, $leftField->getValue());
213+
} else {
214+
$leftField = $this->quoter->quoteName($leftField);
215+
$rightField = $this->quoter->quoteName($rightField);
216+
$sql[] = sprintf('%s %s ON %s %s %s', $joinType, $table, $leftField, $operator, $rightField);
217+
}
214218
}
215219
return $sql;
216220
}

tests/SelectQueryTest.php

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -574,16 +574,73 @@ public function testJoin()
574574
{
575575
$select = $this->select()
576576
->columns('id')
577-
->from('test')
578-
->join('users u', 'u.id', '=', 'test.user_id');
577+
->from('test AS t')
578+
->join('users AS u', 'u.id', '=', 'test.user_id');
579579
$this->assertInstanceOf(PDOStatement::class, $select->prepare());
580-
$this->assertSame("SELECT `id` FROM `test` INNER JOIN `users` `u` ON `u`.`id` = `test`.`user_id`;", $select->build());
580+
$this->assertSame("SELECT `id` FROM `test` AS `t` INNER JOIN `users` AS `u` ON `u`.`id` = `test`.`user_id`;", $select->build());
581581

582582
$select->join('table2 AS t2', 't2.id', '=', 'test.user_id');
583-
$expected = "SELECT `id` FROM `test` INNER JOIN `users` `u` ON `u`.`id` = `test`.`user_id` INNER JOIN `table2` AS `t2` ON `t2`.`id` = `test`.`user_id`;";
583+
$expected = "SELECT `id` FROM `test` AS `t` INNER JOIN `users` AS `u` ON `u`.`id` = `test`.`user_id` INNER JOIN `table2` AS `t2` ON `t2`.`id` = `test`.`user_id`;";
584584
$this->assertSame($expected, $select->build());
585585
}
586586

587+
/**
588+
* Test
589+
*
590+
* @covers ::joinRaw
591+
* @covers ::getJoinSql
592+
* @covers ::from
593+
* @covers ::prepare
594+
* @covers ::build
595+
*/
596+
public function testJoinRaw()
597+
{
598+
$select = $this->select()
599+
->columns('id')
600+
->from('test')
601+
->joinRaw('users u', new RawExp('t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c OR t2.b IS NULL'));
602+
$this->assertInstanceOf(PDOStatement::class, $select->prepare());
603+
$this->assertSame("SELECT `id` FROM `test` INNER JOIN `users` `u` ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c OR t2.b IS NULL);", $select->build());
604+
}
605+
606+
/**
607+
* Test
608+
*
609+
* @covers ::leftJoinRaw
610+
* @covers ::getJoinSql
611+
* @covers ::from
612+
* @covers ::prepare
613+
* @covers ::build
614+
*/
615+
public function testLeftJoinRaw()
616+
{
617+
$select = $this->select()
618+
->columns('id')
619+
->from('test')
620+
->leftJoinRaw('users u', new RawExp('t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c OR t2.b IS NULL'));
621+
$this->assertInstanceOf(PDOStatement::class, $select->prepare());
622+
$this->assertSame("SELECT `id` FROM `test` LEFT JOIN `users` `u` ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c OR t2.b IS NULL);", $select->build());
623+
}
624+
625+
/**
626+
* Test
627+
*
628+
* @covers ::crossJoinRaw
629+
* @covers ::getJoinSql
630+
* @covers ::from
631+
* @covers ::prepare
632+
* @covers ::build
633+
*/
634+
public function testCrossJoinRaw()
635+
{
636+
$select = $this->select()
637+
->columns('id')
638+
->from('test')
639+
->crossJoinRaw('users u', new RawExp('t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c OR t2.b IS NULL'));
640+
$this->assertInstanceOf(PDOStatement::class, $select->prepare());
641+
$this->assertSame("SELECT `id` FROM `test` CROSS JOIN `users` `u` ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c OR t2.b IS NULL);", $select->build());
642+
}
643+
587644
/**
588645
* Test
589646
*

0 commit comments

Comments
 (0)