Skip to content

Commit cb2efea

Browse files
authored
Merge pull request #41 from moufmouf/union_query
Adding support for UNION queries
2 parents b9e4815 + 4f79db6 commit cb2efea

File tree

5 files changed

+133
-1
lines changed

5 files changed

+133
-1
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ php:
44
- 5.6
55
- 7.0
66
- 7.1
7+
- 7.2
78

89
env:
910
matrix:

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"mouf/utils.common.sortable-interface": "~1.0",
2121
"mouf/schema-analyzer": "~1.0",
2222
"twig/twig": "^1.34.4 || ^2",
23-
"greenlion/php-sql-parser": "^4.0",
23+
"greenlion/php-sql-parser": "^4.1.2",
2424
"doctrine/cache": "^1.5"
2525
},
2626
"require-dev": {

src/SQLParser/Query/StatementFactory.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ public static function toObject(array $desc)
8787
}
8888

8989
return $select;
90+
} elseif (isset($desc['UNION'])) {
91+
$selects = array_map([self::class, 'toObject'], $desc['UNION']);
92+
93+
return new Union($selects);
9094
} else {
9195
throw new \BadMethodCallException('Unknown query');
9296
}

src/SQLParser/Query/Union.php

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<?php
2+
3+
namespace SQLParser\Query;
4+
5+
use Doctrine\DBAL\Connection;
6+
use Mouf\MoufInstanceDescriptor;
7+
use SQLParser\Node\NodeFactory;
8+
use Mouf\MoufManager;
9+
use SQLParser\Node\NodeInterface;
10+
use SQLParser\Node\Traverser\NodeTraverser;
11+
use SQLParser\Node\Traverser\VisitorInterface;
12+
13+
/**
14+
* This class represents a <code>UNION</code> query. You can use it to generate a SQL query statement
15+
* using the <code>toSql</code> method.
16+
* You can use the <code>QueryResult</code> class if you want to run the query directly.
17+
*
18+
* @author David Négrier <[email protected]>
19+
*/
20+
class Union implements StatementInterface, NodeInterface
21+
{
22+
/**
23+
* @var array|Select[]
24+
*/
25+
private $selects;
26+
27+
/**
28+
* Union constructor.
29+
* @param Select[] $selects
30+
*/
31+
public function __construct(array $selects)
32+
{
33+
$this->selects = $selects;
34+
}
35+
36+
/**
37+
* @param MoufManager $moufManager
38+
*
39+
* @return MoufInstanceDescriptor
40+
*/
41+
public function toInstanceDescriptor(MoufManager $moufManager)
42+
{
43+
$instanceDescriptor = $moufManager->createInstance(get_called_class());
44+
$instanceDescriptor->getProperty('selects')->setValue(NodeFactory::nodeToInstanceDescriptor($this->selects, $moufManager));
45+
46+
return $instanceDescriptor;
47+
}
48+
49+
/**
50+
* Configure the $instanceDescriptor describing this object (it must already exist as a Mouf instance).
51+
*
52+
* @param MoufManager $moufManager
53+
*
54+
* @return MoufInstanceDescriptor
55+
*/
56+
public function overwriteInstanceDescriptor($name, MoufManager $moufManager)
57+
{
58+
//$name = $moufManager->findInstanceName($this);
59+
$instanceDescriptor = $moufManager->getInstanceDescriptor($name);
60+
$instanceDescriptor->getProperty('selects')->setValue(NodeFactory::nodeToInstanceDescriptor($this->selects, $moufManager));
61+
62+
return $instanceDescriptor;
63+
}
64+
65+
/**
66+
* Renders the object as a SQL string.
67+
*
68+
* @param array $parameters
69+
* @param Connection $dbConnection
70+
* @param int|number $indent
71+
* @param int $conditionsMode
72+
*
73+
* @return string
74+
*/
75+
public function toSql(array $parameters = array(), Connection $dbConnection = null, $indent = 0, $conditionsMode = self::CONDITION_APPLY)
76+
{
77+
$selectsSql = array_map(function(Select $select) use ($parameters, $dbConnection, $indent, $conditionsMode) {
78+
return $select->toSql($parameters, $dbConnection, $indent, $conditionsMode);
79+
}, $this->selects);
80+
81+
$sql = implode(' UNION ', $selectsSql);
82+
83+
return $sql;
84+
}
85+
86+
/**
87+
* Walks the tree of nodes, calling the visitor passed in parameter.
88+
*
89+
* @param VisitorInterface $visitor
90+
*/
91+
public function walk(VisitorInterface $visitor)
92+
{
93+
$node = $this;
94+
$result = $visitor->enterNode($node);
95+
if ($result instanceof NodeInterface) {
96+
$node = $result;
97+
}
98+
if ($result !== NodeTraverser::DONT_TRAVERSE_CHILDREN) {
99+
$this->walkChildren($this->selects, $visitor);
100+
}
101+
102+
return $visitor->leaveNode($node);
103+
}
104+
105+
/**
106+
* @param Select[] $children
107+
* @param VisitorInterface $visitor
108+
*/
109+
private function walkChildren(array &$children, VisitorInterface $visitor)
110+
{
111+
if ($children) {
112+
foreach ($children as $key => $operand) {
113+
if ($operand) {
114+
$result2 = $operand->walk($visitor);
115+
if ($result2 === NodeTraverser::REMOVE_NODE) {
116+
unset($children[$key]);
117+
} elseif ($result2 instanceof NodeInterface) {
118+
$children[$key] = $result2;
119+
}
120+
}
121+
}
122+
}
123+
}
124+
}

tests/Mouf/Database/MagicQueryTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ public function testStandardSelect()
158158

159159
$sql = 'SELECT COUNT(DISTINCT a, b) FROM users';
160160
$this->assertEquals('SELECT COUNT(DISTINCT a, b) FROM users', self::simplifySql($magicQuery->build($sql)));
161+
162+
$sql = 'SELECT a FROM users UNION SELECT a FROM users';
163+
$this->assertEquals('SELECT a FROM users UNION SELECT a FROM users', self::simplifySql($magicQuery->build($sql)));
161164
}
162165

163166
/**

0 commit comments

Comments
 (0)