1 | <?php |
||
2 | |||
3 | namespace ByJG\MicroOrm; |
||
4 | |||
5 | use ByJG\AnyDataset\Db\DbDriverInterface; |
||
6 | use ByJG\MicroOrm\Exception\InvalidArgumentException; |
||
7 | use ByJG\Serializer\BinderObject; |
||
8 | |||
9 | class Query |
||
10 | { |
||
11 | protected $fields = []; |
||
12 | protected $table = ""; |
||
13 | protected $where = []; |
||
14 | protected $groupBy = []; |
||
15 | protected $orderBy = []; |
||
16 | protected $join = []; |
||
17 | protected $limitStart = null; |
||
18 | protected $limitEnd = null; |
||
19 | protected $top = null; |
||
20 | |||
21 | protected $forUpdate = false; |
||
22 | |||
23 | public static function getInstance() |
||
24 | { |
||
25 | return new Query(); |
||
26 | } |
||
27 | |||
28 | 6 | /** |
|
29 | * Example: |
||
30 | 6 | * $query->fields(['name', 'price']); |
|
31 | * |
||
32 | * @param array $fields |
||
33 | * @return $this |
||
34 | * @throws \ByJG\Serializer\Exception\InvalidArgumentException |
||
35 | */ |
||
36 | public function fields(array $fields) |
||
37 | { |
||
38 | foreach ($fields as $field) { |
||
39 | if ($field instanceof Mapper) { |
||
40 | $this->addFieldFromMapper($field); |
||
41 | 5 | continue; |
|
42 | } |
||
43 | 5 | $this->fields[] = $field; |
|
44 | 5 | } |
|
45 | 1 | ||
46 | 1 | return $this; |
|
47 | } |
||
48 | 4 | ||
49 | 5 | /** |
|
50 | * @param \ByJG\MicroOrm\Mapper $mapper |
||
51 | 5 | * @throws \ByJG\Serializer\Exception\InvalidArgumentException |
|
52 | */ |
||
53 | private function addFieldFromMapper(Mapper $mapper) |
||
54 | { |
||
55 | $entityClass = $mapper->getEntity(); |
||
56 | $entity = new $entityClass(); |
||
57 | $serialized = BinderObject::toArrayFrom($entity); |
||
58 | 1 | ||
59 | foreach (array_keys($serialized) as $fieldName) { |
||
60 | 1 | $mapField = $mapper->getFieldMap($fieldName, Mapper::FIELDMAP_FIELD); |
|
61 | 1 | if (empty($mapField)) { |
|
62 | 1 | $mapField = $fieldName; |
|
63 | } |
||
64 | 1 | ||
65 | 1 | $alias = $mapper->getFieldAlias($mapField); |
|
66 | 1 | if (!empty($alias)) { |
|
67 | 1 | $alias = ' as ' . $alias; |
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
68 | 1 | } |
|
69 | |||
70 | 1 | $this->fields[] = $mapper->getTable() . '.' . $mapField . $alias; |
|
71 | 1 | } |
|
72 | 1 | } |
|
73 | 1 | ||
74 | /** |
||
75 | 1 | * Example |
|
76 | 1 | * $query->table('product'); |
|
77 | 1 | * |
|
78 | * @param string $table |
||
79 | * @return $this |
||
80 | */ |
||
81 | public function table($table) |
||
82 | { |
||
83 | $this->table = $table; |
||
84 | |||
85 | return $this; |
||
86 | 24 | } |
|
87 | |||
88 | 24 | /** |
|
89 | * Example: |
||
90 | 24 | * $query->join('sales', 'product.id = sales.id'); |
|
91 | * |
||
92 | * @param string $table |
||
93 | * @param string $filter |
||
94 | * @return $this |
||
95 | */ |
||
96 | public function join($table, $filter) |
||
97 | { |
||
98 | $this->join[] = [ 'table'=>$table, 'filter'=>$filter, 'type' => 'INNER']; |
||
99 | return $this; |
||
100 | } |
||
101 | 1 | ||
102 | /** |
||
103 | 1 | * Example: |
|
104 | 1 | * $query->join('sales', 'product.id = sales.id'); |
|
105 | * |
||
106 | * @param string $table |
||
107 | * @param string $filter |
||
108 | * @return $this |
||
109 | */ |
||
110 | public function leftJoin($table, $filter) |
||
111 | { |
||
112 | $this->join[] = [ 'table'=>$table, 'filter'=>$filter, 'type' => 'LEFT']; |
||
113 | return $this; |
||
114 | } |
||
115 | 1 | ||
116 | /** |
||
117 | 1 | * Example: |
|
118 | 1 | * $query->filter('price > [[amount]]', [ 'amount' => 1000] ); |
|
119 | * |
||
120 | * @param string $filter |
||
121 | * @param array $params |
||
122 | * @return $this |
||
123 | */ |
||
124 | public function where($filter, array $params = []) |
||
125 | { |
||
126 | $this->where[] = [ 'filter' => $filter, 'params' => $params ]; |
||
127 | return $this; |
||
128 | } |
||
129 | 22 | ||
130 | /** |
||
131 | 22 | * Example: |
|
132 | 22 | * $query->groupBy(['name']); |
|
133 | * |
||
134 | * @param array $fields |
||
135 | * @return $this |
||
136 | */ |
||
137 | public function groupBy(array $fields) |
||
138 | { |
||
139 | $this->groupBy = array_merge($this->groupBy, $fields); |
||
140 | |||
141 | return $this; |
||
142 | 1 | } |
|
143 | |||
144 | 1 | /** |
|
145 | * Example: |
||
146 | 1 | * $query->orderBy(['price desc']); |
|
147 | * |
||
148 | * @param array $fields |
||
149 | * @return $this |
||
150 | */ |
||
151 | public function orderBy(array $fields) |
||
152 | { |
||
153 | $this->orderBy = array_merge($this->orderBy, $fields); |
||
154 | |||
155 | return $this; |
||
156 | 4 | } |
|
157 | |||
158 | 4 | public function forUpdate() |
|
159 | { |
||
160 | 4 | $this->forUpdate = true; |
|
161 | |||
162 | return $this; |
||
163 | } |
||
164 | |||
165 | /** |
||
166 | * @param $start |
||
167 | * @param $end |
||
168 | * @return $this |
||
169 | * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException |
||
170 | 1 | */ |
|
171 | public function limit($start, $end) |
||
172 | 1 | { |
|
173 | if (!is_null($this->top)) { |
||
174 | throw new InvalidArgumentException('You cannot mix TOP and LIMIT'); |
||
175 | 1 | } |
|
176 | 1 | $this->limitStart = $start; |
|
177 | 1 | $this->limitEnd = $end; |
|
178 | return $this; |
||
179 | } |
||
180 | 1 | ||
181 | /** |
||
182 | 1 | * @param $top |
|
183 | * @return $this |
||
184 | * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException |
||
185 | 1 | */ |
|
186 | 1 | public function top($top) |
|
187 | { |
||
188 | if (!is_null($this->limitStart)) { |
||
189 | 24 | throw new InvalidArgumentException('You cannot mix TOP and LIMIT'); |
|
190 | } |
||
191 | 24 | $this->top = $top; |
|
192 | 20 | return $this; |
|
193 | } |
||
194 | |||
195 | 5 | protected function getFields() |
|
196 | { |
||
197 | if (empty($this->fields)) { |
||
198 | 24 | return ' * '; |
|
199 | } |
||
200 | 24 | ||
201 | 24 | return ' ' . implode(', ', $this->fields) . ' '; |
|
202 | 2 | } |
|
203 | 24 | ||
204 | 24 | protected function getJoin() |
|
205 | { |
||
206 | $joinStr = $this->table; |
||
207 | 24 | foreach ($this->join as $item) { |
|
208 | $joinStr .= ' ' . $item['type'] . ' JOIN ' . $item['table'] . ' ON ' . $item['filter']; |
||
209 | 24 | } |
|
210 | 24 | return $joinStr; |
|
211 | } |
||
212 | 24 | ||
213 | 22 | protected function getWhere() |
|
214 | 22 | { |
|
215 | 24 | $whereStr = []; |
|
216 | $params = []; |
||
217 | 24 | ||
218 | 3 | foreach ($this->where as $item) { |
|
219 | $whereStr[] = $item['filter']; |
||
220 | $params = array_merge($params, $item['params']); |
||
221 | 22 | } |
|
222 | |||
223 | if (empty($whereStr)) { |
||
224 | return null; |
||
225 | } |
||
226 | |||
227 | return [ implode(' AND ', $whereStr), $params ]; |
||
228 | 24 | } |
|
229 | |||
230 | /** |
||
231 | 24 | * @param \ByJG\AnyDataset\Db\DbDriverInterface|null $dbDriver |
|
232 | 24 | * @return array |
|
233 | * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException |
||
234 | 24 | */ |
|
235 | 24 | public function build(DbDriverInterface $dbDriver = null) |
|
236 | 24 | { |
|
237 | 22 | $sql = "SELECT " . |
|
238 | 22 | $this->getFields() . |
|
239 | 22 | "FROM " . $this->getJoin(); |
|
240 | |||
241 | 24 | $whereStr = $this->getWhere(); |
|
242 | $params = null; |
||
243 | 24 | if (!is_null($whereStr)) { |
|
244 | $sql .= ' WHERE ' . $whereStr[0]; |
||
245 | 24 | $params = $whereStr[1]; |
|
246 | } |
||
247 | 24 | ||
248 | $sql .= $this->addGroupBy(); |
||
249 | 24 | ||
250 | $sql .= $this->addOrderBy(); |
||
251 | 24 | ||
252 | $sql = $this->addforUpdate($dbDriver, $sql); |
||
253 | 24 | ||
254 | $sql = $this->addTop($dbDriver, $sql); |
||
255 | |||
256 | 24 | $sql = $this->addLimit($dbDriver, $sql); |
|
257 | |||
258 | 24 | $sql = ORMHelper::processLiteral($sql, $params); |
|
259 | 21 | ||
260 | return [ 'sql' => $sql, 'params' => $params ]; |
||
261 | 4 | } |
|
262 | |||
263 | private function addOrderBy() |
||
264 | 24 | { |
|
265 | if (empty($this->orderBy)) { |
||
266 | 24 | return ""; |
|
267 | 24 | } |
|
268 | return ' ORDER BY ' . implode(', ', $this->orderBy); |
||
269 | 1 | } |
|
270 | |||
271 | private function addGroupBy() |
||
272 | { |
||
273 | if (empty($this->groupBy)) { |
||
274 | return ""; |
||
275 | } |
||
276 | return ' GROUP BY ' . implode(', ', $this->groupBy); |
||
277 | 24 | } |
|
278 | |||
279 | 24 | /** |
|
280 | 24 | * @param DbDriverInterface $dbDriver |
|
281 | * @param string $sql |
||
282 | * @return string |
||
283 | * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException |
||
284 | */ |
||
285 | private function addforUpdate($dbDriver, $sql) |
||
286 | { |
||
287 | if (empty($this->forUpdate)) { |
||
288 | return $sql; |
||
289 | } |
||
290 | |||
291 | if (is_null($dbDriver)) { |
||
292 | throw new InvalidArgumentException('To get FOR UPDATE working you have to pass the DbDriver'); |
||
293 | } |
||
294 | |||
295 | 24 | return $dbDriver->getDbHelper()->forUpdate($sql); |
|
296 | } |
||
297 | 24 | ||
298 | 23 | /** |
|
299 | * @param DbDriverInterface $dbDriver |
||
300 | * @param string $sql |
||
301 | 1 | * @return string |
|
302 | * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException |
||
303 | */ |
||
304 | private function addTop($dbDriver, $sql) |
||
305 | 1 | { |
|
306 | if (empty($this->top)) { |
||
307 | return $sql; |
||
308 | } |
||
309 | |||
310 | if (is_null($dbDriver)) { |
||
311 | throw new InvalidArgumentException('To get Limit and Top working you have to pass the DbDriver'); |
||
312 | } |
||
313 | 24 | ||
314 | return $dbDriver->getDbHelper()->top($sql, $this->top); |
||
315 | 24 | } |
|
316 | 23 | ||
317 | /** |
||
318 | * @param DbDriverInterface $dbDriver |
||
319 | 1 | * @param string $sql |
|
320 | * @return string |
||
321 | * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException |
||
322 | */ |
||
323 | 1 | private function addLimit($dbDriver, $sql) |
|
324 | { |
||
325 | if (empty($this->limitStart) && ($this->limitStart !== 0)) { |
||
326 | return $sql; |
||
327 | } |
||
328 | |||
329 | if (is_null($dbDriver)) { |
||
330 | throw new InvalidArgumentException('To get Limit and Top working you have to pass the DbDriver'); |
||
331 | } |
||
332 | |||
333 | return $dbDriver->getDbHelper()->limit($sql, $this->limitStart, $this->limitEnd); |
||
334 | } |
||
335 | } |
||
336 |