Skip to content

Commit 52d4567

Browse files
committed
Added support for parameterized virtual tables
1 parent 3544013 commit 52d4567

File tree

5 files changed

+116
-6
lines changed

5 files changed

+116
-6
lines changed

doc/virtual-tables.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Virtual tables
22

3+
## Unparameterized virtual tables
4+
35
First define virtual tables somewhere in your bootstrap:
46

57
```php
@@ -33,4 +35,42 @@ $query = $db->select()
3335
->joinInner('vt2', 'virt_table2', 'vt2.field2=t.field2');
3436
```
3537

38+
## Parameterized virtual tables
39+
40+
When you need parameterized sub-selects, you can use the Helperclass `Kir\MySQL\Tools\VirtualTable` to add parameters to a table-name:
41+
42+
Definition:
43+
44+
```php
45+
use Kir\MySQL\Databases\MySQL;
46+
47+
$db = new MySQL($pdo);
48+
49+
$vt1 = $db->select()
50+
->field('a.field1')
51+
->from('a', 'tableA');
52+
53+
$db->getVirtualTables()->add('virt_table1', $vt1);
54+
55+
// Lazy evaluated; parameterized
56+
$db->getVirtualTables()->add('virt_table2', function (array $args) {
57+
return $db->select()
58+
->field('a.field1')
59+
->from('a', 'tableA')
60+
->where(new DBExprFilter('a.active=?', $args, 'active'));
61+
});
62+
```
63+
64+
Then use it as needed:
65+
66+
```php
67+
$query = $db->select()
68+
->field('t.field1')
69+
->field('vt1.fieldN')
70+
->field('vt2.fieldN')
71+
->from('t', 'test')
72+
->joinInner('vt1', 'virt_table1', 'vt1.field1=t.field1')
73+
->joinInner('vt2', new VirtualTable('virt_table2', ['active' => 1]), 'vt2.field2=t.field2');
74+
```
75+
3676
[Back](../README.md)

src/Builder/Traits/TableNameBuilder.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
namespace Kir\MySQL\Builder\Traits;
33

44
use Kir\MySQL\Databases\MySQL;
5+
use Kir\MySQL\Tools\VirtualTable;
56

67
trait TableNameBuilder {
78
use AbstractAliasReplacer;
@@ -12,7 +13,7 @@ trait TableNameBuilder {
1213
* @return string
1314
*/
1415
protected function buildTableName($alias, $name) {
15-
if(is_object($name)) {
16+
if(is_object($name) && !($name instanceof VirtualTable)) {
1617
$name = (string) $name;
1718
$lines = explode("\n", $name);
1819
foreach($lines as &$line) {
@@ -33,7 +34,7 @@ protected function buildTableName($alias, $name) {
3334
$name = '(' . join("\n\tUNION\n\t", $parts) . ')';
3435
}
3536
if($this->db()->getVirtualTables()->has($name)) {
36-
$select = (string )$this->db()->getVirtualTables()->get($name);
37+
$select = (string) $this->db()->getVirtualTables()->get($name);
3738
$name = sprintf('(%s)', join("\n\t", explode("\n", trim($select))));
3839
}
3940
$name = $this->aliasReplacer()->replace($name);

src/Tools/VirtualTable.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
namespace Kir\MySQL\Tools;
3+
4+
class VirtualTable {
5+
/** @var string */
6+
private $tableName;
7+
/** @var array */
8+
private $params = [];
9+
10+
/**
11+
* @param string $tableName
12+
* @param array $params
13+
*/
14+
public function __construct($tableName, array $params = []) {
15+
$this->tableName = $tableName;
16+
$this->params = $params;
17+
}
18+
19+
/**
20+
* @return string
21+
*/
22+
public function getTableName() {
23+
return $this->tableName;
24+
}
25+
26+
/**
27+
* @return array
28+
*/
29+
public function getParams() {
30+
return $this->params;
31+
}
32+
33+
/**
34+
* @return string
35+
*/
36+
public function __toString() {
37+
return $this->getTableName();
38+
}
39+
}

src/Tools/VirtualTables.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ public function add($tableName, $select) {
1818
}
1919

2020
/**
21-
* @param string $tableName
21+
* @param string|VirtualTable $tableName
2222
* @return bool
2323
*/
2424
public function has($tableName) {
25-
return array_key_exists($tableName, $this->virtualTables);
25+
return array_key_exists((string) $tableName, $this->virtualTables);
2626
}
2727

2828
/**
@@ -31,9 +31,13 @@ public function has($tableName) {
3131
*/
3232
public function get($tableName) {
3333
if($this->has($tableName)) {
34-
$table = $this->virtualTables[$tableName];
34+
$table = $this->virtualTables[(string) $tableName];
3535
if($table instanceof \Closure) {
36-
return call_user_func($table);
36+
$params = [];
37+
if($tableName instanceof VirtualTable) {
38+
$params = $tableName->getParams();
39+
}
40+
return call_user_func($table, $params);
3741
}
3842
return $table;
3943
}

tests/Builder/SelectTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Kir\MySQL\Builder\Expr\RequiredValueNotFoundException;
99
use Kir\MySQL\Builder\SelectTest\TestSelect;
1010
use Kir\MySQL\Databases\TestDB;
11+
use Kir\MySQL\Tools\VirtualTable;
1112

1213
class SelectTestX extends \PHPUnit_Framework_TestCase {
1314
public function testAddition() {
@@ -365,4 +366,29 @@ public function testVirtualTables() {
365366

366367
$this->assertEquals("SELECT\n\tt.field1,\n\tt.field2\nFROM\n\ttest t\nINNER JOIN\n\t(SELECT\n\t\ta.field1\n\tFROM\n\t\ttableA a) vt1 ON vt1.field1=t.field1\nINNER JOIN\n\t(SELECT\n\t\ta.field1\n\tFROM\n\t\ttableA a) vt2 ON vt2.field2=t.field2\n", $query);
367368
}
369+
370+
public function testParametrizedVirtualTables() {
371+
$vt1 = TestSelect::create()
372+
->field('a.field1')
373+
->from('a', 'tableA');
374+
375+
$db = new TestDB();
376+
$db->getVirtualTables()->add('virt_table1', $vt1);
377+
$db->getVirtualTables()->add('virt_table2', function (array $args) {
378+
return TestSelect::create()
379+
->field('a.field1')
380+
->from('a', 'tableA')
381+
->where(new DBExprFilter('a.active=?', $args, 'active'));
382+
});
383+
384+
$query = TestSelect::create($db)
385+
->field('t.field1')
386+
->field('t.field2')
387+
->from('t', 'test')
388+
->joinInner('vt1', 'virt_table1', 'vt1.field1=t.field1')
389+
->joinInner('vt2', new VirtualTable('virt_table2', ['active' => true]), 'vt2.field2=t.field2')
390+
->asString();
391+
392+
$this->assertEquals("SELECT\n\tt.field1,\n\tt.field2\nFROM\n\ttest t\nINNER JOIN\n\t(SELECT\n\t\ta.field1\n\tFROM\n\t\ttableA a) vt1 ON vt1.field1=t.field1\nINNER JOIN\n\t(SELECT\n\t\ta.field1\n\tFROM\n\t\ttableA a\n\tWHERE\n\t\t(a.active='1')) vt2 ON vt2.field2=t.field2\n", $query);
393+
}
368394
}

0 commit comments

Comments
 (0)