PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 3.0.2
Tutor LMS – eLearning and online course solution v3.0.2
3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / helpers / QueryHelper.php
tutor / helpers Last commit date
DateTimeHelper.php 1 year ago HttpHelper.php 1 year ago QueryHelper.php 1 year ago SessionHelper.php 3 years ago ValidationHelper.php 1 year ago
QueryHelper.php
887 lines
1 <?php
2 /**
3 * Query helper class contains static helper methods to perform basic
4 * operations
5 *
6 * @package Tutor\Helper
7 * @since v2.0.7
8 */
9
10 namespace Tutor\Helpers;
11
12 /**
13 * Do the common db operations through helper
14 * methods
15 */
16 class QueryHelper {
17
18 /**
19 * Insert data in the table
20 *
21 * @param string $table table name.
22 * @param array $data | data to insert in the table.
23 *
24 * @return int, inserted id.
25 *
26 * @since v2.0.7
27 *
28 * @since 3.0.0
29 *
30 * @throws \Exception Database error if occur.
31 */
32 public static function insert( string $table, array $data ): int {
33 global $wpdb;
34 // Sanitize text field.
35 $data = array_map(
36 function ( $value ) {
37 return sanitize_text_field( $value );
38 },
39 $data
40 );
41
42 $insert = $wpdb->insert(
43 $table,
44 $data
45 );
46
47 if ( $wpdb->last_error ) {
48 throw new \Exception( $wpdb->last_error );
49 }
50
51 return $insert ? $wpdb->insert_id : 0;
52 }
53
54 /**
55 * Update data
56 *
57 * @param string $table table name.
58 * @param array $data | data to update in the table.
59 * @param array $where | condition array.
60 *
61 * @return bool, true on success false on failure
62 *
63 * @since v2.0.7
64 */
65 public static function update( string $table, array $data, array $where ): bool {
66 global $wpdb;
67 // Sanitize text field.
68 $data = array_map(
69 function ( $value ) {
70 return sanitize_text_field( $value );
71 },
72 $data
73 );
74
75 $where = array_map(
76 function ( $value ) {
77 return sanitize_text_field( $value );
78 },
79 $where
80 );
81
82 $wpdb->update(
83 $table,
84 $data,
85 $where
86 );
87
88 if ( $wpdb->last_error ) {
89 error_log( $wpdb->last_error );
90
91 return false;
92 }
93
94 return true;
95 }
96
97 /**
98 * Delete rows from table
99 *
100 * @param string $table table name.
101 * @param array $where key value pairs.Where key is the name of
102 * column & value is the value to match.
103 * For ex: [ 'id' => 1 ].
104 *
105 * @since v2.0.7
106 */
107 public static function delete( string $table, array $where ): bool {
108 global $wpdb;
109 $delete = $wpdb->delete(
110 $table,
111 $where
112 );
113 return $delete ? true : false;
114 }
115
116 /**
117 * Delete rows from table
118 *
119 * @since 3.0.0
120 *
121 * @param string $table table name.
122 * @param array $ids array of ids.
123 *
124 * @see prepare_in_clause
125 *
126 * @throws \Exception Throw database error if occurred.
127 *
128 * @return true on success
129 */
130 public static function bulk_delete_by_ids( string $table, array $ids ): bool {
131 global $wpdb;
132
133 $ids = self::prepare_in_clause( $ids );
134 //phpcs:ignore --ids already sanitized.
135 $wpdb->query( "DELETE FROM {$table} WHERE id IN ( $ids )");
136
137 if ( $wpdb->last_error ) {
138 throw new \Exception( $wpdb->last_error );
139 }
140
141 return true;
142 }
143
144 /**
145 * Clean everything from table
146 *
147 * @since v2.0.7
148 *
149 * @param string $table table name.
150 *
151 * @return bool
152 */
153 public static function table_clean( string $table ): bool {
154 global $wpdb;
155 $delete = $wpdb->query(
156 //phpcs:ignore
157 $wpdb->prepare( "DELETE FROM {$table} WHERE 1 = %d", 1 )
158 );
159 return $delete ? true : false;
160 }
161
162 /**
163 * Insert multiple rows without knowing key value
164 *
165 * @since v2.0.7
166 *
167 * @param string $table table name.
168 * @param array $request two dimensional array
169 * for ex: [ [id => 1], [id => 2] ].
170 *
171 * @return mixed wpdb response true or int on success, false on failure.
172 * @throws \Exception If error occur.
173 */
174 public static function insert_multiple_rows( $table, $request ) {
175 global $wpdb;
176 $column_keys = '';
177 $column_values = '';
178 $sql = '';
179 $last_key = array_key_last( $request );
180 $first_key = array_key_first( $request );
181 foreach ( $request as $k => $value ) {
182 $keys = array_keys( $value );
183
184 // Prepare column keys & values.
185 foreach ( $keys as $v ) {
186 $column_keys .= sanitize_key( $v ) . ',';
187 $sanitize_value = is_null( $value[ $v ] ) ? $value[ $v ] : sanitize_text_field( $value[ $v ] );
188 $column_values .= is_numeric( $sanitize_value ) ? $sanitize_value . ',' : "'$sanitize_value'" . ',';
189 }
190 // Trim trailing comma.
191 $column_keys = rtrim( $column_keys, ',' );
192 $column_values = rtrim( $column_values, ',' );
193 if ( $first_key === $k ) {
194 $sql .= "INSERT INTO {$table} ($column_keys) VALUES ($column_values)";
195 if ( count( $request ) > 1 ) {
196 $sql .= ',';
197 }
198 } elseif ( $last_key == $k ) {
199 $sql .= "($column_values)";
200 } else {
201 $sql .= "($column_values),";
202 }
203
204 // Reset keys & values to avoid duplication.
205 $column_keys = '';
206 $column_values = '';
207 }
208
209 $wpdb->query( $sql );//phpcs:ignore
210
211 // If error occurred then throw new exception.
212 if ( $wpdb->last_error ) {
213 throw new \Exception( $wpdb->last_error );
214 }
215
216 return true;
217 }
218
219 /**
220 * Make tge where clause base on its column operator and values.
221 *
222 * If the operator is IN then make the clause like `WHERE column_name IN (value1, value2, ...)`
223 * Otherwise the clause would be `WHERE column_name = 'value'`
224 *
225 * @since 3.0.0
226 *
227 * @param array $where The where clause array. e.g. array( 'id', 'IN', array(1, 2, 3) ) or array( 'id', '=', 1 ).
228 *
229 * @return string
230 */
231 public static function make_clause( array $where ) {
232 list ( $field, $operator, $value ) = $where;
233
234 if ( 'IN' === strtoupper( $operator ) ) {
235 $value = '(' . self::prepare_in_clause( $value ) . ')';
236 }
237
238 return "{$field} {$operator} {$value}";
239 }
240
241 /**
242 * Build where clause string
243 *
244 * @param array $where assoc array with field and value.
245 * @return string
246 *
247 * @since 2.0.9
248 *
249 * @since 3.0.0
250 * Null value support added, if need to check with
251 * null: [name => 'null'] we can pass
252 */
253 public static function build_where_clause( array $where ) {
254 $arr = array();
255 foreach ( $where as $field => $value ) {
256 if ( is_array( $value ) ) {
257 $value = array( $field, 'IN', $value );
258 } else {
259 if ( 'null' == $value ) {
260 $value = array( $field, 'IS', 'NULL' );
261 } else {
262 $value = is_numeric( $value ) ? $value : "'" . $value . "'";
263 $value = array( $field, '=', $value );
264 }
265 }
266
267 $arr[] = self::make_clause( $value );
268 }
269
270 return implode( ' AND ', $arr );
271 }
272
273 /**
274 * Build like clause string with or
275 *
276 * @since 1.0.0
277 *
278 * @param array $where assoc array with field and value.
279 * @param string $relation default is OR.
280 *
281 * @return string
282 */
283 public static function build_like_clause( array $where, $relation = 'OR' ) {
284 global $wpdb;
285
286 $like_conditions = array();
287
288 foreach ( $where as $column_name => $term ) {
289 //phpcs:ignore
290 $like_conditions[] = $wpdb->prepare( "$column_name LIKE %s", '%' . $wpdb->esc_like( $term ) . '%' );
291 }
292
293 $where_clause = implode( ' OR ', $like_conditions );
294
295 return $where_clause;
296 }
297
298 /**
299 * Sanitize assoc array
300 *
301 * @param array $array an assoc array.
302 * @return array
303 *
304 * @since 2.0.9
305 */
306 private static function sanitize_assoc_array( array $array ) {
307 return array_map(
308 function ( $value ) {
309 return sanitize_text_field( $value );
310 },
311 $array
312 );
313 }
314
315 /**
316 * Delete comment with associate meta data
317 *
318 * @param array $where associative array with field and value.
319 * Example: array( 'comment_type' => 'comment', 'comment_id' => 1 ).
320 * @return bool
321 *
322 * @since 2.0.9
323 */
324 public static function delete_comment_with_meta( array $where ) {
325 if ( count( $where ) === 0 || ! tutor_utils()->is_assoc( $where ) ) {
326 return false;
327 }
328
329 $where = self::build_where_clause( self::sanitize_assoc_array( $where ) );
330
331 global $wpdb;
332 $ids = $wpdb->get_col( "SELECT comment_id FROM {$wpdb->comments} WHERE {$where}" );//phpcs:ignore
333
334 if ( is_array( $ids ) && count( $ids ) ) {
335 $ids_str = "'" . implode( "','", $ids ) . "'";
336 // delete comment metas.
337 $wpdb->query( "DELETE FROM {$wpdb->commentmeta} WHERE comment_id IN({$ids_str}) " );//phpcs:ignore
338 // delete comment.
339 $wpdb->query( "DELETE FROM {$wpdb->comments} WHERE {$where}" );//phpcs:ignore
340
341 return true;
342 }
343
344 return false;
345 }
346
347 /**
348 * Delete post with associate meta data
349 *
350 * @param array $where associative array with field and value.
351 * Example: array( 'post_type' => 'post', 'id' => 1 ).
352 * @return bool
353 *
354 * @since 2.0.9
355 */
356 public static function delete_post_with_meta( array $where ) {
357 if ( count( $where ) === 0 || ! tutor_utils()->is_assoc( $where ) ) {
358 return false;
359 }
360
361 $where = self::build_where_clause( self::sanitize_assoc_array( $where ) );
362
363 global $wpdb;
364 $ids = $wpdb->get_col( "SELECT id FROM {$wpdb->posts} WHERE {$where}" );//phpcs:ignore
365
366 if ( is_array( $ids ) && count( $ids ) ) {
367 $ids_str = "'" . implode( "','", $ids ) . "'";
368 // delete post metas.
369 $wpdb->query( "DELETE FROM {$wpdb->postmeta} WHERE post_id IN({$ids_str}) " );//phpcs:ignore
370 // delete post.
371 $wpdb->query( "DELETE FROM {$wpdb->posts} WHERE {$where}" );//phpcs:ignore
372
373 return true;
374 }
375
376 return false;
377 }
378
379 /**
380 * Get a single row from any table with where clause
381 *
382 * @param string $table table name with prefix.
383 *
384 * @param array $where assoc_array. For ex: [col_name => value ].
385 * @param string $order_by order by column name.
386 * @param string $order DESC or ASC, default is DESC.
387 * @param string $output expected output type, default is object.
388 *
389 * @return mixed based on output param, default object
390 */
391 public static function get_row( string $table, array $where, string $order_by, string $order = 'DESC', string $output = 'OBJECT' ) {
392 global $wpdb;
393
394 $where_clause = self::build_where_clause( $where );
395
396 //phpcs:disable
397 $query = $wpdb->prepare(
398 "SELECT *
399 FROM {$table}
400 WHERE {$where_clause}
401 ORDER BY {$order_by} {$order}
402 LIMIT %d
403 ",
404 1
405 );
406
407 return $wpdb->get_row(
408 $query,
409 $output
410 );
411 //phpcs:enable
412 }
413
414 /**
415 * Get all row from any table with where clause
416 *
417 * @since 2.2.1
418 * @since 3.0.0 added support for -1 value in the limit parameter.
419 *
420 * @param string $table table name with prefix.
421 *
422 * @param array $where assoc_array. For ex: [col_name => value ].
423 * @param string $order_by order by column name.
424 * @param int $limit default is 1000, -1 for no limit.
425 * @param string $order DESC or ASC, default is DESC.
426 * @param string $output expected output type, default is object.
427 *
428 * @return mixed based on output param, default object
429 */
430 public static function get_all( string $table, array $where, string $order_by, $limit = 1000, string $order = 'DESC', string $output = 'OBJECT' ) {
431 global $wpdb;
432
433 $where_clause = self::build_where_clause( $where );
434 $limit = (int) sanitize_text_field( $limit );
435 $limit_clause = ( -1 === $limit ) ? '' : 'LIMIT ' . $limit;
436
437 //phpcs:disable
438 $query = "SELECT *
439 FROM {$table}
440 WHERE {$where_clause}
441 ORDER BY {$order_by} {$order}
442 {$limit_clause}";
443
444 return $wpdb->get_results(
445 $query,
446 $output
447 );
448 //phpcs:enable
449 }
450
451 /**
452 * Update multiple rows by using where in
453 * clause
454 *
455 * @since v2.1.0
456 *
457 * @param string $table table name.
458 * @param array $data assoc_array data to update
459 * ex: [id => 2, name => 'john' ].
460 * @param string $where_in comma separated values, ex: 1,2,3.
461 * @param string $where_col default is ID but could be other.
462 *
463 * @return bool true on success, false on failure
464 */
465 public static function update_where_in( string $table, array $data, string $where_in, string $where_col = 'ID' ) {
466 global $wpdb;
467 if ( empty( $where_in ) || empty( $where_col ) ) {
468 return false;
469 }
470 $set_clause = self::prepare_set_clause( $data );
471 if ( '' === $set_clause ) {
472 return false;
473 }
474 // @codingStandardsIgnoreStart
475 $query = $wpdb->prepare(
476 "UPDATE {$table}
477 {$set_clause}
478 WHERE $where_col IN ( $where_in )
479 AND 1 = %d
480 ",
481 1
482 );
483 return $wpdb->query( $query ) ? true : false;
484 }
485
486 /**
487 * Prepare MySQL SET clause for update query
488 *
489 * @since v2.1.0
490 *
491 * @param array $data single dimension assoc_array.
492 *
493 * @return string
494 */
495 public static function prepare_set_clause( array $data ) {
496 $set = '';
497 foreach ( $data as $key => $value ) {
498 if ( $key === array_key_first ( $data ) ) {
499 $set .= "SET ";
500 }
501 // Multi dimension not allowed.
502 if ( is_array( $value ) ) {
503 continue;
504 }
505
506 if ( is_null( $value ) ) {
507 $set .= "$key = null";
508 } else {
509 $value = esc_sql( sanitize_text_field( $value ) );
510 $set .= is_numeric( $value ) ? "$key = $value" : "$key = '" . $value ."'";
511 }
512
513 $set .= ",";
514 }
515 return rtrim( $set, ',' );
516 }
517
518 /**
519 * Make sanitized SQL IN clause value from an array
520 *
521 * @param array $arr a sequentital array.
522 * @return string
523 * @since 2.1.1
524 */
525 public static function prepare_in_clause( array $arr ) {
526 $escaped = array_map(
527 function( $value ) {
528 global $wpdb;
529 $escaped_value = null;
530 if ( is_int( $value ) ) {
531 $escaped_value = $wpdb->prepare( '%d', $value );
532 } else if( is_float( $value ) ) {
533 list( $whole, $decimal ) = explode( '.', $value );
534 $expression = '%.'. strlen( $decimal ) . 'f';
535 $escaped_value = $wpdb->prepare( $expression, $value );
536 } else {
537 $escaped_value = $wpdb->prepare( '%s', $value );
538 }
539 return $escaped_value;
540 },
541 $arr
542 );
543
544 return implode( ',', $escaped );
545 }
546
547 /**
548 * Check table exist in database.
549 *
550 * @since 2.5.0
551 *
552 * @param string $table table name.
553 *
554 * @return bool
555 */
556 public static function table_exists( $table ) {
557 global $wpdb;
558 $sql = "SHOW TABLES LIKE '{$table}'";
559 return $wpdb->get_var( $sql ) === $table;
560 }
561
562 /**
563 * Check column exist in a table
564 *
565 * @since 3.0.0
566 *
567 * @param string $table table name.
568 * @param string $column column name.
569 *
570 * @return bool
571 */
572 public static function column_exist( $table, $column ) {
573 global $wpdb;
574 $sql = "SHOW COLUMNS FROM {$table} LIKE '{$column}'";
575 return $wpdb->get_var( $sql ) === $column;
576 }
577
578 /**
579 * Get data by joining multiple tables with specified join relations.
580 *
581 * Argument should be SQL escaped.
582 *
583 * @since 3.0.0
584 *
585 * @param string $primary_table The primary table name with prefix.
586 * @param array $joining_tables An array of join relations. Each relation should be an array with keys 'type', 'table', 'on'.
587 * @param array $select_columns An array of columns to select.
588 * @param array $where An associative array for the WHERE clause. For example: [col_name => value]. Without sql esc.
589 * @param array $search An associative array for the search clause. For example: [col_name => value]. Without sql esc.
590 * @param string $order_by Order by column name.
591 * @param int $limit Maximum number of rows to return.
592 * @param int $offset Offset for pagination.
593 * @param string $order DESC or ASC, default is DESC.
594 * @param string $output Expected output type, default is OBJECT.
595 *
596 * @throws \Exception If an error occurred during the query execution.
597 *
598 * @return mixed Based on output param, default OBJECT.
599 */
600 public static function get_joined_data(
601 string $primary_table,
602 array $joining_tables,
603 array $select_columns,
604 array $where = [],
605 array $search = [],
606 string $order_by = '',
607 $limit = 10,
608 $offset = 0,
609 string $order = 'DESC',
610 string $output = 'OBJECT'
611 ) {
612 global $wpdb;
613
614 $select_clause = implode(', ', $select_columns);
615
616 $from_clause = $primary_table;
617
618 $join_clauses = '';
619 foreach ($joining_tables as $relation) {
620 $join_clauses .= " {$relation['type']} JOIN {$relation['table']} ON {$relation['on']}";
621 }
622
623 $where_clause = !empty($where) ? 'WHERE ' . self::build_where_clause($where) : '';
624
625 if (!empty($search)) {
626 $search_clause = self::build_like_clause( $search );
627 // foreach ($search as $column => $value) {
628 // $search_clauses[] = $wpdb->prepare("{$column} LIKE %s", '%' . $wpdb->esc_like($value) . '%');
629 // }
630 $where_clause .= !empty($where_clause) ? ' AND (' . $search_clause . ')' : 'WHERE ' . $search_clause;
631 }
632
633 $order_by_clause = !empty($order_by) ? "ORDER BY {$order_by} {$order}" : '';
634
635 // Query to get total count.
636 $count_query = "
637 SELECT COUNT(*) as total_count
638 FROM {$from_clause}
639 {$join_clauses}
640 {$where_clause}
641 ";
642
643 $total_count = $wpdb->get_var($count_query);
644
645 if (empty($limit) && empty($offset)) {
646 $query = "SELECT
647 {$select_clause}
648 FROM {$from_clause}
649 {$join_clauses}
650 {$where_clause}
651 {$order_by_clause}";
652 } else {
653 $query = $wpdb->prepare(
654 "SELECT {$select_clause}
655 FROM {$from_clause}
656 {$join_clauses}
657 {$where_clause}
658 {$order_by_clause}
659 LIMIT %d OFFSET %d",
660 $limit,
661 $offset
662 );
663 }
664
665
666 $results = $wpdb->get_results($query, $output);
667
668 // Throw exception if error occurred.
669 if ($wpdb->last_error) {
670 throw new \Exception($wpdb->last_error);
671 }
672
673 // Prepare response array.
674 $response = array(
675 'total_count' => (int) $total_count,
676 'results' => $results,
677 );
678
679 return $response;
680 }
681
682 /**
683 * Get count var
684 *
685 * Argument should be SQL escaped.
686 *
687 * @since 1.0.0
688 *
689 * @param string $table table name with prefix.
690 * @param array $where array of where condition.
691 * @param array $search array of search conditions for LIKE operator.
692 * @param string $count_column column name to count, default id.
693 *
694 * @return int
695 */
696 public static function get_count( $table, $where = [], $search = [], $count_column = 'id' ): int {
697 global $wpdb;
698
699 $where_clause = !empty( $where ) ? 'WHERE ' . self::build_where_clause( $where ) : '';
700 $search_clause = !empty( $search ) ? self::build_like_clause( $search, 'AND' ) : '';
701
702 if ( !empty( $search_clause ) ) {
703 if ( !empty( $where_clause ) ) {
704 $where_clause .= ' AND (' . $search_clause . ')';
705 } else {
706 $where_clause = 'WHERE ' . $search_clause;
707 }
708 }
709
710 $count = $wpdb->get_var(
711 "SELECT COUNT($count_column)
712 FROM $table
713 {$where_clause}"
714 );
715
716 // If error occurred then throw new exception.
717 if ( $wpdb->last_error ) {
718 throw new \Exception( $wpdb->last_error );
719 }
720
721 return (int) $count;
722 }
723
724 /**
725 * Get count by joining multiple tables with specified join relations.
726 *
727 * Argument should be SQL escaped.
728 *
729 * @since 3.0.0
730 *
731 * @param string $primary_table The primary table name with prefix.
732 * @param array $joining_tables An array of join relations. Each relation should be an array with keys 'type', 'table', 'on'.
733 * @param array $where array of where conditions.
734 * @param array $search array of search conditions for LIKE operator.
735 * @param string $count_column column name to count, default id.
736 *
737 * @return int
738 */
739 public static function get_joined_count(string $primary_table, array $joining_tables, array $where = [], array $search = [], string $count_column = '*'): int {
740 global $wpdb;
741
742 $from_clause = $primary_table;
743
744 $join_clauses = '';
745 foreach ($joining_tables as $relation) {
746 $join_clauses .= " {$relation['type']} JOIN {$relation['table']} ON {$relation['on']}";
747 }
748
749 $where_clause = !empty($where) ? 'WHERE ' . self::build_where_clause($where) : '';
750 $search_clause = !empty($search) ? self::build_like_clause($search, 'AND') : '';
751
752 if (!empty($search_clause)) {
753 if (!empty($where_clause)) {
754 $where_clause .= ' AND (' . $search_clause . ')';
755 } else {
756 $where_clause = 'WHERE ' . $search_clause;
757 }
758 }
759
760 $count_query = "
761 SELECT COUNT($count_column) as total_count
762 FROM {$from_clause}
763 {$join_clauses}
764 {$where_clause}
765 ";
766
767 $total_count = $wpdb->get_var($count_query);
768
769 // If error occurred then throw new exception.
770 if ($wpdb->last_error) {
771 throw new \Exception($wpdb->last_error);
772 }
773
774 return (int) $total_count;
775 }
776
777 /**
778 * Get all rows from any table with where and search clauses.
779 *
780 * @since 3.0.0
781 *
782 * @param string $table Table name with prefix.
783 * @param array $where Assoc array for exact match. For example: [col_name => value]. Without sql esc.
784 * @param array $search Assoc array for LIKE match. For example: [col_name => search_term]. Without sql esc.
785 * @param string $order_by Order by column name.
786 * @param int $limit Maximum number of rows to return, default is 10.
787 * @param int $offset Offset for pagination, default is 0.
788 * @param string $order DESC or ASC, default is DESC.
789 * @param string $output Expected output type, default is OBJECT.
790 *
791 * @throws \Exception Throw exception if error occurred during query execution.
792 *
793 * @return mixed Based on output param, default OBJECT.
794 */
795 public static function get_all_with_search(string $table, array $where, array $search, string $order_by, $limit = 10, $offset = 0, string $order = 'DESC', string $output = 'OBJECT'): array {
796 global $wpdb;
797
798 $where_clause = !empty($where) ? 'WHERE ' . self::build_where_clause($where) : '';
799 $search_clause = !empty($search) ? self::build_like_clause($search, 'AND') : '';
800
801 if (!empty($search_clause)) {
802 if (!empty($where_clause)) {
803 $where_clause .= ' AND (' . $search_clause . ')';
804 } else {
805 $where_clause = 'WHERE ' . $search_clause;
806 }
807 }
808
809 // Query to get total count
810 $count_query = "
811 SELECT COUNT(*)
812 FROM {$table}
813 {$where_clause}
814 ";
815 $total_count = $wpdb->get_var($count_query);
816
817 // If error occurred then throw new exception.
818 if ($wpdb->last_error) {
819 throw new \Exception($wpdb->last_error);
820 }
821
822 $query = $wpdb->prepare(
823 "SELECT *
824 FROM {$table}
825 {$where_clause}
826 ORDER BY {$order_by} {$order}
827 LIMIT %d OFFSET %d",
828 $limit,
829 $offset
830 );
831
832 $results = $wpdb->get_results($query, $output);
833
834 // If error occurred then throw new exception.
835 if ($wpdb->last_error) {
836 throw new \Exception($wpdb->last_error);
837 }
838
839 // Prepare response array.
840 $response = array(
841 'results' => $results,
842 'total_count' => (int) $total_count,
843 );
844
845 return $response;
846 }
847
848 /**
849 * Get period clause based on the provided period.
850 *
851 * @since 3.0.0
852 *
853 * @param string $column Table.column name, ex: table.created_at.
854 * @param string $period Period for filter refund data.
855 *
856 * @return string
857 */
858 public static function get_period_clause( string $column, string $period = '' ) {
859 $period_clause = '';
860 switch ( $period ) {
861 case 'today':
862 $period_clause = "AND DATE($column) = CURDATE()";
863 break;
864 case 'monthly':
865 $period_clause = "AND MONTH($column) = MONTH(CURDATE())";
866 break;
867 case 'yearly':
868 $period_clause = "AND YEAR($column) = YEAR(CURDATE())";
869 break;
870 case 'last30days':
871 $period_clause = "AND DATE($column) BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND CURDATE()";
872 break;
873 case 'last90days':
874 $period_clause = "AND DATE($column) BETWEEN DATE_SUB(CURDATE(), INTERVAL 90 DAY) AND CURDATE()";
875 break;
876 case 'last365days':
877 $period_clause = "AND DATE($column) BETWEEN DATE_SUB(CURDATE(), INTERVAL 365 DAY) AND CURDATE()";
878 break;
879 default:
880 break;
881 }
882
883 return $period_clause;
884 }
885
886 }
887