1
|
|
|
<?php |
2
|
|
|
namespace JayaCode\Framework\Core\Database\Query\Grammar; |
3
|
|
|
|
4
|
|
|
use JayaCode\Framework\Core\Database\Query\Query; |
5
|
|
|
use Stringy\Stringy; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Class GrammarMySql |
9
|
|
|
* @package JayaCode\Framework\Core\Database\Query\Grammar |
10
|
|
|
*/ |
11
|
|
|
class GrammarMySql extends Grammar |
12
|
|
|
{ |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* @return string |
16
|
|
|
*/ |
17
|
|
|
public function build() |
18
|
|
|
{ |
19
|
|
|
switch ($this->query->getType()) { |
20
|
|
|
case Query::TYPE_SELECT: |
21
|
|
|
return $this->select(); |
22
|
|
|
|
23
|
|
|
case Query::TYPE_INSERT: |
24
|
|
|
return $this->insert(); |
25
|
|
|
|
26
|
|
|
case Query::TYPE_UPDATE: |
27
|
|
|
return $this->update(); |
28
|
|
|
|
29
|
|
|
case Query::TYPE_DELETE: |
30
|
|
|
return $this->delete(); |
31
|
|
|
|
32
|
|
|
case Query::TYPE_QUERY: |
33
|
|
|
return $this->query->query; |
34
|
|
|
} |
35
|
|
|
return null; |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @return string |
40
|
|
|
*/ |
41
|
|
|
private function select() |
42
|
|
|
{ |
43
|
|
|
$this->queryString = "SELECT "; |
44
|
|
|
|
45
|
|
|
$this->queryString .= $this->selectColumn(); |
46
|
|
|
|
47
|
|
|
$table = $this->query->table; |
48
|
|
|
$this->queryString .= " FROM {$this->getFormattedTableOrColumn($table)}"; |
49
|
|
|
|
50
|
|
|
$this->queryString .= $this->where(); |
51
|
|
|
|
52
|
|
|
$this->queryString .= $this->sort(); |
53
|
|
|
$this->queryString .= $this->limit(); |
54
|
|
|
|
55
|
|
|
return $this->queryString; |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @return string |
60
|
|
|
*/ |
61
|
|
|
private function selectColumn() |
62
|
|
|
{ |
63
|
|
|
$columns = $this->query->columns; |
64
|
|
|
if (is_null($columns)) { |
65
|
|
|
$columns = [Query::sql("*")]; |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
if (is_string($columns)) { |
69
|
|
|
$columns = array($columns); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
foreach ($columns as $key => $val) { |
73
|
|
|
if ($columns[$key] instanceof Query) { |
74
|
|
|
$columns[$key] = $columns[$key]->query; |
75
|
|
|
} else { |
76
|
|
|
$columns[$key] = $this->getFormattedTableOrColumn($val); |
77
|
|
|
} |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
return implode(', ', $columns); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* @return string |
85
|
|
|
*/ |
86
|
|
|
private function where() |
87
|
|
|
{ |
88
|
|
|
if (count($this->query->where) <= 0) { |
89
|
|
|
return ""; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
$q = Stringy::create(""); |
93
|
|
|
|
94
|
|
|
foreach ($this->query->where as $where) { |
95
|
|
|
$type = $where[0]; |
96
|
|
|
$arr = $where[1]; |
97
|
|
|
|
98
|
|
|
if ($q->count() > 1) { |
99
|
|
|
$q = $q->append(" {$type} "); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
if (is_string($arr)) { |
103
|
|
|
$q = $q->append($arr); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
if (is_array($arr)) { |
107
|
|
|
$q = $q->append($this->buildArrWhere($arr)); |
108
|
|
|
|
109
|
|
|
$this->params[] = $arr[2]; |
110
|
|
|
} |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
return $q->count()?$q->prepend(" WHERE ")->__toString():""; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* @return string |
118
|
|
|
*/ |
119
|
|
|
private function sort() |
120
|
|
|
{ |
121
|
|
|
if (empty($this->query->sort)) { |
122
|
|
|
return ""; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
$sort = $this->query->sort; |
126
|
|
|
|
127
|
|
|
if (!isset($sort['column']) || !isset($sort['order'])) { |
128
|
|
|
return ""; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
return " ORDER BY {$this->getFormattedTableOrColumn($sort['column'])} {$sort['order']}"; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* @return string |
136
|
|
|
*/ |
137
|
|
|
private function limit() |
138
|
|
|
{ |
139
|
|
|
if (empty($this->query->limit) || !is_numeric($this->query->limit)) { |
140
|
|
|
return ""; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
$str = " LIMIT {$this->query->limit}"; |
144
|
|
|
|
145
|
|
|
if ($this->query->offset && is_numeric($this->query->offset)) { |
|
|
|
|
146
|
|
|
$str .= " OFFSET {$this->query->offset}"; |
147
|
|
|
} |
148
|
|
|
return $str; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* @param $arr |
153
|
|
|
* @return string |
154
|
|
|
*/ |
155
|
|
|
private function buildArrWhere($arr) |
156
|
|
|
{ |
157
|
|
|
if (count($arr) != 3) { |
158
|
|
|
throw new \OutOfBoundsException(); |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
switch ($arr[1]) { |
162
|
|
|
case "BETWEEN": |
163
|
|
|
return "`{$arr[0]}` {$arr[1]} ? AND ?"; |
164
|
|
|
default: |
165
|
|
|
return "`{$arr[0]}` {$arr[1]} ?"; |
166
|
|
|
} |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* @return string |
171
|
|
|
*/ |
172
|
|
|
private function insert() |
173
|
|
|
{ |
174
|
|
|
|
175
|
|
|
$this->params = $this->query->values; |
176
|
|
|
|
177
|
|
|
$table = $this->query->table; |
178
|
|
|
$this->queryString = "INSERT INTO {$this->getFormattedTableOrColumn($table)}"; |
179
|
|
|
|
180
|
|
|
$this->queryString .= "({$this->selectColumn()})"; |
181
|
|
|
|
182
|
|
|
$this->queryString .= " VALUES("; |
183
|
|
|
|
184
|
|
|
$params = array(); |
185
|
|
|
|
186
|
|
|
for ($i=0, $c=count($this->query->columns); $i<$c; $i++) { |
187
|
|
|
$params[$i] = "?"; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
$this->queryString .= join(', ', $params).")"; |
191
|
|
|
|
192
|
|
|
return $this->queryString; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* @return string |
197
|
|
|
*/ |
198
|
|
|
private function update() |
199
|
|
|
{ |
200
|
|
|
$this->params = $this->query->values; |
201
|
|
|
|
202
|
|
|
$table = $this->query->table; |
203
|
|
|
$this->queryString = "UPDATE {$this->getFormattedTableOrColumn($table)} SET "; |
204
|
|
|
|
205
|
|
|
$arrSet = array(); |
206
|
|
|
foreach ($this->query->columns as $column) { |
207
|
|
|
$arrSet[] = "{$this->getFormattedTableOrColumn($column)} = ?"; |
208
|
|
|
} |
209
|
|
|
$this->queryString .= join(", ", $arrSet); |
210
|
|
|
|
211
|
|
|
$this->queryString .= $this->where(); |
212
|
|
|
|
213
|
|
|
return $this->queryString; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* @return string |
218
|
|
|
*/ |
219
|
|
|
private function delete() |
220
|
|
|
{ |
221
|
|
|
$table = $this->query->table; |
222
|
|
|
$this->queryString = "DELETE FROM {$this->getFormattedTableOrColumn($table)}"; |
223
|
|
|
$this->queryString .= $this->where(); |
224
|
|
|
|
225
|
|
|
return $this->queryString; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* @param null $str |
230
|
|
|
* @return null|string |
231
|
|
|
*/ |
232
|
|
|
private function getFormattedTableOrColumn($str = null) |
233
|
|
|
{ |
234
|
|
|
$tmpStr = $str?$str:$this->query->table; |
235
|
|
|
$strArr = explode(".", $tmpStr); |
236
|
|
|
|
237
|
|
|
foreach ($strArr as $key => $val) { |
238
|
|
|
$strArr[$key] = "`{$val}`"; |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
return join(".", $strArr); |
242
|
|
|
} |
243
|
|
|
} |
244
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.