PluginProbe ʕ •ᴥ•ʔ
JetFormBuilder — Dynamic Blocks Form Builder / 3.5.4
JetFormBuilder — Dynamic Blocks Form Builder v3.5.4
3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.1.0 2.1.1 2.1.10 2.1.11 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 3.0.0 3.0.0.1 3.0.0.2 3.0.0.3 3.0.1 3.0.1.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.0.1 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.3.1 3.3.4 3.3.4.1 3.3.4.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.5.1 3.4.5.2 3.4.6 3.4.7 3.4.7.1 3.5.0 3.5.1 3.5.1.1 3.5.1.2 3.5.2 3.5.2.1 3.5.3 3.5.4 3.5.5 3.5.6 3.5.6.1 3.5.6.2 3.5.6.3 3.6.0
jetformbuilder / includes / db-queries / query-conditions-builder.php
jetformbuilder / includes / db-queries Last commit date
constraints 2 years ago exceptions 2 years ago models 2 years ago traits 2 years ago views 2 years ago base-db-constraint.php 2 years ago base-db-model.php 2 years ago execution-builder.php 2 years ago query-builder.php 2 years ago query-cache-builder.php 2 years ago query-conditions-builder.php 8 months ago
query-conditions-builder.php
608 lines
1 <?php
2
3
4 namespace Jet_Form_Builder\Db_Queries;
5
6 use Jet_Form_Builder\Db_Queries\Traits\With_View;
7 use Jet_Form_Builder\Exceptions\Query_Builder_Exception;
8 use JFB_Components\Db\Db_Tools;
9
10 // If this file is called directly, abort.
11 if ( ! defined( 'WPINC' ) ) {
12 die;
13 }
14
15 /**
16 * @method Query_Conditions_Builder set_view( Views\View_Base $view )
17 *
18 * Class Query_Conditions_Builder
19 * @package Jet_Form_Builder\Db_Queries
20 */
21 class Query_Conditions_Builder {
22
23 const TYPE_EQUAL_STATIC = 'equal_static';
24 const TYPE_EQUAL = 'equal_column';
25 const TYPE_EQUAL_COLUMNS = 'equal_two_columns';
26 const TYPE_LIKE = 'like';
27 const TYPE_NOT_LIKE = 'not_like';
28 const TYPE_MORE_STATIC = 'more_static';
29 const TYPE_MORE_OR_EQUAL_STATIC = 'more_or_equal_static';
30 const TYPE_LESS_STATIC = 'less_static';
31 const TYPE_LESS_OR_EQUAL_STATIC = 'less_or_equal_static';
32 const TYPE_IN = 'in';
33 /**
34 * @since 3.1.0
35 */
36 const TYPE_NOT_EQUAL = 'not_equal_column';
37 const TYPE_LIKE_END = 'like_end';
38 const TYPE_NOT_LIKE_END = 'not_like_end';
39 /**
40 * @since 3.2.0
41 */
42 const TYPE_IS_NULL = 'is_null';
43
44 /**
45 * @since 3.1.0
46 */
47 const RELATIONS_TYPES = array( 'AND', 'OR' );
48
49 use With_View;
50
51 private $conditions = array();
52
53 private $relation_type = 'AND';
54
55 /**
56 * @var array
57 */
58 private $current_condition;
59
60 /**
61 * @var \Generator
62 */
63 private $generator;
64
65 public function get_types(): array {
66 return array(
67 self::TYPE_EQUAL_STATIC => array(
68 'callback' => array( $this, 'build_equal_static' ),
69 ),
70 self::TYPE_EQUAL => array(
71 'callback' => array( $this, 'build_equal_column' ),
72 ),
73 self::TYPE_EQUAL_COLUMNS => array(
74 'callback' => array( $this, 'build_equal_two_columns' ),
75 ),
76 self::TYPE_LIKE => array(
77 'callback' => array( $this, 'build_like' ),
78 ),
79 self::TYPE_NOT_LIKE => array(
80 'callback' => array( $this, 'build_not_like' ),
81 ),
82 self::TYPE_MORE_STATIC => array(
83 'callback' => array( $this, 'build_more_static' ),
84 ),
85 self::TYPE_LESS_STATIC => array(
86 'callback' => array( $this, 'build_less_static' ),
87 ),
88 self::TYPE_IN => array(
89 'callback' => array( $this, 'build_in' ),
90 ),
91 /**
92 * @since 3.1.0
93 */
94 self::TYPE_NOT_EQUAL => array(
95 'callback' => array( $this, 'build_not_equal_column' ),
96 ),
97 self::TYPE_LIKE_END => array(
98 'callback' => array( $this, 'build_like_end' ),
99 ),
100 self::TYPE_NOT_LIKE_END => array(
101 'callback' => array( $this, 'build_not_like_end' ),
102 ),
103 self::TYPE_LESS_OR_EQUAL_STATIC => array(
104 'callback' => array( $this, 'build_less_or_equal_static' ),
105 ),
106 self::TYPE_MORE_OR_EQUAL_STATIC => array(
107 'callback' => array( $this, 'build_more_or_equal_static' ),
108 ),
109 /**
110 * @since 3.2.0
111 */
112 self::TYPE_IS_NULL => array(
113 'callback' => array( $this, 'build_is_null' ),
114 ),
115 );
116 }
117
118 /**
119 * @param array|Query_Conditions_Builder $condition
120 *
121 * @return $this
122 */
123 public function set_condition( $condition ): Query_Conditions_Builder {
124 if ( ! is_array( $condition ) && ! ( $condition instanceof Query_Conditions_Builder ) ) {
125 return $this;
126 }
127 $this->conditions[] = $condition;
128
129 return $this;
130 }
131
132 public function set_conditions( array $conditions ): Query_Conditions_Builder {
133 foreach ( $conditions as $condition ) {
134 $this->set_condition( $condition );
135 }
136
137 return $this;
138 }
139
140 public function after_set_view() {
141 try {
142 $view = $this->view();
143 } catch ( Query_Builder_Exception $exception ) {
144 return;
145 }
146
147 $this->set_conditions( $view->conditions() );
148 }
149
150 /**
151 * @return string
152 */
153 public function result(): string {
154 if ( ! $this->conditions ) {
155 return '';
156 }
157
158 return 'WHERE ' . $this->prepare_conditions();
159 }
160
161 /**
162 * @return string
163 */
164 public function prepare_conditions(): string {
165 $this->generator = $this->generate_conditions();
166 $prepared = array();
167
168 foreach ( $this->generator as $condition ) {
169 $prepared[] = $this->prepare();
170 }
171
172 return implode(
173 sprintf( "\r\n\t%s ", $this->relation_type ),
174 $prepared
175 );
176 }
177
178 /**
179 * @return mixed
180 */
181 public function prepare() {
182 $condition = $this->generator->current();
183
184 if ( $condition instanceof Query_Conditions_Builder ) {
185 return sprintf( "(\r\n%s\r\n)", $condition->prepare_conditions() );
186 }
187
188 $type = $this->get_condition_type();
189 $values = $this->get_condition_values();
190 $callback = $this->get_types()[ $type ]['callback'];
191
192 return call_user_func( $callback, $values[0], $values[1] ?? false );
193 }
194
195 /**
196 * @return string
197 */
198 private function get_condition_type(): string {
199 $condition = $this->generator->current();
200 $type = $condition['type'] ?? false;
201
202 if ( ! $type || ! in_array( $type, array_keys( $this->get_types() ), true ) ) {
203 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
204 _doing_it_wrong( __METHOD__, "Undefined condition type: $type", '2.0.0' );
205 wp_die();
206 }
207
208 return $type;
209 }
210
211 public function build_equal_static( $first, $second ): string {
212 global $wpdb;
213
214 return $wpdb->prepare(
215 '%s = %s',
216 $first,
217 $second
218 );
219 }
220
221 /**
222 * @param $column_name
223 * @param $second
224 *
225 * @return string
226 */
227 public function build_equal_column( $column_name, $second ): string {
228 global $wpdb;
229
230 $format = $this->get_format_value( $second );
231 $format_col = $this->get_format_column();
232 $column_name = Db_Tools::sanitize_column( $column_name );
233
234 try {
235 $column_name = $this->view()->column( $column_name );
236 } catch ( Query_Builder_Exception $exception ) {
237 // silence
238 }
239
240 return $wpdb->prepare(
241 // phpcs:ignore WordPress.DB
242 sprintf( $format_col, $column_name ) . " = {$format}",
243 $second
244 );
245 }
246
247 /**
248 * @param $column_name
249 * @param $second
250 *
251 * @return string
252 * @since 3.1.0
253 */
254 public function build_not_equal_column( $column_name, $second ): string {
255 global $wpdb;
256
257 $format = $this->get_format_value( $second );
258 $format_col = $this->get_format_column();
259 $column_name = Db_Tools::sanitize_column( $column_name );
260
261 try {
262 $column_name = $this->view()->column( $column_name );
263 } catch ( Query_Builder_Exception $exception ) {
264 // silence
265 }
266
267 return $wpdb->prepare(
268 // phpcs:ignore WordPress.DB
269 sprintf( $format_col, $column_name ) . " != {$format}",
270 $second
271 );
272 }
273
274 /**
275 * @param $column_name
276 * @param $second
277 *
278 * @return string
279 */
280 public function build_equal_two_columns( $column_name, $second ): string {
281 $column_name = Db_Tools::sanitize_column( $column_name );
282 $second = Db_Tools::sanitize_column( $second );
283
284 try {
285 $column_name = $this->view()->column( $column_name );
286 $second = $this->view()->column( $second );
287 } catch ( Query_Builder_Exception $exception ) {
288 // silence
289 }
290
291 return "{$column_name} = {$second}";
292 }
293
294 /**
295 * @param $column_name
296 * @param $second
297 *
298 * @return string
299 */
300 public function build_like( $column_name, $second ): string {
301 $second = esc_sql( $second );
302 $column_name = Db_Tools::sanitize_column( $column_name );
303
304 try {
305 $column_name = $this->view()->column( $column_name );
306 } catch ( Query_Builder_Exception $exception ) {
307 // silence
308 }
309
310 return "{$column_name} LIKE '%{$second}%'";
311 }
312
313 /**
314 * @param $column_name
315 * @param $second
316 *
317 * @return string
318 */
319 public function build_not_like( $column_name, $second ): string {
320 $second = esc_sql( $second );
321 $column_name = Db_Tools::sanitize_column( $column_name );
322
323 try {
324 $column_name = $this->view()->column( $column_name );
325 } catch ( Query_Builder_Exception $exception ) {
326 // silence
327 }
328
329 return "{$column_name} NOT LIKE '%{$second}%'";
330 }
331
332 /**
333 * @param $column_name
334 * @param $second
335 *
336 * @return string
337 */
338 public function build_like_end( $column_name, $second ): string {
339 $second = esc_sql( $second );
340 $column_name = Db_Tools::sanitize_column( $column_name );
341
342 try {
343 $column_name = $this->view()->column( $column_name );
344 } catch ( Query_Builder_Exception $exception ) {
345 // silence
346 }
347
348 return "{$column_name} LIKE '{$second}%'";
349 }
350
351 /**
352 * @param $column_name
353 * @param $second
354 *
355 * @return string
356 */
357 public function build_not_like_end( $column_name, $second ): string {
358 $second = esc_sql( $second );
359 $column_name = Db_Tools::sanitize_column( $column_name );
360
361 try {
362 $column_name = $this->view()->column( $column_name );
363 } catch ( Query_Builder_Exception $exception ) {
364 // silence
365 }
366
367 return "{$column_name} NOT LIKE '{$second}%'";
368 }
369
370 /**
371 * @param $column_name
372 * @param $second
373 *
374 * @return string
375 */
376 public function build_more_static( $column_name, $second ): string {
377 global $wpdb;
378
379 $format = $this->get_format_value( $second );
380 $format_col = $this->get_format_column();
381 $column_name = Db_Tools::sanitize_column( $column_name );
382
383 try {
384 $column_name = $this->view()->column( $column_name );
385 } catch ( Query_Builder_Exception $exception ) {
386 // silence
387 }
388
389 // phpcs:disable WordPress.DB
390 return $wpdb->prepare(
391 sprintf( $format_col, $column_name ) . ' > ' . $format,
392 $second
393 );
394 // phpcs:enable WordPress.DB
395 }
396
397 /**
398 * @param $column_name
399 * @param $second
400 *
401 * @return string
402 */
403 public function build_more_or_equal_static( $column_name, $second ): string {
404 global $wpdb;
405
406 $format = $this->get_format_value( $second );
407 $format_col = $this->get_format_column();
408 $column_name = Db_Tools::sanitize_column( $column_name );
409
410 try {
411 $column_name = $this->view()->column( $column_name );
412 } catch ( Query_Builder_Exception $exception ) {
413 // silence
414 }
415
416 // phpcs:disable WordPress.DB
417 return $wpdb->prepare(
418 sprintf( $format_col, $column_name ) . ' >= ' . $format,
419 $second
420 );
421 // phpcs:enable WordPress.DB
422 }
423
424 /**
425 * .wrap > *:not(h1, #poststuff) {
426 * display: none;
427 * }
428 */
429 /**
430 * @param $column_name
431 * @param $second
432 *
433 * @return string
434 */
435 public function build_less_static( $column_name, $second ): string {
436 global $wpdb;
437
438 $format = $this->get_format_value( $second );
439 $format_col = $this->get_format_column();
440 $column_name = Db_Tools::sanitize_column( $column_name );
441
442 try {
443 $column_name = $this->view()->column( $column_name );
444 } catch ( Query_Builder_Exception $exception ) {
445 // silence
446 }
447
448 // phpcs:disable WordPress.DB
449 return $wpdb->prepare(
450 sprintf( $format_col, $column_name ) . ' < ' . $format,
451 $second
452 );
453 // phpcs:enable WordPress.DB
454 }
455
456 /**
457 * @param $column_name
458 * @param $second
459 *
460 * @return string
461 */
462 public function build_less_or_equal_static( $column_name, $second ): string {
463 global $wpdb;
464
465 $format = $this->get_format_value( $second );
466 $format_col = $this->get_format_column();
467 $column_name = Db_Tools::sanitize_column( $column_name );
468
469 try {
470 $column_name = $this->view()->column( $column_name );
471 } catch ( Query_Builder_Exception $exception ) {
472 // silence
473 }
474
475 // phpcs:disable WordPress.DB
476 return $wpdb->prepare(
477 sprintf( $format_col, $column_name ) . ' <= ' . $format,
478 $second
479 );
480 // phpcs:enable WordPress.DB
481 }
482
483 /**
484 * @param $column_name
485 * @param $second
486 *
487 * @return string
488 */
489 public function build_in( $column_name, $second ): string {
490 if ( ! is_array( $second ) ) {
491 $second = array( $second );
492 }
493
494 $in_list = array();
495
496 foreach ( $second as $in_item ) {
497 if ( ! is_scalar( $in_item ) ) {
498 continue;
499 }
500
501 $in_list[] = is_numeric( $in_item )
502 ? $in_item
503 : sprintf( "'%s'", sanitize_key( $in_item ) );
504 }
505
506 // Fix: Return FALSE condition when IN list is empty to prevent SQL error
507 if ( empty( $in_list ) ) {
508 $column_name = Db_Tools::sanitize_column( $column_name );
509 try {
510 $column_name = $this->view()->column( $column_name );
511 } catch ( Query_Builder_Exception $exception ) {
512 // silence
513 }
514 return "{$column_name} IN (NULL)";
515 }
516
517 $right_part = implode( ', ', $in_list );
518 $column_name = Db_Tools::sanitize_column( $column_name );
519
520 try {
521 $column_name = $this->view()->column( $column_name );
522 } catch ( Query_Builder_Exception $exception ) {
523 // silence
524 }
525
526 return "{$column_name} IN ({$right_part})";
527 }
528
529 /**
530 * @param $column_name
531 *
532 * @return string
533 * @since 3.2.0
534 */
535 public function build_is_null( $column_name ): string {
536 $column_name = Db_Tools::sanitize_column( $column_name );
537
538 try {
539 $column_name = $this->view()->column( $column_name );
540 } catch ( Query_Builder_Exception $exception ) {
541 // silence
542 }
543
544 // phpcs:disable WordPress.DB
545 return sprintf( '%s IS NULL', $column_name );
546 // phpcs:enable WordPress.DB
547 }
548
549 /**
550 * @return array
551 */
552 public function get_condition_values(): array {
553 $condition = $this->generator->current();
554
555 return $condition['values'] ?? array();
556 }
557
558 /**
559 * @return $this
560 * @since 3.1.0
561 */
562 public function set_relation_and(): Query_Conditions_Builder {
563 return $this->set_relation_type( 'AND' );
564 }
565
566 /**
567 * @return $this
568 * @since 3.1.0
569 */
570 public function set_relation_or(): Query_Conditions_Builder {
571 return $this->set_relation_type( 'OR' );
572 }
573
574 protected function set_relation_type( string $type ): Query_Conditions_Builder {
575 if ( ! in_array( $type, self::RELATIONS_TYPES, true ) ) {
576 return $this;
577 }
578 $this->relation_type = $type;
579
580 return $this;
581 }
582
583 protected function generate_conditions(): \Generator {
584 foreach ( $this->conditions as $condition ) {
585 yield $condition;
586 }
587 }
588
589 protected function get_format_value( $value ) {
590 /** @var array $condition */
591 $condition = $this->generator->current();
592
593 if ( ! empty( $condition['format'] ) ) {
594 return $condition['format'];
595 }
596
597 return is_numeric( $value ) ? '%d' : '%s';
598 }
599
600 protected function get_format_column() {
601 /** @var array $condition */
602 $condition = $this->generator->current();
603
604 return empty( $condition['format_col'] ) ? '%s' : $condition['format_col'];
605 }
606
607 }
608