PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 3.6.40
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v3.6.40
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Services / wpfluent / src / QueryBuilder / Adapters / BaseAdapter.php

BaseAdapter.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 3.6.40, at app/Services/wpfluent/src/QueryBuilder/Adapters/BaseAdapter.php

546 lines 15.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php namespace WpFluent\QueryBuilder\Adapters;
2
3 use WpFluent\Connection;
4 use WpFluent\Exception;
5 use WpFluent\QueryBuilder\Raw;
6
7 abstract class BaseAdapter
8 {
9 /**
10 * @var \WpFluent\Connection
11 */
12 protected $connection;
13
14 /**
15 * @var \Viocon\Container
16 */
17 protected $container;
18
19 public function __construct(Connection $connection)
20 {
21 $this->connection = $connection;
22 $this->container = $this->connection->getContainer();
23 }
24
25 /**
26 * Build select query string and bindings
27 *
28 * @param $statements
29 *
30 * @throws Exception
31 * @return array
32 */
33 public function select($statements)
34 {
35 if (! array_key_exists('tables', $statements)) {
36 throw new Exception('No table specified.', 3);
37 } elseif (! array_key_exists('selects', $statements)) {
38 $statements['selects'][] = '*';
39 }
40
41 // From
42 $tables = $this->arrayStr($statements['tables'], ', ');
43 // Select
44 $selects = $this->arrayStr($statements['selects'], ', ');
45
46
47 // Wheres
48 list($whereCriteria, $whereBindings) = $this->buildCriteriaWithType($statements, 'wheres', 'WHERE');
49 // Group bys
50 $groupBys = '';
51 if (isset($statements['groupBys']) && $groupBys = $this->arrayStr($statements['groupBys'], ', ')) {
52 $groupBys = 'GROUP BY ' . $groupBys;
53 }
54
55 // Order bys
56 $orderBys = '';
57 if (isset($statements['orderBys']) && is_array($statements['orderBys'])) {
58 foreach ($statements['orderBys'] as $orderBy) {
59 $orderBys .= $this->wrapSanitizer($orderBy['field']) . ' ' . $orderBy['type'] . ', ';
60 }
61
62 if ($orderBys = trim($orderBys, ', ')) {
63 $orderBys = 'ORDER BY ' . $orderBys;
64 }
65 }
66
67 // Limit and offset
68 $limit = isset($statements['limit']) ? 'LIMIT ' . $statements['limit'] : '';
69 $offset = isset($statements['offset']) ? 'OFFSET ' . $statements['offset'] : '';
70
71 // Having
72 list($havingCriteria, $havingBindings) = $this->buildCriteriaWithType($statements, 'havings', 'HAVING');
73
74 // Joins
75 $joinString = $this->buildJoin($statements);
76
77 $sqlArray = array(
78 'SELECT' . (isset($statements['distinct']) ? ' DISTINCT' : ''),
79 $selects,
80 'FROM',
81 $tables,
82 $joinString,
83 $whereCriteria,
84 $groupBys,
85 $havingCriteria,
86 $orderBys,
87 $limit,
88 $offset
89 );
90
91 $sql = $this->concatenateQuery($sqlArray);
92
93 $bindings = array_merge(
94 $whereBindings,
95 $havingBindings
96 );
97
98 return compact('sql', 'bindings');
99 }
100
101 /**
102 * Build just criteria part of the query
103 *
104 * @param $statements
105 * @param bool $bindValues
106 *
107 * @return array
108 */
109 public function criteriaOnly($statements, $bindValues = true)
110 {
111 $sql = $bindings = array();
112
113 if (! isset($statements['criteria'])) {
114 return compact('sql', 'bindings');
115 }
116
117 list($sql, $bindings) = $this->buildCriteria($statements['criteria'], $bindValues);
118
119 return compact('sql', 'bindings');
120 }
121
122 /**
123 * Build a generic insert/ignore/replace query
124 *
125 * @param $statements
126 * @param array $data
127 *
128 * @return array
129 * @throws Exception
130 */
131 private function doInsert($statements, array $data, $type)
132 {
133 if (! isset($statements['tables'])) {
134 throw new Exception('No table specified', 3);
135 }
136
137 $table = end($statements['tables']);
138
139 $bindings = $keys = $values = array();
140
141 foreach ($data as $key => $value) {
142 $keys[] = $key;
143 if ($value instanceof Raw) {
144 $values[] = (string) $value;
145 } else {
146 $values[] = '?';
147 $bindings[] = $value;
148 }
149 }
150
151 $sqlArray = array(
152 $type . ' INTO',
153 $this->wrapSanitizer($table),
154 '(' . $this->arrayStr($keys, ',') . ')',
155 'VALUES',
156 '(' . $this->arrayStr($values, ',', false) . ')',
157 );
158
159 if (isset($statements['onduplicate'])) {
160 if (count($statements['onduplicate']) < 1) {
161 throw new Exception('No data given.', 4);
162 }
163 list($updateStatement, $updateBindings) = $this->getUpdateStatement($statements['onduplicate']);
164 $sqlArray[] = 'ON DUPLICATE KEY UPDATE ' . $updateStatement;
165 $bindings = array_merge($bindings, $updateBindings);
166 }
167
168 $sql = $this->concatenateQuery($sqlArray);
169
170 return compact('sql', 'bindings');
171 }
172
173 /**
174 * Build Insert query
175 *
176 * @param $statements
177 * @param array $data
178 *
179 * @return array
180 * @throws Exception
181 */
182 public function insert($statements, array $data)
183 {
184 return $this->doInsert($statements, $data, 'INSERT');
185 }
186
187 /**
188 * Build Insert Ignore query
189 *
190 * @param $statements
191 * @param array $data
192 *
193 * @return array
194 * @throws Exception
195 */
196 public function insertIgnore($statements, array $data)
197 {
198 return $this->doInsert($statements, $data, 'INSERT IGNORE');
199 }
200
201 /**
202 * Build Insert Ignore query
203 *
204 * @param $statements
205 * @param array $data
206 *
207 * @return array
208 * @throws Exception
209 */
210 public function replace($statements, array $data)
211 {
212 return $this->doInsert($statements, $data, 'REPLACE');
213 }
214
215 /**
216 * Build fields assignment part of SET ... or ON DUBLICATE KEY UPDATE ... statements
217 *
218 * @param array $data
219 *
220 * @return array
221 */
222 private function getUpdateStatement($data)
223 {
224 $bindings = array();
225 $statement = '';
226
227 foreach ($data as $key => $value) {
228 if ($value instanceof Raw) {
229 $statement .= $this->wrapSanitizer($key) . '=' . $value . ',';
230 } else {
231 $statement .= $this->wrapSanitizer($key) . '=?,';
232 $bindings[] = $value;
233 }
234 }
235
236 $statement = trim($statement, ',');
237
238 return array($statement, $bindings);
239 }
240
241 /**
242 * Build update query
243 *
244 * @param $statements
245 * @param array $data
246 *
247 * @return array
248 * @throws Exception
249 */
250 public function update($statements, array $data)
251 {
252 if (! isset($statements['tables'])) {
253 throw new Exception('No table specified', 3);
254 } elseif (count($data) < 1) {
255 throw new Exception('No data given.', 4);
256 }
257
258 $table = end($statements['tables']);
259
260 // Update statement
261 list($updateStatement, $bindings) = $this->getUpdateStatement($data);
262
263 // Wheres
264 list($whereCriteria, $whereBindings) = $this->buildCriteriaWithType($statements, 'wheres', 'WHERE');
265
266 // Limit
267 $limit = isset($statements['limit']) ? 'LIMIT ' . $statements['limit'] : '';
268
269 $sqlArray = array(
270 'UPDATE',
271 $this->wrapSanitizer($table),
272 'SET ' . $updateStatement,
273 $whereCriteria,
274 $limit
275 );
276
277 $sql = $this->concatenateQuery($sqlArray);
278
279 $bindings = array_merge($bindings, $whereBindings);
280
281 return compact('sql', 'bindings');
282 }
283
284 /**
285 * Build delete query
286 *
287 * @param $statements
288 *
289 * @return array
290 * @throws Exception
291 */
292 public function delete($statements)
293 {
294 if (! isset($statements['tables'])) {
295 throw new Exception('No table specified', 3);
296 }
297
298 $table = end($statements['tables']);
299
300 // Wheres
301 list($whereCriteria, $whereBindings) = $this->buildCriteriaWithType($statements, 'wheres', 'WHERE');
302
303 // Limit
304 $limit = isset($statements['limit']) ? 'LIMIT ' . $statements['limit'] : '';
305
306 $sqlArray = array('DELETE FROM', $this->wrapSanitizer($table), $whereCriteria);
307 $sql = $this->concatenateQuery($sqlArray);
308 $bindings = $whereBindings;
309
310 return compact('sql', 'bindings');
311 }
312
313 /**
314 * Array concatenating method, like implode.
315 * But it does wrap sanitizer and trims last glue
316 *
317 * @param array $pieces
318 * @param $glue
319 * @param bool $wrapSanitizer
320 *
321 * @return string
322 */
323 protected function arrayStr(array $pieces, $glue, $wrapSanitizer = true)
324 {
325 $str = '';
326
327 foreach ($pieces as $key => $piece) {
328 if ($wrapSanitizer) {
329 $piece = $this->wrapSanitizer($piece);
330 }
331
332 if (! is_int($key)) {
333 $piece = ($wrapSanitizer ? $this->wrapSanitizer($key) : $key) . ' AS ' . $piece;
334 }
335
336 $str .= $piece . $glue;
337 }
338
339 return trim($str, $glue);
340 }
341
342 /**
343 * Join different part of queries with a space.
344 *
345 * @param array $pieces
346 *
347 * @return string
348 */
349 protected function concatenateQuery(array $pieces)
350 {
351 $str = '';
352
353 foreach ($pieces as $piece) {
354 $str = trim($str) . ' ' . trim($piece);
355 }
356
357 return trim($str);
358 }
359
360 /**
361 * Build generic criteria string and bindings from statements, like "a = b and c = ?"
362 *
363 * @param $statements
364 * @param bool $bindValues
365 *
366 * @return array
367 */
368 protected function buildCriteria($statements, $bindValues = true)
369 {
370 $criteria = '';
371 $bindings = array();
372
373 foreach ($statements as $statement) {
374 $key = $this->wrapSanitizer($statement['key']);
375 $value = $statement['value'];
376
377 if (is_null($value) && $key instanceof \Closure) {
378 // We have a closure, a nested criteria
379
380 // Build a new NestedCriteria class, keep it by reference so any changes made
381 // in the closure should reflect here
382 $nestedCriteria = $this->container->build(
383 '\\WpFluent\\QueryBuilder\\NestedCriteria',
384 array($this->connection)
385 );
386
387 $nestedCriteria = & $nestedCriteria;
388 // Call the closure with our new nestedCriteria object
389 $key($nestedCriteria);
390 // Get the criteria only query from the nestedCriteria object
391 $queryObject = $nestedCriteria->getQuery('criteriaOnly', true);
392 // Merge the bindings we get from nestedCriteria object
393 $bindings = array_merge($bindings, $queryObject->getBindings());
394 // Append the sql we get from the nestedCriteria object
395 $criteria .= $statement['joiner'] . ' (' . $queryObject->getSql() . ') ';
396 } elseif (is_array($value)) {
397 // where_in or between like query
398 $criteria .= $statement['joiner'] . ' ' . $key . ' ' . $statement['operator'];
399
400 switch ($statement['operator']) {
401 case 'BETWEEN':
402 $bindings = array_merge($bindings, $statement['value']);
403 $criteria .= ' ? AND ? ';
404 break;
405 default:
406 $valuePlaceholder = '';
407 foreach ($statement['value'] as $subValue) {
408 $valuePlaceholder .= '?, ';
409 $bindings[] = $subValue;
410 }
411
412 $valuePlaceholder = trim($valuePlaceholder, ', ');
413 $criteria .= ' (' . $valuePlaceholder . ') ';
414 break;
415 }
416 } elseif ($value instanceof Raw) {
417 $criteria .= "{$statement['joiner']} {$key} {$statement['operator']} $value ";
418 } else {
419 // Usual where like criteria
420
421 if (! $bindValues) {
422 // Specially for joins
423
424 // We are not binding values, lets sanitize then
425 $value = $this->wrapSanitizer($value);
426 $criteria .= $statement['joiner'] . ' ' . $key . ' ' . $statement['operator'] . ' ' . $value . ' ';
427 } elseif ($statement['key'] instanceof Raw) {
428 $criteria .= $statement['joiner'] . ' ' . $key . ' ';
429 $bindings = array_merge($bindings, $statement['key']->getBindings());
430 } else {
431 // For wheres
432
433 $valuePlaceholder = '?';
434 $bindings[] = $value;
435 $criteria .= $statement['joiner'] . ' ' . $key . ' ' . $statement['operator'] . ' '
436 . $valuePlaceholder . ' ';
437 }
438 }
439 }
440
441 // Clear all white spaces, and, or from beginning and white spaces from ending
442 $criteria = preg_replace('/^(\s?AND ?|\s?OR ?)|\s$/i', '', $criteria);
443
444 return array($criteria, $bindings);
445 }
446
447 /**
448 * Wrap values with adapter's sanitizer like, '`'
449 *
450 * @param $value
451 *
452 * @return string
453 */
454 public function wrapSanitizer($value)
455 {
456 // Its a raw query, just cast as string, object has __toString()
457 if ($value instanceof Raw) {
458 return (string) $value;
459 } elseif ($value instanceof \Closure) {
460 return $value;
461 }
462
463 // Separate our table and fields which are joined with a ".",
464 // like my_table.id
465 $valueArr = explode('.', $value, 2);
466
467 foreach ($valueArr as $key => $subValue) {
468 // Don't wrap if we have *, which is not a usual field
469 $valueArr[$key] = trim($subValue) == '*' ? $subValue : $this->sanitizer . $subValue . $this->sanitizer;
470 }
471
472 // Join these back with "." and return
473 return implode('.', $valueArr);
474 }
475
476 /**
477 * Build criteria string and binding with various types added, like WHERE and Having
478 *
479 * @param $statements
480 * @param $key
481 * @param $type
482 * @param bool $bindValues
483 *
484 * @return array
485 */
486 protected function buildCriteriaWithType($statements, $key, $type, $bindValues = true)
487 {
488 $criteria = '';
489 $bindings = array();
490
491 if (isset($statements[$key])) {
492 // Get the generic/adapter agnostic criteria string from parent
493 list($criteria, $bindings) = $this->buildCriteria($statements[$key], $bindValues);
494
495 if ($criteria) {
496 $criteria = $type . ' ' . $criteria;
497 }
498 }
499
500 return array($criteria, $bindings);
501 }
502
503 /**
504 * Build join string
505 *
506 * @param $statements
507 *
508 * @return array|string
509 */
510 protected function buildJoin($statements)
511 {
512 $sql = '';
513
514 if (! array_key_exists('joins', $statements) || ! is_array($statements['joins'])) {
515 return $sql;
516 }
517
518 foreach ($statements['joins'] as $joinArr) {
519 if (is_array($joinArr['table'])) {
520 $mainTable = $joinArr['table'][0];
521 $aliasTable = $joinArr['table'][1];
522 $table = $this->wrapSanitizer($mainTable) . ' AS ' . $this->wrapSanitizer($aliasTable);
523 } else {
524 $table = $joinArr['table'] instanceof Raw ?
525 (string) $joinArr['table'] :
526 $this->wrapSanitizer($joinArr['table']);
527 }
528
529 $joinBuilder = $joinArr['joinBuilder'];
530
531 $sqlArr = array(
532 $sql,
533 strtoupper($joinArr['type']),
534 'JOIN',
535 $table,
536 'ON',
537 $joinBuilder->getQuery('criteriaOnly', false)->getSql()
538 );
539
540 $sql = $this->concatenateQuery($sqlArr);
541 }
542
543 return $sql;
544 }
545 }
546