Total Complexity | 164 |
Total Lines | 1510 |
Duplicated Lines | 0 % |
Changes | 10 | ||
Bugs | 0 | Features | 2 |
Complex classes like QueryBuilderHandler often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use QueryBuilderHandler, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
25 | class QueryBuilderHandler implements HasConnection |
||
26 | { |
||
27 | /** |
||
28 | * @method add |
||
29 | */ |
||
30 | use TablePrefixer; |
||
31 | |||
32 | /** |
||
33 | * @var \Viocon\Container |
||
34 | */ |
||
35 | protected $container; |
||
36 | |||
37 | /** |
||
38 | * @var Connection |
||
39 | */ |
||
40 | protected $connection; |
||
41 | |||
42 | /** |
||
43 | * @var array<string, mixed[]|mixed> |
||
44 | */ |
||
45 | protected $statements = []; |
||
46 | |||
47 | /** |
||
48 | * @var wpdb |
||
49 | */ |
||
50 | protected $dbInstance; |
||
51 | |||
52 | /** |
||
53 | * @var string|string[]|null |
||
54 | */ |
||
55 | protected $sqlStatement = null; |
||
56 | |||
57 | /** |
||
58 | * @var string|null |
||
59 | */ |
||
60 | protected $tablePrefix = null; |
||
61 | |||
62 | /** |
||
63 | * @var WPDBAdapter |
||
64 | */ |
||
65 | protected $adapterInstance; |
||
66 | |||
67 | /** |
||
68 | * The mode to return results as. |
||
69 | * Accepts WPDB constants or class names. |
||
70 | * |
||
71 | * @var string |
||
72 | */ |
||
73 | protected $fetchMode; |
||
74 | |||
75 | /** |
||
76 | * Custom args used to construct models for hydrator |
||
77 | * |
||
78 | * @var array<int, mixed>|null |
||
79 | */ |
||
80 | protected $hydratorConstructorArgs; |
||
81 | |||
82 | /** |
||
83 | * Handler for Json Selectors |
||
84 | * |
||
85 | * @var JsonHandler |
||
86 | */ |
||
87 | protected $jsonHandler; |
||
88 | |||
89 | /** |
||
90 | * @param \Pixie\Connection|null $connection |
||
91 | * @param string $fetchMode |
||
92 | * @param mixed[] $hydratorConstructorArgs |
||
93 | * |
||
94 | * @throws Exception if no connection passed and not previously established |
||
95 | */ |
||
96 | final public function __construct( |
||
97 | Connection $connection = null, |
||
98 | string $fetchMode = \OBJECT, |
||
99 | ?array $hydratorConstructorArgs = null |
||
100 | ) { |
||
101 | if (is_null($connection)) { |
||
102 | // throws if connection not already established. |
||
103 | $connection = Connection::getStoredConnection(); |
||
104 | } |
||
105 | |||
106 | // Set all dependencies from connection. |
||
107 | $this->connection = $connection; |
||
108 | $this->container = $this->connection->getContainer(); |
||
109 | $this->dbInstance = $this->connection->getDbInstance(); |
||
110 | $this->setAdapterConfig($this->connection->getAdapterConfig()); |
||
111 | |||
112 | // Set up optional hydration details. |
||
113 | $this->setFetchMode($fetchMode); |
||
114 | $this->hydratorConstructorArgs = $hydratorConstructorArgs; |
||
115 | |||
116 | // Query builder adapter instance |
||
117 | $this->adapterInstance = $this->container->build( |
||
118 | WPDBAdapter::class, |
||
119 | [$this->connection] |
||
120 | ); |
||
121 | |||
122 | // Setup JSON Selector handler. |
||
123 | $this->jsonHandler = new JsonHandler($connection); |
||
124 | } |
||
125 | |||
126 | /** |
||
127 | * Sets the config for WPDB |
||
128 | * |
||
129 | * @param array<string, mixed> $adapterConfig |
||
130 | * |
||
131 | * @return void |
||
132 | */ |
||
133 | protected function setAdapterConfig(array $adapterConfig): void |
||
134 | { |
||
135 | if (isset($adapterConfig[Connection::PREFIX])) { |
||
136 | $this->tablePrefix = $adapterConfig[Connection::PREFIX]; |
||
137 | } |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * Fetch query results as object of specified type |
||
142 | * |
||
143 | * @param string $className |
||
144 | * @param array<int, mixed> $constructorArgs |
||
145 | * @return static |
||
146 | */ |
||
147 | public function asObject($className, $constructorArgs = array()): self |
||
148 | { |
||
149 | return $this->setFetchMode($className, $constructorArgs); |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * Set the fetch mode |
||
154 | * |
||
155 | * @param string $mode |
||
156 | * @param array<int, mixed>|null $constructorArgs |
||
157 | * |
||
158 | * @return static |
||
159 | */ |
||
160 | public function setFetchMode(string $mode, ?array $constructorArgs = null): self |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * @param Connection|null $connection |
||
170 | * |
||
171 | * @return static |
||
172 | * |
||
173 | * @throws Exception |
||
174 | */ |
||
175 | public function newQuery(Connection $connection = null): self |
||
176 | { |
||
177 | if (is_null($connection)) { |
||
178 | $connection = $this->connection; |
||
179 | } |
||
180 | |||
181 | $newQuery = $this->constructCurrentBuilderClass($connection); |
||
182 | $newQuery->setFetchMode($this->getFetchMode(), $this->hydratorConstructorArgs); |
||
183 | |||
184 | return $newQuery; |
||
185 | } |
||
186 | |||
187 | /** |
||
188 | * Returns a new instance of the current, with the passed connection. |
||
189 | * |
||
190 | * @param \Pixie\Connection $connection |
||
191 | * |
||
192 | * @return static |
||
193 | */ |
||
194 | protected function constructCurrentBuilderClass(Connection $connection): self |
||
195 | { |
||
196 | return new static($connection); |
||
197 | } |
||
198 | |||
199 | /** |
||
200 | * Interpolates a query |
||
201 | * |
||
202 | * @param string $query |
||
203 | * @param array<mixed> $bindings |
||
204 | * @return string |
||
205 | */ |
||
206 | public function interpolateQuery(string $query, array $bindings = []): string |
||
207 | { |
||
208 | return $this->adapterInstance->interpolateQuery($query, $bindings); |
||
209 | } |
||
210 | |||
211 | /** |
||
212 | * @param string $sql |
||
213 | * @param array<int,mixed> $bindings |
||
214 | * |
||
215 | * @return static |
||
216 | */ |
||
217 | public function query($sql, $bindings = []): self |
||
218 | { |
||
219 | list($this->sqlStatement) = $this->statement($sql, $bindings); |
||
220 | |||
221 | return $this; |
||
222 | } |
||
223 | |||
224 | /** |
||
225 | * @param string $sql |
||
226 | * @param array<int,mixed> $bindings |
||
227 | * |
||
228 | * @return array{0:string, 1:float} |
||
229 | */ |
||
230 | public function statement(string $sql, $bindings = []): array |
||
231 | { |
||
232 | $start = microtime(true); |
||
233 | $sqlStatement = empty($bindings) ? $sql : $this->interpolateQuery($sql, $bindings); |
||
234 | |||
235 | if (!is_string($sqlStatement)) { |
||
|
|||
236 | throw new Exception('Could not interpolate query', 1); |
||
237 | } |
||
238 | |||
239 | return [$sqlStatement, microtime(true) - $start]; |
||
240 | } |
||
241 | |||
242 | /** |
||
243 | * Get all rows |
||
244 | * |
||
245 | * @return array<mixed,mixed>|null |
||
246 | * |
||
247 | * @throws Exception |
||
248 | */ |
||
249 | public function get() |
||
250 | { |
||
251 | $eventResult = $this->fireEvents('before-select'); |
||
252 | if (!is_null($eventResult)) { |
||
253 | return $eventResult; |
||
254 | } |
||
255 | $executionTime = 0; |
||
256 | if (is_null($this->sqlStatement)) { |
||
257 | $queryObject = $this->getQuery('select'); |
||
258 | $statement = $this->statement( |
||
259 | $queryObject->getSql(), |
||
260 | $queryObject->getBindings() |
||
261 | ); |
||
262 | |||
263 | $this->sqlStatement = $statement[0]; |
||
264 | $executionTime = $statement[1]; |
||
265 | } |
||
266 | |||
267 | $start = microtime(true); |
||
268 | $result = $this->dbInstance()->get_results( |
||
269 | is_array($this->sqlStatement) ? (end($this->sqlStatement) ?: '') : $this->sqlStatement, |
||
270 | // If we are using the hydrator, return as OBJECT and let the hydrator map the correct model. |
||
271 | $this->useHydrator() ? OBJECT : $this->getFetchMode() |
||
272 | ); |
||
273 | $executionTime += microtime(true) - $start; |
||
274 | $this->sqlStatement = null; |
||
275 | |||
276 | // Ensure we have an array of results. |
||
277 | if (!is_array($result) && null !== $result) { |
||
278 | $result = [$result]; |
||
279 | } |
||
280 | |||
281 | // Maybe hydrate the results. |
||
282 | if (null !== $result && $this->useHydrator()) { |
||
283 | $result = $this->getHydrator()->fromMany($result); |
||
284 | } |
||
285 | |||
286 | $this->fireEvents('after-select', $result, $executionTime); |
||
287 | |||
288 | return $result; |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * Returns a populated instance of the Hydrator. |
||
293 | * |
||
294 | * @return Hydrator |
||
295 | */ |
||
296 | protected function getHydrator(): Hydrator /* @phpstan-ignore-line */ |
||
297 | { |
||
298 | $hydrator = new Hydrator($this->getFetchMode(), $this->hydratorConstructorArgs ?? []); /* @phpstan-ignore-line */ |
||
299 | |||
300 | return $hydrator; |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * Checks if the results should be mapped via the hydrator |
||
305 | * |
||
306 | * @return bool |
||
307 | */ |
||
308 | protected function useHydrator(): bool |
||
311 | } |
||
312 | |||
313 | /** |
||
314 | * Find all matching a simple where condition. |
||
315 | * |
||
316 | * Shortcut of ->where('key','=','value')->limit(1)->get(); |
||
317 | * |
||
318 | * @return \stdClass\array<mixed,mixed>|object|null Can return any object using hydrator |
||
319 | */ |
||
320 | public function first() |
||
321 | { |
||
322 | $this->limit(1); |
||
323 | $result = $this->get(); |
||
324 | |||
325 | return empty($result) ? null : $result[0]; |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * Find all matching a simple where condition. |
||
330 | * |
||
331 | * Shortcut of ->where('key','=','value')->get(); |
||
332 | * |
||
333 | * @param string $fieldName |
||
334 | * @param mixed $value |
||
335 | * |
||
336 | * @return array<mixed,mixed>|null Can return any object using hydrator |
||
337 | */ |
||
338 | public function findAll($fieldName, $value) |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * @param string $fieldName |
||
347 | * @param mixed $value |
||
348 | * |
||
349 | * @return \stdClass\array<mixed,mixed>|object|null Can return any object using hydrator |
||
350 | */ |
||
351 | public function find($value, $fieldName = 'id') |
||
356 | } |
||
357 | |||
358 | /** |
||
359 | * @param string $fieldName |
||
360 | * @param mixed $value |
||
361 | * |
||
362 | * @return \stdClass\array<mixed,mixed>|object Can return any object using hydrator |
||
363 | * @throws Exception If fails to find |
||
364 | */ |
||
365 | public function findOrFail($value, $fieldName = 'id') |
||
372 | } |
||
373 | |||
374 | /** |
||
375 | * Used to handle all aggregation method. |
||
376 | * |
||
377 | * @see Taken from the pecee-pixie library - https://github.com/skipperbent/pecee-pixie/ |
||
378 | * |
||
379 | * @param string $type |
||
380 | * @param string|Raw $field |
||
381 | * |
||
382 | * @return float |
||
383 | */ |
||
384 | protected function aggregate(string $type, $field = '*'): float |
||
412 | } |
||
413 | |||
414 | /** |
||
415 | * Get count of all the rows for the current query |
||
416 | * |
||
417 | * @see Taken from the pecee-pixie library - https://github.com/skipperbent/pecee-pixie/ |
||
418 | * |
||
419 | * @param string|Raw $field |
||
420 | * |
||
421 | * @return int |
||
422 | * |
||
423 | * @throws Exception |
||
424 | */ |
||
425 | public function count($field = '*'): int |
||
426 | { |
||
427 | return (int)$this->aggregate('count', $field); |
||
428 | } |
||
429 | |||
430 | /** |
||
431 | * Get the sum for a field in the current query |
||
432 | * |
||
433 | * @see Taken from the pecee-pixie library - https://github.com/skipperbent/pecee-pixie/ |
||
434 | * |
||
435 | * @param string|Raw $field |
||
436 | * |
||
437 | * @return float |
||
438 | * |
||
439 | * @throws Exception |
||
440 | */ |
||
441 | public function sum($field): float |
||
442 | { |
||
443 | return $this->aggregate('sum', $field); |
||
444 | } |
||
445 | |||
446 | /** |
||
447 | * Get the average for a field in the current query |
||
448 | * |
||
449 | * @see Taken from the pecee-pixie library - https://github.com/skipperbent/pecee-pixie/ |
||
450 | * |
||
451 | * @param string|Raw $field |
||
452 | * |
||
453 | * @return float |
||
454 | * |
||
455 | * @throws Exception |
||
456 | */ |
||
457 | public function average($field): float |
||
458 | { |
||
459 | return $this->aggregate('avg', $field); |
||
460 | } |
||
461 | |||
462 | /** |
||
463 | * Get the minimum for a field in the current query |
||
464 | * |
||
465 | * @see Taken from the pecee-pixie library - https://github.com/skipperbent/pecee-pixie/ |
||
466 | * |
||
467 | * @param string|Raw $field |
||
468 | * |
||
469 | * @return float |
||
470 | * |
||
471 | * @throws Exception |
||
472 | */ |
||
473 | public function min($field): float |
||
474 | { |
||
475 | return $this->aggregate('min', $field); |
||
476 | } |
||
477 | |||
478 | /** |
||
479 | * Get the maximum for a field in the current query |
||
480 | * |
||
481 | * @see Taken from the pecee-pixie library - https://github.com/skipperbent/pecee-pixie/ |
||
482 | * |
||
483 | * @param string|Raw $field |
||
484 | * |
||
485 | * @return float |
||
486 | * |
||
487 | * @throws Exception |
||
488 | */ |
||
489 | public function max($field): float |
||
490 | { |
||
491 | return $this->aggregate('max', $field); |
||
492 | } |
||
493 | |||
494 | /** |
||
495 | * @param string $type |
||
496 | * @param bool|array<mixed, mixed> $dataToBePassed |
||
497 | * |
||
498 | * @return mixed |
||
499 | * |
||
500 | * @throws Exception |
||
501 | */ |
||
502 | public function getQuery(string $type = 'select', $dataToBePassed = []) |
||
503 | { |
||
504 | $allowedTypes = ['select', 'insert', 'insertignore', 'replace', 'delete', 'update', 'criteriaonly']; |
||
505 | if (!in_array(strtolower($type), $allowedTypes)) { |
||
506 | throw new Exception($type . ' is not a known type.', 2); |
||
507 | } |
||
508 | |||
509 | $queryArr = $this->adapterInstance->$type($this->statements, $dataToBePassed); |
||
510 | |||
511 | return $this->container->build( |
||
512 | QueryObject::class, |
||
513 | [$queryArr['sql'], $queryArr['bindings'], $this->dbInstance] |
||
514 | ); |
||
515 | } |
||
516 | |||
517 | /** |
||
518 | * @param QueryBuilderHandler $queryBuilder |
||
519 | * @param string|null $alias |
||
520 | * |
||
521 | * @return Raw |
||
522 | */ |
||
523 | public function subQuery(QueryBuilderHandler $queryBuilder, ?string $alias = null) |
||
524 | { |
||
525 | $sql = '(' . $queryBuilder->getQuery()->getRawSql() . ')'; |
||
526 | if (is_string($alias) && 0 !== mb_strlen($alias)) { |
||
527 | $sql = $sql . ' as ' . $alias; |
||
528 | } |
||
529 | |||
530 | return $queryBuilder->raw($sql); |
||
531 | } |
||
532 | |||
533 | /** |
||
534 | * Handles the various insert operations based on the type. |
||
535 | * |
||
536 | * @param array<int|string, mixed|mixed[]> $data |
||
537 | * @param string $type |
||
538 | * |
||
539 | * @return int|int[]|mixed|null can return a single row id, array of row ids, null (for failed) or any other value short circuited from event |
||
540 | */ |
||
541 | private function doInsert(array $data, string $type) |
||
542 | { |
||
543 | $eventResult = $this->fireEvents('before-insert'); |
||
544 | if (!is_null($eventResult)) { |
||
545 | return $eventResult; |
||
546 | } |
||
547 | |||
548 | // If first value is not an array () not a batch insert) |
||
549 | if (!is_array(current($data))) { |
||
550 | $queryObject = $this->getQuery($type, $data); |
||
551 | |||
552 | list($preparedQuery, $executionTime) = $this->statement($queryObject->getSql(), $queryObject->getBindings()); |
||
553 | $this->dbInstance->get_results($preparedQuery); |
||
554 | |||
555 | // Check we have a result. |
||
556 | $return = 1 === $this->dbInstance->rows_affected ? $this->dbInstance->insert_id : null; |
||
557 | } else { |
||
558 | // Its a batch insert |
||
559 | $return = []; |
||
560 | $executionTime = 0; |
||
561 | foreach ($data as $subData) { |
||
562 | $queryObject = $this->getQuery($type, $subData); |
||
563 | |||
564 | list($preparedQuery, $time) = $this->statement($queryObject->getSql(), $queryObject->getBindings()); |
||
565 | $this->dbInstance->get_results($preparedQuery); |
||
566 | $executionTime += $time; |
||
567 | |||
568 | if (1 === $this->dbInstance->rows_affected) { |
||
569 | $return[] = $this->dbInstance->insert_id; |
||
570 | } |
||
571 | } |
||
572 | } |
||
573 | |||
574 | $this->fireEvents('after-insert', $return, $executionTime); |
||
575 | |||
576 | return $return; |
||
577 | } |
||
578 | |||
579 | /** |
||
580 | * @param array<int|string, mixed|mixed[]> $data either key=>value array for single or array of arrays for bulk |
||
581 | * |
||
582 | * @return int|int[]|mixed|null can return a single row id, array of row ids, null (for failed) or any other value short circuited from event |
||
583 | */ |
||
584 | public function insert($data) |
||
585 | { |
||
586 | return $this->doInsert($data, 'insert'); |
||
587 | } |
||
588 | |||
589 | /** |
||
590 | * |
||
591 | * @param array<int|string, mixed|mixed[]> $data either key=>value array for single or array of arrays for bulk |
||
592 | * |
||
593 | * @return int|int[]|mixed|null can return a single row id, array of row ids, null (for failed) or any other value short circuited from event |
||
594 | */ |
||
595 | public function insertIgnore($data) |
||
598 | } |
||
599 | |||
600 | /** |
||
601 | * |
||
602 | * @param array<int|string, mixed|mixed[]> $data either key=>value array for single or array of arrays for bulk |
||
603 | * |
||
604 | * @return int|int[]|mixed|null can return a single row id, array of row ids, null (for failed) or any other value short circuited from event |
||
605 | */ |
||
606 | public function replace($data) |
||
607 | { |
||
608 | return $this->doInsert($data, 'replace'); |
||
609 | } |
||
610 | |||
611 | /** |
||
612 | * @param array<string, mixed> $data |
||
613 | * |
||
614 | * @return int|null Number of row effected, null for none. |
||
615 | */ |
||
616 | public function update(array $data): ?int |
||
631 | } |
||
632 | |||
633 | /** |
||
634 | * Update or Insert based on the attributes. |
||
635 | * |
||
636 | * @param array<string, mixed> $attributes Conditions to check |
||
637 | * @param array<string, mixed> $values Values to add/update |
||
638 | * |
||
639 | * @return int|int[]|null will return row id(s) for insert and null for success/fail on update |
||
640 | */ |
||
641 | public function updateOrInsert(array $attributes, array $values = []) |
||
642 | { |
||
643 | // Check if existing post exists. |
||
644 | $query = clone $this; |
||
645 | foreach ($attributes as $column => $value) { |
||
646 | $query->where($column, $value); |
||
647 | } |
||
648 | |||
649 | // If we have a result, update it. |
||
650 | if (null !== $query->first()) { |
||
651 | foreach ($attributes as $column => $value) { |
||
652 | $this->where($column, $value); |
||
653 | } |
||
654 | |||
655 | return $this->update($values); |
||
656 | } |
||
657 | |||
658 | // Else insert |
||
659 | return $this->insert($values); |
||
660 | } |
||
661 | |||
662 | /** |
||
663 | * @param array<string, mixed> $data |
||
664 | * |
||
665 | * @return static |
||
666 | */ |
||
667 | public function onDuplicateKeyUpdate($data) |
||
668 | { |
||
669 | $this->addStatement('onduplicate', $data); |
||
670 | |||
671 | return $this; |
||
672 | } |
||
673 | |||
674 | /** |
||
675 | * @return mixed number of rows effected or shortcircuited response |
||
676 | */ |
||
677 | public function delete() |
||
678 | { |
||
679 | $eventResult = $this->fireEvents('before-delete'); |
||
680 | if (!is_null($eventResult)) { |
||
681 | return $eventResult; |
||
682 | } |
||
683 | |||
684 | $queryObject = $this->getQuery('delete'); |
||
685 | |||
686 | list($preparedQuery, $executionTime) = $this->statement($queryObject->getSql(), $queryObject->getBindings()); |
||
687 | $this->dbInstance()->get_results($preparedQuery); |
||
688 | $this->fireEvents('after-delete', $queryObject, $executionTime); |
||
689 | |||
690 | return $this->dbInstance()->rows_affected; |
||
691 | } |
||
692 | |||
693 | /** |
||
694 | * @param string|Raw ...$tables Single table or array of tables |
||
695 | * |
||
696 | * @return static |
||
697 | * |
||
698 | * @throws Exception |
||
699 | */ |
||
700 | public function table(...$tables) |
||
701 | { |
||
702 | $instance = $this->constructCurrentBuilderClass($this->connection); |
||
703 | $this->setFetchMode($this->getFetchMode(), $this->hydratorConstructorArgs); |
||
704 | $tables = $this->addTablePrefix($tables, false); |
||
705 | $instance->addStatement('tables', $tables); |
||
706 | |||
707 | return $instance; |
||
708 | } |
||
709 | |||
710 | /** |
||
711 | * @param string|Raw ...$tables Single table or array of tables |
||
712 | * |
||
713 | * @return static |
||
714 | */ |
||
715 | public function from(...$tables): self |
||
716 | { |
||
717 | $tables = $this->addTablePrefix($tables, false); |
||
718 | $this->addStatement('tables', $tables); |
||
719 | |||
720 | return $this; |
||
721 | } |
||
722 | |||
723 | /** |
||
724 | * @param string|string[]|Raw[]|array<string, string> $fields |
||
725 | * |
||
726 | * @return static |
||
727 | */ |
||
728 | public function select($fields): self |
||
729 | { |
||
730 | if (!is_array($fields)) { |
||
731 | $fields = func_get_args(); |
||
732 | } |
||
733 | |||
734 | foreach ($fields as $field => $alias) { |
||
735 | // If we have a JSON expression |
||
736 | if ($this->jsonHandler->isJsonSelector($field)) { |
||
737 | $field = $this->jsonHandler->extractAndUnquoteFromJsonSelector($field); |
||
738 | } |
||
739 | |||
740 | // If no alias passed, but field is for JSON. thrown an exception. |
||
741 | if (is_numeric($field) && is_string($alias) && $this->jsonHandler->isJsonSelector($alias)) { |
||
742 | throw new Exception("An alias must be used if you wish to select from JSON Object", 1); |
||
743 | } |
||
744 | |||
745 | // Treat each array as a single table, to retain order added |
||
746 | $field = is_numeric($field) |
||
747 | ? $field = $alias // If single colum |
||
748 | : $field = [$field => $alias]; // Has alias |
||
749 | |||
750 | $field = $this->addTablePrefix($field); |
||
751 | $this->addStatement('selects', $field); |
||
752 | } |
||
753 | |||
754 | return $this; |
||
755 | } |
||
756 | |||
757 | /** |
||
758 | * @param string|string[]|Raw[]|array<string, string> $fields |
||
759 | * |
||
760 | * @return static |
||
761 | */ |
||
762 | public function selectDistinct($fields) |
||
763 | { |
||
764 | $this->select($fields); |
||
765 | $this->addStatement('distinct', true); |
||
766 | |||
767 | return $this; |
||
768 | } |
||
769 | |||
770 | /** |
||
771 | * @param string|string[] $field either the single field or an array of fields |
||
772 | * |
||
773 | * @return static |
||
774 | */ |
||
775 | public function groupBy($field): self |
||
776 | { |
||
777 | $field = $this->addTablePrefix($field); |
||
778 | $this->addStatement('groupBys', $field); |
||
779 | |||
780 | return $this; |
||
781 | } |
||
782 | |||
783 | /** |
||
784 | * @param string|array<string|int, mixed> $fields |
||
785 | * @param string $defaultDirection |
||
786 | * |
||
787 | * @return static |
||
788 | */ |
||
789 | public function orderBy($fields, string $defaultDirection = 'ASC'): self |
||
790 | { |
||
791 | if (!is_array($fields)) { |
||
792 | $fields = [$fields]; |
||
793 | } |
||
794 | |||
795 | foreach ($fields as $key => $value) { |
||
796 | $field = $key; |
||
797 | $type = $value; |
||
798 | if (is_int($key)) { |
||
799 | $field = $value; |
||
800 | $type = $defaultDirection; |
||
801 | } |
||
802 | |||
803 | if ($this->jsonHandler->isJsonSelector($field)) { |
||
804 | $field = $this->jsonHandler->extractAndUnquoteFromJsonSelector($field); |
||
805 | } |
||
806 | |||
807 | if (!$field instanceof Raw) { |
||
808 | $field = $this->addTablePrefix($field); |
||
809 | } |
||
810 | $this->statements['orderBys'][] = compact('field', 'type'); |
||
811 | } |
||
812 | |||
813 | return $this; |
||
814 | } |
||
815 | |||
816 | /** |
||
817 | * @param string|Raw $key The database column which holds the JSON value |
||
818 | * @param string|Raw|string[] $jsonKey The json key/index to search |
||
819 | * @param string $defaultDirection |
||
820 | * @return static |
||
821 | */ |
||
822 | public function orderByJson($key, $jsonKey, string $defaultDirection = 'ASC'): self |
||
823 | { |
||
824 | $key = $this->jsonHandler->jsonExpressionFactory()->extractAndUnquote($key, $jsonKey); |
||
825 | return $this->orderBy($key, $defaultDirection); |
||
826 | } |
||
827 | |||
828 | /** |
||
829 | * @param int $limit |
||
830 | * |
||
831 | * @return static |
||
832 | */ |
||
833 | public function limit(int $limit): self |
||
834 | { |
||
835 | $this->statements['limit'] = $limit; |
||
836 | |||
837 | return $this; |
||
838 | } |
||
839 | |||
840 | /** |
||
841 | * @param int $offset |
||
842 | * |
||
843 | * @return static |
||
844 | */ |
||
845 | public function offset(int $offset): self |
||
846 | { |
||
847 | $this->statements['offset'] = $offset; |
||
848 | |||
849 | return $this; |
||
850 | } |
||
851 | |||
852 | /** |
||
853 | * @param string|string[]|Raw|Raw[] $key |
||
854 | * @param string $operator |
||
855 | * @param mixed $value |
||
856 | * @param string $joiner |
||
857 | * |
||
858 | * @return static |
||
859 | */ |
||
860 | public function having($key, string $operator, $value, string $joiner = 'AND') |
||
861 | { |
||
862 | $key = $this->addTablePrefix($key); |
||
863 | $this->statements['havings'][] = compact('key', 'operator', 'value', 'joiner'); |
||
864 | |||
865 | return $this; |
||
866 | } |
||
867 | |||
868 | /** |
||
869 | * @param string|string[]|Raw|Raw[] $key |
||
870 | * @param string $operator |
||
871 | * @param mixed $value |
||
872 | * |
||
873 | * @return static |
||
874 | */ |
||
875 | public function orHaving($key, $operator, $value) |
||
876 | { |
||
877 | return $this->having($key, $operator, $value, 'OR'); |
||
878 | } |
||
879 | |||
880 | /** |
||
881 | * @param string|Raw $key |
||
882 | * @param string|mixed|null $operator Can be used as value, if 3rd arg not passed |
||
883 | * @param mixed|null $value |
||
884 | * |
||
885 | * @return static |
||
886 | */ |
||
887 | public function where($key, $operator = null, $value = null): self |
||
888 | { |
||
889 | // If two params are given then assume operator is = |
||
890 | if (2 === func_num_args()) { |
||
891 | $value = $operator; |
||
892 | $operator = '='; |
||
893 | } |
||
894 | |||
895 | return $this->whereHandler($key, $operator, $value); |
||
896 | } |
||
897 | |||
898 | /** |
||
899 | * @param string|Raw|\Closure(QueryBuilderHandler):void $key |
||
900 | * @param string|mixed|null $operator Can be used as value, if 3rd arg not passed |
||
901 | * @param mixed|null $value |
||
902 | * |
||
903 | * @return static |
||
904 | */ |
||
905 | public function orWhere($key, $operator = null, $value = null): self |
||
906 | { |
||
907 | // If two params are given then assume operator is = |
||
908 | if (2 === func_num_args()) { |
||
909 | $value = $operator; |
||
910 | $operator = '='; |
||
911 | } |
||
912 | |||
913 | return $this->whereHandler($key, $operator, $value, 'OR'); |
||
914 | } |
||
915 | |||
916 | /** |
||
917 | * @param string|Raw $key |
||
918 | * @param string|mixed|null $operator Can be used as value, if 3rd arg not passed |
||
919 | * @param mixed|null $value |
||
920 | * |
||
921 | * @return static |
||
922 | */ |
||
923 | public function whereNot($key, $operator = null, $value = null): self |
||
924 | { |
||
925 | // If two params are given then assume operator is = |
||
926 | if (2 === func_num_args()) { |
||
927 | $value = $operator; |
||
928 | $operator = '='; |
||
929 | } |
||
930 | |||
931 | return $this->whereHandler($key, $operator, $value, 'AND NOT'); |
||
932 | } |
||
933 | |||
934 | /** |
||
935 | * @param string|Raw $key |
||
936 | * @param string|mixed|null $operator Can be used as value, if 3rd arg not passed |
||
937 | * @param mixed|null $value |
||
938 | * |
||
939 | * @return static |
||
940 | */ |
||
941 | public function orWhereNot($key, $operator = null, $value = null) |
||
942 | { |
||
943 | // If two params are given then assume operator is = |
||
944 | if (2 === func_num_args()) { |
||
945 | $value = $operator; |
||
946 | $operator = '='; |
||
947 | } |
||
948 | |||
949 | return $this->whereHandler($key, $operator, $value, 'OR NOT'); |
||
950 | } |
||
951 | |||
952 | /** |
||
953 | * @param string|Raw $key |
||
954 | * @param mixed[]|string|Raw $values |
||
955 | * |
||
956 | * @return static |
||
957 | */ |
||
958 | public function whereIn($key, $values): self |
||
959 | { |
||
960 | return $this->whereHandler($key, 'IN', $values, 'AND'); |
||
961 | } |
||
962 | |||
963 | /** |
||
964 | * @param string|Raw $key |
||
965 | * @param mixed[]|string|Raw $values |
||
966 | * |
||
967 | * @return static |
||
968 | */ |
||
969 | public function whereNotIn($key, $values): self |
||
970 | { |
||
971 | return $this->whereHandler($key, 'NOT IN', $values, 'AND'); |
||
972 | } |
||
973 | |||
974 | /** |
||
975 | * @param string|Raw $key |
||
976 | * @param mixed[]|string|Raw $values |
||
977 | * |
||
978 | * @return static |
||
979 | */ |
||
980 | public function orWhereIn($key, $values): self |
||
981 | { |
||
982 | return $this->whereHandler($key, 'IN', $values, 'OR'); |
||
983 | } |
||
984 | |||
985 | /** |
||
986 | * @param string|Raw $key |
||
987 | * @param mixed[]|string|Raw $values |
||
988 | * |
||
989 | * @return static |
||
990 | */ |
||
991 | public function orWhereNotIn($key, $values): self |
||
992 | { |
||
993 | return $this->whereHandler($key, 'NOT IN', $values, 'OR'); |
||
994 | } |
||
995 | |||
996 | /** |
||
997 | * @param string|Raw $key |
||
998 | * @param mixed $valueFrom |
||
999 | * @param mixed $valueTo |
||
1000 | * |
||
1001 | * @return static |
||
1002 | */ |
||
1003 | public function whereBetween($key, $valueFrom, $valueTo): self |
||
1004 | { |
||
1005 | return $this->whereHandler($key, 'BETWEEN', [$valueFrom, $valueTo], 'AND'); |
||
1006 | } |
||
1007 | |||
1008 | /** |
||
1009 | * @param string|Raw $key |
||
1010 | * @param mixed $valueFrom |
||
1011 | * @param mixed $valueTo |
||
1012 | * |
||
1013 | * @return static |
||
1014 | */ |
||
1015 | public function orWhereBetween($key, $valueFrom, $valueTo): self |
||
1016 | { |
||
1017 | return $this->whereHandler($key, 'BETWEEN', [$valueFrom, $valueTo], 'OR'); |
||
1018 | } |
||
1019 | |||
1020 | /** |
||
1021 | * Handles all function call based where conditions |
||
1022 | * |
||
1023 | * @param string|Raw $key |
||
1024 | * @param string $function |
||
1025 | * @param string|mixed|null $operator Can be used as value, if 3rd arg not passed |
||
1026 | * @param mixed|null $value |
||
1027 | * @return static |
||
1028 | */ |
||
1029 | protected function whereFunctionCallHandler($key, $function, $operator, $value): self |
||
1030 | { |
||
1031 | $key = \sprintf('%s(%s)', $function, $this->addTablePrefix($key)); |
||
1032 | return $this->where($key, $operator, $value); |
||
1033 | } |
||
1034 | |||
1035 | /** |
||
1036 | * @param string|Raw $key |
||
1037 | * @param string|mixed|null $operator Can be used as value, if 3rd arg not passed |
||
1038 | * @param mixed|null $value |
||
1039 | * @return self |
||
1040 | */ |
||
1041 | public function whereMonth($key, $operator = null, $value = null): self |
||
1042 | { |
||
1043 | // If two params are given then assume operator is = |
||
1044 | if (2 === func_num_args()) { |
||
1045 | $value = $operator; |
||
1046 | $operator = '='; |
||
1047 | } |
||
1048 | return $this->whereFunctionCallHandler($key, 'MONTH', $operator, $value); |
||
1049 | } |
||
1050 | |||
1051 | /** |
||
1052 | * @param string|Raw $key |
||
1053 | * @param string|mixed|null $operator Can be used as value, if 3rd arg not passed |
||
1054 | * @param mixed|null $value |
||
1055 | * @return self |
||
1056 | */ |
||
1057 | public function whereDay($key, $operator = null, $value = null): self |
||
1058 | { |
||
1059 | // If two params are given then assume operator is = |
||
1060 | if (2 === func_num_args()) { |
||
1061 | $value = $operator; |
||
1062 | $operator = '='; |
||
1063 | } |
||
1064 | return $this->whereFunctionCallHandler($key, 'DAY', $operator, $value); |
||
1065 | } |
||
1066 | |||
1067 | /** |
||
1068 | * @param string|Raw $key |
||
1069 | * @param string|mixed|null $operator Can be used as value, if 3rd arg not passed |
||
1070 | * @param mixed|null $value |
||
1071 | * @return self |
||
1072 | */ |
||
1073 | public function whereYear($key, $operator = null, $value = null): self |
||
1074 | { |
||
1075 | // If two params are given then assume operator is = |
||
1076 | if (2 === func_num_args()) { |
||
1077 | $value = $operator; |
||
1078 | $operator = '='; |
||
1079 | } |
||
1080 | return $this->whereFunctionCallHandler($key, 'YEAR', $operator, $value); |
||
1081 | } |
||
1082 | |||
1083 | /** |
||
1084 | * @param string|Raw $key |
||
1085 | * @param string|mixed|null $operator Can be used as value, if 3rd arg not passed |
||
1086 | * @param mixed|null $value |
||
1087 | * @return self |
||
1088 | */ |
||
1089 | public function whereDate($key, $operator = null, $value = null): self |
||
1090 | { |
||
1091 | // If two params are given then assume operator is = |
||
1092 | if (2 === func_num_args()) { |
||
1093 | $value = $operator; |
||
1094 | $operator = '='; |
||
1095 | } |
||
1096 | return $this->whereFunctionCallHandler($key, 'DATE', $operator, $value); |
||
1097 | } |
||
1098 | |||
1099 | /** |
||
1100 | * @param string|Raw $key |
||
1101 | * |
||
1102 | * @return static |
||
1103 | */ |
||
1104 | public function whereNull($key): self |
||
1105 | { |
||
1106 | return $this->whereNullHandler($key); |
||
1107 | } |
||
1108 | |||
1109 | /** |
||
1110 | * @param string|Raw $key |
||
1111 | * |
||
1112 | * @return static |
||
1113 | */ |
||
1114 | public function whereNotNull($key): self |
||
1115 | { |
||
1116 | return $this->whereNullHandler($key, 'NOT'); |
||
1117 | } |
||
1118 | |||
1119 | /** |
||
1120 | * @param string|Raw $key |
||
1121 | * |
||
1122 | * @return static |
||
1123 | */ |
||
1124 | public function orWhereNull($key): self |
||
1125 | { |
||
1126 | return $this->whereNullHandler($key, '', 'or'); |
||
1127 | } |
||
1128 | |||
1129 | /** |
||
1130 | * @param string|Raw $key |
||
1131 | * |
||
1132 | * @return static |
||
1133 | */ |
||
1134 | public function orWhereNotNull($key): self |
||
1135 | { |
||
1136 | return $this->whereNullHandler($key, 'NOT', 'or'); |
||
1137 | } |
||
1138 | |||
1139 | /** |
||
1140 | * @param string|Raw $key |
||
1141 | * @param string $prefix |
||
1142 | * @param string $operator |
||
1143 | * |
||
1144 | * @return static |
||
1145 | */ |
||
1146 | protected function whereNullHandler($key, string $prefix = '', $operator = ''): self |
||
1147 | { |
||
1148 | $prefix = 0 === mb_strlen($prefix) ? '' : " {$prefix}"; |
||
1149 | |||
1150 | if ($key instanceof Raw) { |
||
1151 | $key = $this->adapterInstance->parseRaw($key); |
||
1152 | } |
||
1153 | |||
1154 | $key = $this->addTablePrefix($key); |
||
1155 | if ($key instanceof Closure) { |
||
1156 | throw new Exception('Key used for whereNull condition must be a string or raw exrpession.', 1); |
||
1157 | } |
||
1158 | |||
1159 | return $this->{$operator . 'Where'}($this->raw("{$key} IS{$prefix} NULL")); |
||
1160 | } |
||
1161 | |||
1162 | |||
1163 | /** |
||
1164 | * Runs a transaction |
||
1165 | * |
||
1166 | * @param \Closure(Transaction):void $callback |
||
1167 | * |
||
1168 | * @return static |
||
1169 | */ |
||
1170 | public function transaction(Closure $callback): self |
||
1193 | } |
||
1194 | } |
||
1195 | |||
1196 | /** |
||
1197 | * Handles the transaction call. |
||
1198 | * Catches any WPDB Errors (printed) |
||
1199 | * |
||
1200 | * @param Closure $callback |
||
1201 | * @param Transaction $transaction |
||
1202 | * |
||
1203 | * @return void |
||
1204 | * @throws Exception |
||
1205 | */ |
||
1206 | protected function handleTransactionCall(Closure $callback, Transaction $transaction): void |
||
1207 | { |
||
1208 | try { |
||
1209 | ob_start(); |
||
1210 | $callback($transaction); |
||
1211 | $output = ob_get_clean() ?: ''; |
||
1212 | } catch (Throwable $th) { |
||
1213 | ob_end_clean(); |
||
1214 | throw $th; |
||
1215 | } |
||
1216 | |||
1217 | // If we caught an error, throw an exception. |
||
1218 | if (0 !== mb_strlen($output)) { |
||
1219 | throw new Exception($output); |
||
1220 | } |
||
1221 | } |
||
1222 | |||
1223 | /*************************************************************************/ |
||
1224 | /*************************************************************************/ |
||
1225 | /*************************************************************************/ |
||
1226 | /** JOIN JOIN **/ |
||
1227 | /** JOIN **/ |
||
1228 | /** JOIN JOIN **/ |
||
1229 | /*************************************************************************/ |
||
1230 | /*************************************************************************/ |
||
1231 | /*************************************************************************/ |
||
1232 | |||
1233 | /** |
||
1234 | * @param string|Raw $table |
||
1235 | * @param string|Raw|Closure $key |
||
1236 | * @param string|null $operator |
||
1237 | * @param mixed $value |
||
1238 | * @param string $type |
||
1239 | * |
||
1240 | * @return static |
||
1241 | */ |
||
1242 | public function join($table, $key, ?string $operator = null, $value = null, $type = 'inner') |
||
1243 | { |
||
1244 | // Potentially cast key from JSON |
||
1245 | if ($this->jsonHandler->isJsonSelector($key)) { |
||
1246 | /** @var string $key */ |
||
1247 | $key = $this->jsonHandler->extractAndUnquoteFromJsonSelector($key); /** @phpstan-ignore-line */ |
||
1248 | } |
||
1249 | |||
1250 | // Potentially cast value from json |
||
1251 | if ($this->jsonHandler->isJsonSelector($value)) { |
||
1252 | /** @var string $value */ |
||
1253 | $value = $this->jsonHandler->extractAndUnquoteFromJsonSelector($value); |
||
1254 | } |
||
1255 | |||
1256 | if (!$key instanceof Closure) { |
||
1257 | $key = function ($joinBuilder) use ($key, $operator, $value) { |
||
1258 | $joinBuilder->on($key, $operator, $value); |
||
1259 | }; |
||
1260 | } |
||
1261 | |||
1262 | // Build a new JoinBuilder class, keep it by reference so any changes made |
||
1263 | // in the closure should reflect here |
||
1264 | $joinBuilder = $this->container->build(JoinBuilder::class, [$this->connection]); |
||
1265 | $joinBuilder = &$joinBuilder; |
||
1266 | // Call the closure with our new joinBuilder object |
||
1267 | $key($joinBuilder); |
||
1268 | $table = $this->addTablePrefix($table, false); |
||
1269 | // Get the criteria only query from the joinBuilder object |
||
1270 | $this->statements['joins'][] = compact('type', 'table', 'joinBuilder'); |
||
1271 | return $this; |
||
1272 | } |
||
1273 | |||
1274 | /** |
||
1275 | * @param string|Raw $table |
||
1276 | * @param string|Raw|Closure $key |
||
1277 | * @param string|null $operator |
||
1278 | * @param mixed $value |
||
1279 | * |
||
1280 | * @return static |
||
1281 | */ |
||
1282 | public function leftJoin($table, $key, $operator = null, $value = null) |
||
1283 | { |
||
1284 | return $this->join($table, $key, $operator, $value, 'left'); |
||
1285 | } |
||
1286 | |||
1287 | /** |
||
1288 | * @param string|Raw $table |
||
1289 | * @param string|Raw|Closure $key |
||
1290 | * @param string|null $operator |
||
1291 | * @param mixed $value |
||
1292 | * |
||
1293 | * @return static |
||
1294 | */ |
||
1295 | public function rightJoin($table, $key, $operator = null, $value = null) |
||
1296 | { |
||
1297 | return $this->join($table, $key, $operator, $value, 'right'); |
||
1298 | } |
||
1299 | |||
1300 | /** |
||
1301 | * @param string|Raw $table |
||
1302 | * @param string|Raw|Closure $key |
||
1303 | * @param string|null $operator |
||
1304 | * @param mixed $value |
||
1305 | * |
||
1306 | * @return static |
||
1307 | */ |
||
1308 | public function innerJoin($table, $key, $operator = null, $value = null) |
||
1309 | { |
||
1310 | return $this->join($table, $key, $operator, $value, 'inner'); |
||
1311 | } |
||
1312 | |||
1313 | /** |
||
1314 | * @param string|Raw $table |
||
1315 | * @param string|Raw|Closure $key |
||
1316 | * @param string|null $operator |
||
1317 | * @param mixed $value |
||
1318 | * |
||
1319 | * @return static |
||
1320 | */ |
||
1321 | public function crossJoin($table, $key, $operator = null, $value = null) |
||
1322 | { |
||
1323 | return $this->join($table, $key, $operator, $value, 'cross'); |
||
1324 | } |
||
1325 | |||
1326 | /** |
||
1327 | * @param string|Raw $table |
||
1328 | * @param string|Raw|Closure $key |
||
1329 | * @param string|null $operator |
||
1330 | * @param mixed $value |
||
1331 | * |
||
1332 | * @return static |
||
1333 | */ |
||
1334 | public function outerJoin($table, $key, $operator = null, $value = null) |
||
1335 | { |
||
1336 | return $this->join($table, $key, $operator, $value, 'full outer'); |
||
1337 | } |
||
1338 | |||
1339 | /** |
||
1340 | * Shortcut to join 2 tables on the same key name with equals |
||
1341 | * |
||
1342 | * @param string $table |
||
1343 | * @param string $key |
||
1344 | * @param string $type |
||
1345 | * @return self |
||
1346 | * @throws Exception If base table is set as more than 1 or 0 |
||
1347 | */ |
||
1348 | public function joinUsing(string $table, string $key, string $type = 'INNER'): self |
||
1349 | { |
||
1350 | if (!array_key_exists('tables', $this->statements) || count($this->statements['tables']) !== 1) { |
||
1351 | throw new Exception("JoinUsing can only be used with a single table set as the base of the query", 1); |
||
1352 | } |
||
1353 | $baseTable = end($this->statements['tables']); |
||
1354 | |||
1355 | // Potentialy cast key from JSON |
||
1356 | if ($this->jsonHandler->isJsonSelector($key)) { |
||
1357 | $key = $this->jsonHandler->extractAndUnquoteFromJsonSelector($key); |
||
1358 | } |
||
1359 | |||
1360 | $remoteKey = $table = $this->addTablePrefix("{$table}.{$key}", true); |
||
1361 | $localKey = $table = $this->addTablePrefix("{$baseTable}.{$key}", true); |
||
1362 | return $this->join($table, $remoteKey, '=', $localKey, $type); |
||
1363 | } |
||
1364 | |||
1365 | /** |
||
1366 | * Add a raw query |
||
1367 | * |
||
1368 | * @param string|Raw $value |
||
1369 | * @param mixed|mixed[] $bindings |
||
1370 | * |
||
1371 | * @return Raw |
||
1372 | */ |
||
1373 | public function raw($value, $bindings = []): Raw |
||
1374 | { |
||
1375 | return new Raw($value, $bindings); |
||
1376 | } |
||
1377 | |||
1378 | /** |
||
1379 | * Return wpdb instance |
||
1380 | * |
||
1381 | * @return wpdb |
||
1382 | */ |
||
1383 | public function dbInstance(): wpdb |
||
1384 | { |
||
1385 | return $this->dbInstance; |
||
1386 | } |
||
1387 | |||
1388 | /** |
||
1389 | * @param Connection $connection |
||
1390 | * |
||
1391 | * @return static |
||
1392 | */ |
||
1393 | public function setConnection(Connection $connection): self |
||
1394 | { |
||
1395 | $this->connection = $connection; |
||
1396 | |||
1397 | return $this; |
||
1398 | } |
||
1399 | |||
1400 | /** |
||
1401 | * @return Connection |
||
1402 | */ |
||
1403 | public function getConnection(): Connection |
||
1406 | } |
||
1407 | |||
1408 | /** |
||
1409 | * @param string|Raw|Closure $key |
||
1410 | * @param string|null $operator |
||
1411 | * @param mixed|null $value |
||
1412 | * @param string $joiner |
||
1413 | * |
||
1414 | * @return static |
||
1415 | */ |
||
1416 | protected function whereHandler($key, $operator = null, $value = null, $joiner = 'AND') |
||
1417 | { |
||
1418 | $key = $this->addTablePrefix($key); |
||
1419 | if ($key instanceof Raw) { |
||
1420 | $key = $this->adapterInstance->parseRaw($key); |
||
1421 | } |
||
1422 | |||
1423 | if ($this->jsonHandler->isJsonSelector($key)) { |
||
1424 | $key = $this->jsonHandler->extractAndUnquoteFromJsonSelector($key); |
||
1425 | } |
||
1426 | |||
1427 | $this->statements['wheres'][] = compact('key', 'operator', 'value', 'joiner'); |
||
1428 | return $this; |
||
1429 | } |
||
1430 | |||
1431 | |||
1432 | |||
1433 | /** |
||
1434 | * @param string $key |
||
1435 | * @param mixed|mixed[]|bool $value |
||
1436 | * |
||
1437 | * @return void |
||
1438 | */ |
||
1439 | protected function addStatement($key, $value) |
||
1440 | { |
||
1441 | if (!is_array($value)) { |
||
1442 | $value = [$value]; |
||
1443 | } |
||
1444 | |||
1445 | if (!array_key_exists($key, $this->statements)) { |
||
1446 | $this->statements[$key] = $value; |
||
1447 | } else { |
||
1448 | $this->statements[$key] = array_merge($this->statements[$key], $value); |
||
1449 | } |
||
1450 | } |
||
1451 | |||
1452 | /** |
||
1453 | * @param string $event |
||
1454 | * @param string|Raw $table |
||
1455 | * |
||
1456 | * @return callable|null |
||
1457 | */ |
||
1458 | public function getEvent(string $event, $table = ':any'): ?callable |
||
1461 | } |
||
1462 | |||
1463 | /** |
||
1464 | * @param string $event |
||
1465 | * @param string|Raw $table |
||
1466 | * @param Closure $action |
||
1467 | * |
||
1468 | * @return void |
||
1469 | */ |
||
1470 | public function registerEvent($event, $table, Closure $action): void |
||
1471 | { |
||
1472 | $table = $table ?: ':any'; |
||
1473 | |||
1474 | if (':any' != $table) { |
||
1475 | $table = $this->addTablePrefix($table, false); |
||
1476 | } |
||
1477 | |||
1478 | $this->connection->getEventHandler()->registerEvent($event, $table, $action); |
||
1479 | } |
||
1480 | |||
1481 | /** |
||
1482 | * @param string $event |
||
1483 | * @param string|Raw $table |
||
1484 | * |
||
1485 | * @return void |
||
1486 | */ |
||
1487 | public function removeEvent(string $event, $table = ':any') |
||
1494 | } |
||
1495 | |||
1496 | /** |
||
1497 | * @param string $event |
||
1498 | * |
||
1499 | * @return mixed |
||
1500 | */ |
||
1501 | public function fireEvents(string $event) |
||
1502 | { |
||
1503 | $params = func_get_args(); // @todo Replace this with an easier to read alteratnive |
||
1504 | array_unshift($params, $this); |
||
1505 | |||
1506 | return call_user_func_array([$this->connection->getEventHandler(), 'fireEvents'], $params); |
||
1507 | } |
||
1508 | |||
1509 | /** |
||
1510 | * @return array<string, mixed[]> |
||
1511 | */ |
||
1512 | public function getStatements() |
||
1515 | } |
||
1516 | |||
1517 | /** |
||
1518 | * @return string will return WPDB Fetch mode |
||
1519 | */ |
||
1520 | public function getFetchMode() |
||
1521 | { |
||
1522 | return null !== $this->fetchMode |
||
1523 | ? $this->fetchMode |
||
1524 | : \OBJECT; |
||
1525 | } |
||
1526 | |||
1527 | /** |
||
1528 | * Returns an NEW instance of the JSON builder populated with the same connection and hydrator details. |
||
1529 | * |
||
1530 | * @return JsonQueryBuilder |
||
1531 | */ |
||
1532 | public function jsonBuilder(): JsonQueryBuilder |
||
1535 | } |
||
1536 | } |
||
1537 |