PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.9
4.4.9 4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 All 140 releases
← All changes | inc/Databases/DataBase.php +898 -890 4.3.9.1 → 4.4.9 View file →
@@ -1,890 +1,898 @@
1 -<?php
2 -
3 -namespace LearnPress\Databases;
4 -
5 -use Exception;
6 -use LearnPress\Filters\FilterBase;
7 -use wpdb;
8 -
9 -defined( 'ABSPATH' ) || exit();
10 -
11 -/**
12 - * Class DataBase
13 - *
14 - * @since 4.2.9.3
15 - * @version 1.0.0
16 - */
17 -class DataBase {
18 - private static $_instance;
19 - public $wpdb, $tb_users;
20 - public $tb_lp_courses;
21 - public $tb_lp_user_items, $tb_lp_user_itemmeta;
22 - public $tb_posts, $tb_postmeta, $tb_options;
23 - public $tb_terms, $tb_term_relationships, $tb_term_taxonomy;
24 - public $tb_lp_order_items, $tb_lp_order_itemmeta;
25 - public $tb_lp_sections, $tb_lp_section_items;
26 - public $tb_lp_quiz_questions;
27 - public $tb_lp_user_item_results;
28 - public $tb_lp_question_answers;
29 - public $tb_lp_question_answermeta;
30 - public $tb_lp_upgrade_db;
31 - public $tb_lp_sessions;
32 - public $tb_lp_files;
33 - public $tb_thim_cache;
34 - private $collate = '';
35 - public $max_index_length = '191';
36 -
37 - protected function __construct() {
38 - /**
39 - * @var wpdb $wpdb
40 - */
41 - global $wpdb;
42 - $prefix = $wpdb->prefix;
43 -
44 - $this->wpdb = $wpdb;
45 - $this->tb_users = $wpdb->users;
46 - $this->tb_posts = $wpdb->posts;
47 - $this->tb_postmeta = $wpdb->postmeta;
48 - $this->tb_options = $wpdb->options;
49 - $this->tb_terms = $wpdb->terms;
50 - $this->tb_term_relationships = $wpdb->term_relationships;
51 - $this->tb_term_taxonomy = $wpdb->term_taxonomy;
52 - $this->tb_lp_courses = $prefix . 'learnpress_courses';
53 - $this->tb_lp_user_items = $prefix . 'learnpress_user_items';
54 - $this->tb_lp_user_itemmeta = $prefix . 'learnpress_user_itemmeta';
55 - $this->tb_lp_order_items = $prefix . 'learnpress_order_items';
56 - $this->tb_lp_order_itemmeta = $prefix . 'learnpress_order_itemmeta';
57 - $this->tb_lp_section_items = $prefix . 'learnpress_section_items';
58 - $this->tb_lp_sections = $prefix . 'learnpress_sections';
59 - $this->tb_lp_quiz_questions = $prefix . 'learnpress_quiz_questions';
60 - $this->tb_lp_user_item_results = $prefix . 'learnpress_user_item_results';
61 - $this->tb_lp_question_answers = $prefix . 'learnpress_question_answers';
62 - $this->tb_lp_question_answermeta = $prefix . 'learnpress_question_answermeta';
63 - $this->tb_lp_upgrade_db = $prefix . 'learnpress_upgrade_db';
64 - $this->tb_lp_sessions = $prefix . 'learnpress_sessions';
65 - $this->tb_lp_files = $prefix . 'learnpress_files';
66 - $this->tb_thim_cache = $prefix . 'thim_cache';
67 - $this->wpdb->hide_errors();
68 - $this->set_collate();
69 - }
70 -
71 - /**
72 - * Get Instance
73 - *
74 - * @return DataBase
75 - */
76 - public static function getInstance() {
77 - if ( is_null( self::$_instance ) ) {
78 - self::$_instance = new self();
79 - }
80 -
81 - return self::$_instance;
82 - }
83 -
84 - public function set_collate() {
85 - $collate = '';
86 -
87 - if ( $this->wpdb->has_cap( 'collation' ) ) {
88 - if ( ! empty( $this->wpdb->charset ) ) {
89 - $collate .= 'DEFAULT CHARACTER SET ' . $this->wpdb->charset;
90 - }
91 -
92 - if ( ! empty( $this->wpdb->collate ) ) {
93 - $collate .= ' COLLATE ' . $this->wpdb->collate;
94 - }
95 - }
96 -
97 - $this->collate = $collate;
98 - }
99 -
100 - public function get_collate(): string {
101 - return $this->collate;
102 - }
103 -
104 - /**
105 - * Check table exists.
106 - *
107 - * @param string $name_table
108 - *
109 - * @return bool|int
110 - */
111 - public function check_table_exists( string $name_table ) {
112 - return $this->wpdb->query( $this->wpdb->prepare( "SHOW TABLES LIKE '%s'", $name_table ) );
113 - }
114 -
115 - /**
116 - * Clone table
117 - *
118 - * @param string $name_table .
119 - *
120 - * @throws Exception
121 - */
122 - public function clone_table( string $name_table ): bool {
123 - if ( ! current_user_can( ADMIN_ROLE ) ) {
124 - throw new Exception( 'You don\'t have permission' );
125 - }
126 -
127 - $table_bk = $name_table . '_bk';
128 -
129 - // Drop table bk if exists.
130 - $this->drop_table( $table_bk );
131 -
132 - // Clone table
133 - $this->wpdb->query( "CREATE TABLE $table_bk LIKE $name_table" );
134 - $this->wpdb->query( "INSERT INTO $table_bk SELECT * FROM $name_table" );
135 -
136 - /*dbDelta(
137 - "CREATE TABLE $table_bk LIKE $name_table;
138 - INSERT INTO $table_bk SELECT * FROM $name_table;"
139 - );*/
140 -
141 - $this->check_execute_has_error();
142 -
143 - return true;
144 - }
145 -
146 - /**
147 - * Check column table
148 - *
149 - * @param string $name_table .
150 - * @param string $name_col .
151 - *
152 - * @return bool|int
153 - */
154 - public function check_col_table( string $name_table = '', string $name_col = '' ) {
155 - $query = $this->wpdb->prepare( "SHOW COLUMNS FROM $name_table LIKE '%s'", $name_col );
156 -
157 - return $this->wpdb->query( $query );
158 - }
159 -
160 - /**
161 - * Drop Column of Table
162 - *
163 - * @param string $name_table .
164 - * @param string $name_col .
165 - *
166 - * @return bool|int
167 - * @throws Exception
168 - */
169 - public function drop_col_table( string $name_table = '', string $name_col = '' ) {
170 - if ( ! current_user_can( 'administrator' ) ) {
171 - return false;
172 - }
173 -
174 - $check_table = $this->check_col_table( $name_table, $name_col );
175 -
176 - if ( $check_table ) {
177 - $execute = $this->wpdb->query( "ALTER TABLE $name_table DROP COLUMN $name_col" );
178 -
179 - $this->check_execute_has_error();
180 -
181 - return $execute;
182 - }
183 -
184 - return true;
185 - }
186 -
187 - /**
188 - * Add Column of Table
189 - *
190 - * @param string $name_table .
191 - * @param string $name_col .
192 - * @param string $type .
193 - * @param string $after_col .
194 - *
195 - * @return bool|int
196 - * @throws Exception
197 - */
198 - public function add_col_table( string $name_table, string $name_col, string $type, string $after_col = '' ) {
199 - if ( ! current_user_can( ADMIN_ROLE ) ) {
200 - throw new Exception( 'You don\'t have permission' );
201 - }
202 -
203 - $query_add = '';
204 -
205 - $col_exists = $this->check_col_table( $name_table, $name_col );
206 -
207 - if ( ! empty( $after_col ) ) {
208 - $query_add .= "AFTER $after_col";
209 - }
210 -
211 - if ( ! $col_exists ) {
212 - $execute = $this->wpdb->query( "ALTER TABLE $name_table ADD COLUMN $name_col $type $query_add" );
213 -
214 - $this->check_execute_has_error();
215 -
216 - return $execute;
217 - }
218 -
219 - return true;
220 - }
221 -
222 - /**
223 - * Drop Index of Table
224 - *
225 - * @param string $name_table .
226 - *
227 - * @return void
228 - * @throws Exception
229 - */
230 - public function drop_indexs_table( string $name_table ) {
231 - $show_index = "SHOW INDEX FROM $name_table";
232 - $indexs = $this->wpdb->get_results( $show_index );
233 -
234 - foreach ( $indexs as $index ) {
235 - if ( 'PRIMARY' === $index->Key_name || '1' !== $index->Seq_in_index ) {
236 - continue;
237 - }
238 -
239 - $query = "ALTER TABLE $name_table DROP INDEX $index->Key_name";
240 -
241 - $this->wpdb->query( $query );
242 - $this->check_execute_has_error();
243 - }
244 - }
245 -
246 - /**
247 - * Add Index of Table
248 - *
249 - * @param string $name_table .
250 - * @param array $indexs .
251 - *
252 - * @return bool|int
253 - * @throws Exception
254 - */
255 - public function add_indexs_table( string $name_table, array $indexs ) {
256 - $add_index = '';
257 - $count_indexs = count( $indexs ) - 1;
258 -
259 - // Drop indexs .
260 - $this->drop_indexs_table( $name_table );
261 -
262 - foreach ( $indexs as $index ) {
263 - if ( $count_indexs === array_search( $index, $indexs ) ) {
264 - $add_index .= ' ADD INDEX ' . $index . ' (' . $index . ')';
265 - } else {
266 - $add_index .= ' ADD INDEX ' . $index . ' (' . $index . '),';
267 - }
268 - }
269 -
270 - $execute = $this->wpdb->query(
271 - "ALTER TABLE $name_table
272 - $add_index"
273 - );
274 -
275 - $this->check_execute_has_error();
276 -
277 - return $execute;
278 - }
279 -
280 - /**
281 - * Drop table
282 - *
283 - * @param string $name_table .
284 - *
285 - * @return bool|int
286 - * @throws Exception
287 - */
288 - public function drop_table( string $name_table = '' ) {
289 - if ( ! current_user_can( ADMIN_ROLE ) ) {
290 - throw new Exception( 'You don\'t have permission' );
291 - }
292 -
293 - // Check table exists.
294 - $tb_exists = $this->check_table_exists( $name_table );
295 - if ( $tb_exists ) {
296 - $execute = $this->wpdb->query( "DROP TABLE $name_table" );
297 -
298 - $this->check_execute_has_error();
299 -
300 - return $execute;
301 - }
302 -
303 - return true;
304 - }
305 -
306 - /**
307 - * Get list columns name of table
308 - *
309 - * @param string $name_table
310 - *
311 - * @return array
312 - * @throws Exception
313 - * @version 1.0.0
314 - * @since 4.1.6
315 - * @author tungnx
316 - */
317 - public function get_cols_of_table( string $name_table ): array {
318 - $query = "SHOW COLUMNS FROM $name_table";
319 -
320 - $result = $this->wpdb->get_col( $query );
321 -
322 - $this->check_execute_has_error();
323 -
324 - return $result;
325 - }
326 -
327 - /**
328 - * Create table learnpress_user_item_results
329 - *
330 - * @return bool|int
331 - * @throws Exception
332 - */
333 - public function create_tb_lp_user_item_results() {
334 - $collate = $this->get_collate();
335 -
336 - $execute = $this->wpdb->query(
337 - "
338 - CREATE TABLE IF NOT EXISTS $this->tb_lp_user_item_results(
339 - id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
340 - user_item_id bigint(20) unsigned NOT NULL,
341 - result longtext,
342 - PRIMARY KEY (id),
343 - KEY user_item_id (user_item_id)
344 - ) $collate
345 - "
346 - );
347 -
348 - $this->check_execute_has_error();
349 -
350 - return $execute;
351 - }
352 -
353 - /**
354 - * Create table learnpress_upgrade_db
355 - *
356 - * @return bool|int
357 - * @throws Exception
358 - */
359 - public function create_tb_lp_upgrade_db() {
360 - $collate = $this->get_collate();
361 -
362 - $execute = $this->wpdb->query(
363 - "
364 - CREATE TABLE IF NOT EXISTS {$this->tb_lp_upgrade_db}(
365 - step varchar(50) PRIMARY KEY UNIQUE,
366 - status varchar(10),
367 - KEY status (status)
368 - ) $collate
369 - "
370 - );
371 -
372 - $this->check_execute_has_error();
373 -
374 - return $execute;
375 - }
376 -
377 - /**
378 - * Set step completed.
379 - *
380 - * @param string $step .
381 - * @param string $status .
382 - *
383 - * @return int|bool
384 - */
385 - public function set_step_complete( string $step, string $status ) {
386 - if ( ! current_user_can( 'administrator' ) ) {
387 - return false;
388 - }
389 -
390 - return $this->wpdb->insert(
391 - $this->tb_lp_upgrade_db,
392 - array(
393 - 'step' => $step,
394 - 'status' => $status,
395 - ),
396 - array( '%s', '%s' )
397 - );
398 - }
399 -
400 - /**
401 - * Get steps completed.
402 - *
403 - * @return array|object|null
404 - */
405 - public function get_steps_completed() {
406 - return $this->wpdb->get_results( "SELECT step, status FROM {$this->tb_lp_upgrade_db}", OBJECT_K );
407 - }
408 -
409 - /**
410 - * Check execute current has any errors.
411 - *
412 - * @throws Exception
413 - */
414 - public function check_execute_has_error() {
415 - if ( $this->wpdb->last_error ) {
416 - throw new Exception( $this->wpdb->last_error );
417 - }
418 - }
419 -
420 - /**
421 - * Important: Reason need set again indexes for table options of WP
422 - * because if want change value of "option_name" will error "database error Duplicate entry"
423 - * So before set must drop and add when done all
424 - *
425 - * @throws Exception
426 - * @version 1.0.0
427 - * @since 4.0.3
428 - * @author tungnx
429 - */
430 - public function create_indexes_tb_options() {
431 - $this->drop_indexs_table( $this->tb_options );
432 - $result = $this->wpdb->query(
433 - "
434 - ALTER TABLE $this->tb_options
435 - ADD UNIQUE option_name (option_name),
436 - ADD INDEX autoload (autoload)
437 - "
438 - );
439 -
440 - $this->check_execute_has_error();
441 -
442 - return $result;
443 - }
444 -
445 - /**
446 - * Rename table
447 - *
448 - * @throws Exception
449 - * @version 1.0.0
450 - * @since 4.0.3
451 - * @author tungnx
452 - */
453 - public function rename_table( string $name_table = '', string $new_name = '' ) {
454 - if ( ! current_user_can( ADMIN_ROLE ) ) {
455 - throw new Exception( 'You don\'t have permission' );
456 - }
457 -
458 - $tb_exists = $this->check_table_exists( $name_table );
459 -
460 - if ( ! $tb_exists ) {
461 - throw new Exception( 'Table not exists' );
462 - }
463 -
464 - $result = $this->wpdb->query(
465 - "
466 - ALTER TABLE $name_table
467 - RENAME $new_name
468 - "
469 - );
470 - $this->check_execute_has_error();
471 -
472 - return $result;
473 - }
474 -
475 - /**
476 - * Check key postmeta exist on Database
477 - *
478 - * @param int $post_id
479 - * @param string $key
480 - *
481 - * @return bool|int
482 - */
483 - public function check_key_postmeta_exists( int $post_id = 0, string $key = '' ) {
484 - return $this->wpdb->query(
485 - $this->wpdb->prepare(
486 - "
487 - SELECT meta_id FROM $this->tb_postmeta
488 - WHERE meta_key = %s
489 - AND post_id = %d
490 - ",
491 - $key,
492 - $post_id
493 - )
494 - );
495 - }
496 -
497 - /**
498 - * Get total pages
499 - *
500 - * @param int $limit
501 - * @param int $total_rows
502 - *
503 - * @return int
504 - */
505 - public static function get_total_pages( int $limit = 0, int $total_rows = 0 ): int {
506 - if ( $limit == 0 ) {
507 - return 0;
508 - }
509 -
510 - $total_pages = (int) ceil( $total_rows / $limit );
511 -
512 - return (int) $total_pages;
513 - }
514 -
515 - /**
516 - * Get query string single row
517 - *
518 - * @param FilterBase $filter
519 - *
520 - * @since 4.2.5
521 - * @version 1.0.1
522 - */
523 - public function get_query_single_row( &$filter ) {
524 - $filter->limit = 1;
525 - $filter->return_string_query = true;
526 - $filter->run_query_count = false;
527 - }
528 -
529 - /**
530 - * Get result query
531 - *
532 - * @param FilterBase $filter
533 - * @param int $total_rows
534 - *
535 - * @return array|object|null|int|string
536 - * @throws Exception
537 - * @author tungnx
538 - * @version 1.0.2
539 - * @since 4.1.6
540 - */
541 - public function execute( $filter, int &$total_rows = 0 ) {
542 - $result = null;
543 -
544 - // Where
545 - $WHERE = array( 'WHERE 1=1' );
546 -
547 - // Fields select
548 - $FIELDS = '*';
549 - if ( ! empty( $filter->only_fields ) ) {
550 - $FIELDS = implode( ',', array_unique( $filter->only_fields ) );
551 - } elseif ( ! empty( $filter->fields ) ) {
552 - // exclude more fields
553 - if ( ! empty( $filter->exclude_fields ) ) {
554 - foreach ( $filter->exclude_fields as $field ) {
555 - $index_field = array_search( $field, $filter->fields );
556 - if ( $index_field ) {
557 - unset( $filter->fields[ $index_field ] );
558 - }
559 - }
560 - }
561 -
562 - foreach ( $filter->fields as $key => $field ) {
563 - if ( $field === 'order' ) {
564 - // Replace order with `order` to avoid conflict with SQL reserved word.
565 - $filter->fields[ $key ] = '`order`';
566 - break;
567 - }
568 - }
569 -
570 - $FIELDS = implode( ',', array_unique( $filter->fields ) );
571 - }
572 - $FIELDS = apply_filters( 'lp/query/fields', $FIELDS, $filter );
573 -
574 - $INNER_JOIN = array();
575 - $INNER_JOIN = array_merge( $INNER_JOIN, $filter->join );
576 - $INNER_JOIN = apply_filters( 'lp/query/inner_join', $INNER_JOIN, $filter );
577 - $INNER_JOIN = implode( ' ', array_unique( $INNER_JOIN ) );
578 -
579 - $WHERE = array_merge( $WHERE, $filter->where );
580 - $WHERE = apply_filters( 'lp/query/where', $WHERE, $filter );
581 - $WHERE = implode( ' ', array_unique( $WHERE ) );
582 -
583 - // Group by
584 - $GROUP_BY = '';
585 - if ( $filter->group_by ) {
586 - $GROUP_BY .= 'GROUP BY ' . $filter->group_by;
587 - $GROUP_BY = apply_filters( 'lp/query/group_by', $GROUP_BY, $filter );
588 - }
589 -
590 - // Order by
591 - $ORDER_BY = '';
592 - if ( $filter->order_by ) {
593 - $filter->order = strtoupper( $filter->order );
594 - if ( ! in_array( $filter->order, [ 'DESC', 'ASC' ] ) ) {
595 - $filter->order = 'DESC';
596 - }
597 -
598 - $ORDER_BY .= 'ORDER BY ' . $filter->order_by . ' ' . $filter->order . ' ';
599 - $ORDER_BY = apply_filters( 'lp/query/order_by', $ORDER_BY, $filter );
600 - }
601 -
602 - // Limit
603 - $LIMIT = '';
604 - if ( $filter->limit != - 1 ) {
605 - $filter->limit = absint( $filter->limit );
606 - /*if ( $filter->limit > $filter->max_limit ) {
607 - $filter->limit = $filter->max_limit;
608 - }*/
609 - $offset = $filter->limit * ( $filter->page - 1 );
610 - $LIMIT = $this->wpdb->prepare( 'LIMIT %d, %d', $offset, $filter->limit );
611 - }
612 -
613 - // For nest query
614 - if ( $filter->return_string_query ) {
615 - $LIMIT = '';
616 - }
617 -
618 - // From table or group select
619 - $COLLECTION = '';
620 - if ( ! empty( $filter->collection ) ) {
621 - $COLLECTION = $filter->collection;
622 - }
623 -
624 - // Alias table
625 - $ALIAS_COLLECTION = 'X';
626 - if ( ! empty( $filter->collection_alias ) ) {
627 - $ALIAS_COLLECTION = $filter->collection_alias;
628 - }
629 -
630 - // Query
631 - $query = "SELECT $FIELDS FROM $COLLECTION AS $ALIAS_COLLECTION
632 - $INNER_JOIN
633 - $WHERE
634 - $GROUP_BY
635 - $ORDER_BY
636 - $LIMIT
637 - ";
638 -
639 - if ( $filter->return_string_query ) {
640 - return $query;
641 - } elseif ( ! empty( $filter->union ) ) {
642 - $query = implode( ' UNION ', array_unique( $filter->union ) );
643 - $query .= $GROUP_BY;
644 - $query .= $ORDER_BY;
645 - $query .= $LIMIT;
646 - }
647 -
648 - if ( ! $filter->query_count ) {
649 - // Debug string query
650 - if ( $filter->debug_string_query ) {
651 - return $query;
652 - }
653 -
654 - $result = $this->wpdb->get_results( $query );
655 - }
656 -
657 - // Query total rows
658 - if ( $filter->run_query_count ) {
659 - $query = str_replace( array( $LIMIT, $ORDER_BY ), '', $query );
660 - $query_total = "SELECT COUNT($filter->field_count) FROM ($query) AS $ALIAS_COLLECTION";
661 - $total_rows = (int) $this->wpdb->get_var( $query_total );
662 -
663 - $this->check_execute_has_error();
664 -
665 - if ( $filter->query_count ) {
666 - // Debug string query
667 - if ( $filter->debug_string_query ) {
668 - return $query_total;
669 - }
670 -
671 - return $total_rows;
672 - }
673 - }
674 -
675 - $this->check_execute_has_error();
676 -
677 - return $result;
678 - }
679 -
680 - /**
681 - * Query update
682 - *
683 - * @param FilterBase $filter
684 - *
685 - * @throws Exception
686 - * @since 4.1.7
687 - * @version 1.0.1
688 - */
689 - public function update_execute( $filter ) {
690 -
691 - $COLLECTION = $filter->collection;
692 -
693 - // SET value
694 - $SET = apply_filters( 'lp/query/update/set', $filter->set, $filter );
695 - $SET = implode( ',', array_unique( $SET ) );
696 -
697 - // Where
698 - $WHERE = array( 'WHERE 1=1' );
699 - $WHERE = array_merge( $WHERE, $filter->where );
700 - $WHERE = apply_filters( 'lp/query/update/where', $WHERE, $filter );
701 - $WHERE = implode( ' ', array_unique( $WHERE ) );
702 -
703 - $query = "
704 - UPDATE $COLLECTION
705 - SET $SET
706 - $WHERE
707 - ";
708 -
709 - $result = $this->wpdb->query( $query );
710 -
711 - $this->check_execute_has_error();
712 -
713 - return $result;
714 - }
715 -
716 - /**
717 - * Query delete
718 - *
719 - * @param FilterBase $filter
720 - * @param string $table
721 - *
722 - * @return bool|int|\mysqli_result|string|null
723 - * @throws Exception
724 - * @since 4.1.7
725 - * @version 1.0.1
726 - */
727 - public function delete_execute( $filter, string $table = '' ) {
728 - $COLLECTION = $filter->collection;
729 -
730 - // Where
731 - $WHERE = array( 'WHERE 1=1' );
732 - $WHERE = array_merge( $WHERE, $filter->where );
733 - $WHERE = apply_filters( 'lp/query/delete/where', $WHERE, $filter );
734 - $WHERE = implode( ' ', array_unique( $WHERE ) );
735 -
736 - // Join
737 - $INNER_JOIN = array();
738 - $INNER_JOIN = array_merge( $INNER_JOIN, $filter->join );
739 - $INNER_JOIN = apply_filters( 'lp/query/delete/inner_join', $INNER_JOIN, $filter );
740 - $INNER_JOIN = implode( ' ', array_unique( $INNER_JOIN ) );
741 -
742 - $query = "
743 - DELETE $table FROM $COLLECTION
744 - $INNER_JOIN
745 - $WHERE
746 - ";
747 -
748 - if ( $filter->return_string_query ) {
749 - return $query;
750 - }
751 -
752 - $result = $this->wpdb->query( $query );
753 -
754 - $this->check_execute_has_error();
755 -
756 - return $result;
757 - }
758 -
759 - /**
760 - * Get values of list object by key
761 - *
762 - * @param array $arr_object
763 - * @param string $key
764 - *
765 - * @return array
766 - */
767 - public static function get_values_by_key( array $arr_object, string $key = 'ID' ): array {
768 - $arr_object_ids = array();
769 - foreach ( $arr_object as $object ) {
770 - $arr_object_ids[] = $object->{$key};
771 - }
772 -
773 - return $arr_object_ids;
774 - }
775 -
776 - /**
777 - * Insert data
778 - *
779 - * @param array $args [ 'data' => [], 'filter' => FilterBase, 'table_name' => '', 'key_auto_increment' => '' ]
780 - *
781 - * @return int
782 - * @throws Exception
783 - * @version 1.0.1
784 - * @since 4.2.9
785 - */
786 - public function insert_data( array $args ): int {
787 - $data = $args['data'] ?? [];
788 - $filter = $args['filter'] ?? null;
789 - $table_name = $args['table_name'] ?? '';
790 - $key_auto_increment = $args['key_auto_increment'] ?? '';
791 - $key_auto_increment = sanitize_key( $key_auto_increment );
792 -
793 - if ( empty( $data ) || ! is_array( $data ) ) {
794 - throw new Exception( __( 'Data must be an array!', 'learnpress' ) . ' | ' . __FUNCTION__ );
795 - }
796 -
797 - /*if ( ! $filter instanceof FilterBase ) {
798 - throw new Exception( __( 'Invalid filter!', 'learnpress' ) . ' | ' . __FUNCTION__ );
799 - }*/
800 -
801 - if ( empty( $filter->all_fields ) ) {
802 - throw new Exception( __( 'Filter must have property all_fields!', 'learnpress' ) . ' | ' . __FUNCTION__ );
803 - }
804 -
805 - if ( empty( $table_name ) ) {
806 - throw new Exception( __( 'Table name is required!', 'learnpress' ) . ' | ' . __FUNCTION__ );
807 - }
808 -
809 - if ( empty( $key_auto_increment ) || ! is_string( $key_auto_increment ) ) {
810 - throw new Exception( __( 'Key auto increment must be a string!', 'learnpress' ) . ' | ' . __FUNCTION__ );
811 - }
812 -
813 - foreach ( $data as $col_name => $value ) {
814 - if ( ! in_array( $col_name, $filter->all_fields ) ) {
815 - unset( $data[ $col_name ] );
816 - }
817 - }
818 -
819 - // unset key is auto increment.
820 - unset( $data[ $key_auto_increment ] );
821 -
822 - $this->wpdb->insert( $table_name, $data );
823 -
824 - $this->check_execute_has_error();
825 -
826 - return $this->wpdb->insert_id;
827 - }
828 -
829 - /**
830 - * Update data
831 - *
832 - * @param array $args
833 - *
834 - * @return bool
835 - *
836 - * @throws Exception
837 - * @since 4.2.9
838 - * @version 1.0.1
839 - */
840 - public function update_data( array $args ): bool {
841 - $data = $args['data'] ?? [];
842 - $filter = $args['filter'] ?? null;
843 - $table_name = $args['table_name'] ?? '';
844 - $where_key = $args['where_key'] ?? '';
845 - $where_key = sanitize_key( $where_key );
846 -
847 - /*if ( ! $filter instanceof FilterBase ) {
848 - throw new Exception( __( 'Invalid filter!', 'learnpress' ) . ' | ' . __FUNCTION__ );
849 - }*/
850 -
851 - if ( empty( $filter->all_fields ) ) {
852 - throw new Exception( __( 'Filter must have property all_fields!', 'learnpress' ) . ' | ' . __FUNCTION__ );
853 - }
854 -
855 - if ( empty( $data ) || ! is_array( $data ) ) {
856 - throw new Exception( __( 'Data must be an array!', 'learnpress' ) . ' | ' . __FUNCTION__ );
857 - }
858 -
859 - if ( empty( $where_key ) ) {
860 - throw new Exception( __( 'Invalid where key!', 'learnpress' ) . ' | ' . __FUNCTION__ );
861 - }
862 -
863 - if ( empty( $table_name ) ) {
864 - throw new Exception( __( 'Table name is required!', 'learnpress' ) . ' | ' . __FUNCTION__ );
865 - }
866 -
867 - $filter->collection = $table_name;
868 - foreach ( $data as $col_name => $value ) {
869 - if ( ! in_array( $col_name, $filter->all_fields ) ) {
870 - continue;
871 - }
872 -
873 - // Key `order` is reserved keyword in MySQL
874 - if ( $col_name === 'order' ) {
875 - $col_name = '`order`';
876 - }
877 -
878 - if ( is_null( $value ) ) {
879 - $filter->set[] = $col_name . ' = null';
880 - } else {
881 - $filter->set[] = $this->wpdb->prepare( $col_name . ' = %s', $value );
882 - }
883 - }
884 -
885 - $filter->where[] = $this->wpdb->prepare( "AND $where_key = %d", $data[ $where_key ] );
886 - $this->update_execute( $filter );
887 -
888 - return true;
889 - }
890 -}
1 +<?php
2 +
3 +namespace LearnPress\Databases;
4 +
5 +use Exception;
6 +use LearnPress\Filters\FilterBase;
7 +use wpdb;
8 +
9 +defined( 'ABSPATH' ) || exit();
10 +
11 +/**
12 + * Class DataBase
13 + *
14 + * @since 4.2.9.3
15 + * @version 1.0.1
16 + */
17 +class DataBase {
18 + private static $_instance;
19 + public $wpdb, $tb_users;
20 + public $tb_lp_courses;
21 + public $tb_lp_user_items, $tb_lp_user_itemmeta;
22 + public $tb_posts, $tb_postmeta, $tb_options;
23 + public $tb_terms, $tb_term_relationships, $tb_term_taxonomy;
24 + public $tb_lp_order_items, $tb_lp_order_itemmeta;
25 + public $tb_lp_sections, $tb_lp_section_items;
26 + public $tb_lp_quiz_questions;
27 + public $tb_lp_user_item_results;
28 + public $tb_lp_question_answers;
29 + public $tb_lp_question_answermeta;
30 + public $tb_lp_upgrade_db;
31 + public $tb_lp_sessions;
32 + public $tb_lp_files;
33 + public $tb_lp_webhooks;
34 + public $tb_thim_cache;
35 + public $tb_lp_mcp_api_keys;
36 + private $collate = '';
37 + public $max_index_length = '191';
38 +
39 + protected function __construct() {
40 + /**
41 + * @var wpdb $wpdb
42 + */
43 + global $wpdb;
44 + $prefix = $wpdb->prefix;
45 +
46 + $this->wpdb = $wpdb;
47 + $this->tb_users = $wpdb->users;
48 + $this->tb_posts = $wpdb->posts;
49 + $this->tb_postmeta = $wpdb->postmeta;
50 + $this->tb_options = $wpdb->options;
51 + $this->tb_terms = $wpdb->terms;
52 + $this->tb_term_relationships = $wpdb->term_relationships;
53 + $this->tb_term_taxonomy = $wpdb->term_taxonomy;
54 + $this->tb_lp_courses = $prefix . 'learnpress_courses';
55 + $this->tb_lp_user_items = $prefix . 'learnpress_user_items';
56 + $this->tb_lp_user_itemmeta = $prefix . 'learnpress_user_itemmeta';
57 + $this->tb_lp_order_items = $prefix . 'learnpress_order_items';
58 + $this->tb_lp_order_itemmeta = $prefix . 'learnpress_order_itemmeta';
59 + $this->tb_lp_section_items = $prefix . 'learnpress_section_items';
60 + $this->tb_lp_sections = $prefix . 'learnpress_sections';
61 + $this->tb_lp_quiz_questions = $prefix . 'learnpress_quiz_questions';
62 + $this->tb_lp_user_item_results = $prefix . 'learnpress_user_item_results';
63 + $this->tb_lp_question_answers = $prefix . 'learnpress_question_answers';
64 + $this->tb_lp_question_answermeta = $prefix . 'learnpress_question_answermeta';
65 + $this->tb_lp_upgrade_db = $prefix . 'learnpress_upgrade_db';
66 + $this->tb_lp_sessions = $prefix . 'learnpress_sessions';
67 + $this->tb_lp_files = $prefix . 'learnpress_files';
68 + $this->tb_lp_webhooks = $prefix . 'learnpress_webhooks';
69 + $this->tb_thim_cache = $prefix . 'thim_cache';
70 + $this->tb_lp_mcp_api_keys = $prefix . 'learnpress_mcp_api_keys';
71 + $this->wpdb->hide_errors();
72 + $this->set_collate();
73 + }
74 +
75 + /**
76 + * Get Instance
77 + *
78 + * @return DataBase
79 + */
80 + public static function getInstance() {
81 + if ( is_null( self::$_instance ) ) {
82 + self::$_instance = new self();
83 + }
84 +
85 + return self::$_instance;
86 + }
87 +
88 + public function set_collate() {
89 + $collate = '';
90 +
91 + if ( $this->wpdb->has_cap( 'collation' ) ) {
92 + if ( ! empty( $this->wpdb->charset ) ) {
93 + $collate .= 'DEFAULT CHARACTER SET ' . $this->wpdb->charset;
94 + }
95 +
96 + if ( ! empty( $this->wpdb->collate ) ) {
97 + $collate .= ' COLLATE ' . $this->wpdb->collate;
98 + }
99 + }
100 +
101 + $this->collate = $collate;
102 + }
103 +
104 + public function get_collate(): string {
105 + return $this->collate;
106 + }
107 +
108 + /**
109 + * Check table exists.
110 + *
111 + * @param string $name_table
112 + *
113 + * @return bool|int
114 + * @throws Exception
115 + */
116 + public function check_table_exists( string $name_table ) {
117 + return $this->wpdb->query(
118 + $this->wpdb->prepare(
119 + "SHOW TABLES LIKE '%s'", $name_table
120 + )
121 + );
122 + }
123 +
124 + /**
125 + * Clone table
126 + *
127 + * @param string $name_table .
128 + *
129 + * @throws Exception
130 + */
131 + public function clone_table( string $name_table ): bool {
132 + if ( ! current_user_can( ADMIN_ROLE ) ) {
133 + throw new Exception( 'You don\'t have permission' );
134 + }
135 +
136 + $table_bk = $name_table . '_bk';
137 +
138 + // Drop table bk if exists.
139 + $this->drop_table( $table_bk );
140 +
141 + // Clone table
142 + $this->wpdb->query( "CREATE TABLE $table_bk LIKE $name_table" );
143 + $this->wpdb->query( "INSERT INTO $table_bk SELECT * FROM $name_table" );
144 +
145 + /*dbDelta(
146 + "CREATE TABLE $table_bk LIKE $name_table;
147 + INSERT INTO $table_bk SELECT * FROM $name_table;"
148 + );*/
149 +
150 + $this->check_execute_has_error();
151 +
152 + return true;
153 + }
154 +
155 + /**
156 + * Check column table
157 + *
158 + * @param string $name_table .
159 + * @param string $name_col .
160 + *
161 + * @return bool|int
162 + */
163 + public function check_col_table( string $name_table = '', string $name_col = '' ) {
164 + $query = $this->wpdb->prepare( "SHOW COLUMNS FROM $name_table LIKE '%s'", $name_col );
165 + //$query = $this->wpdb->prepare( "SHOW COLUMNS FROM $name_table WHERE Field = '%s'", $name_col );
166 +
167 + return $this->wpdb->query( $query );
168 + }
169 +
170 + /**
171 + * Drop Column of Table
172 + *
173 + * @param string $name_table .
174 + * @param string $name_col .
175 + *
176 + * @return bool|int
177 + * @throws Exception
178 + */
179 + public function drop_col_table( string $name_table = '', string $name_col = '' ) {
180 + if ( ! current_user_can( 'administrator' ) ) {
181 + return false;
182 + }
183 +
184 + $check_table = $this->check_col_table( $name_table, $name_col );
185 +
186 + if ( $check_table ) {
187 + $execute = $this->wpdb->query( "ALTER TABLE $name_table DROP COLUMN $name_col" );
188 +
189 + $this->check_execute_has_error();
190 +
191 + return $execute;
192 + }
193 +
194 + return true;
195 + }
196 +
197 + /**
198 + * Add Column of Table
199 + *
200 + * @param string $name_table .
201 + * @param string $name_col .
202 + * @param string $type .
203 + * @param string $after_col .
204 + *
205 + * @return bool|int
206 + * @throws Exception
207 + */
208 + public function add_col_table( string $name_table, string $name_col, string $type, string $after_col = '' ) {
209 + if ( ! current_user_can( ADMIN_ROLE ) ) {
210 + return false;
211 + }
212 +
213 + $query_add = '';
214 +
215 + $col_exists = $this->check_col_table( $name_table, $name_col );
216 +
217 + if ( ! empty( $after_col ) ) {
218 + $query_add .= "AFTER $after_col";
219 + }
220 +
221 + if ( ! $col_exists ) {
222 + $execute = $this->wpdb->query( "ALTER TABLE $name_table ADD COLUMN $name_col $type $query_add" );
223 +
224 + $this->check_execute_has_error();
225 +
226 + return $execute;
227 + }
228 +
229 + return true;
230 + }
231 +
232 + /**
233 + * Drop Index of Table
234 + *
235 + * @param string $name_table .
236 + *
237 + * @return void
238 + * @throws Exception
239 + */
240 + public function drop_indexs_table( string $name_table ) {
241 + $show_index = "SHOW INDEX FROM $name_table";
242 + $indexs = $this->wpdb->get_results( $show_index );
243 +
244 + foreach ( $indexs as $index ) {
245 + if ( 'PRIMARY' === $index->Key_name || '1' !== $index->Seq_in_index ) {
246 + continue;
247 + }
248 +
249 + $query = "ALTER TABLE $name_table DROP INDEX $index->Key_name";
250 +
251 + $this->wpdb->query( $query );
252 + $this->check_execute_has_error();
253 + }
254 + }
255 +
256 + /**
257 + * Add Index of Table
258 + *
259 + * @param string $name_table .
260 + * @param array $indexs .
261 + *
262 + * @return bool|int
263 + * @throws Exception
264 + */
265 + public function add_indexs_table( string $name_table, array $indexs ) {
266 + $add_index = '';
267 + $count_indexs = count( $indexs ) - 1;
268 +
269 + // Drop indexs .
270 + $this->drop_indexs_table( $name_table );
271 +
272 + foreach ( $indexs as $index ) {
273 + if ( $count_indexs === array_search( $index, $indexs ) ) {
274 + $add_index .= ' ADD INDEX ' . $index . ' (' . $index . ')';
275 + } else {
276 + $add_index .= ' ADD INDEX ' . $index . ' (' . $index . '),';
277 + }
278 + }
279 +
280 + $execute = $this->wpdb->query(
281 + "ALTER TABLE $name_table
282 + $add_index"
283 + );
284 +
285 + $this->check_execute_has_error();
286 +
287 + return $execute;
288 + }
289 +
290 + /**
291 + * Drop table
292 + *
293 + * @param string $name_table .
294 + *
295 + * @return bool|int
296 + * @throws Exception
297 + */
298 + public function drop_table( string $name_table = '' ) {
299 + if ( ! current_user_can( ADMIN_ROLE ) ) {
300 + throw new Exception( 'You don\'t have permission' );
301 + }
302 +
303 + // Check table exists.
304 + $tb_exists = $this->check_table_exists( $name_table );
305 + if ( $tb_exists ) {
306 + $execute = $this->wpdb->query( "DROP TABLE $name_table" );
307 +
308 + $this->check_execute_has_error();
309 +
310 + return $execute;
311 + }
312 +
313 + return true;
314 + }
315 +
316 + /**
317 + * Get list columns name of table
318 + *
319 + * @param string $name_table
320 + *
321 + * @return array
322 + * @throws Exception
323 + * @version 1.0.0
324 + * @since 4.1.6
325 + * @author tungnx
326 + */
327 + public function get_cols_of_table( string $name_table ): array {
328 + $query = "SHOW COLUMNS FROM $name_table";
329 +
330 + $result = $this->wpdb->get_col( $query );
331 +
332 + $this->check_execute_has_error();
333 +
334 + return $result;
335 + }
336 +
337 + /**
338 + * Create table learnpress_user_item_results
339 + *
340 + * @return bool|int
341 + * @throws Exception
342 + */
343 + public function create_tb_lp_user_item_results() {
344 + $collate = $this->get_collate();
345 +
346 + $execute = $this->wpdb->query(
347 + "
348 + CREATE TABLE IF NOT EXISTS $this->tb_lp_user_item_results(
349 + id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
350 + user_item_id bigint(20) unsigned NOT NULL,
351 + result longtext,
352 + PRIMARY KEY (id),
353 + KEY user_item_id (user_item_id)
354 + ) $collate
355 + "
356 + );
357 +
358 + $this->check_execute_has_error();
359 +
360 + return $execute;
361 + }
362 +
363 + /**
364 + * Create table learnpress_upgrade_db
365 + *
366 + * @return bool|int
367 + * @throws Exception
368 + */
369 + public function create_tb_lp_upgrade_db() {
370 + $collate = $this->get_collate();
371 +
372 + $execute = $this->wpdb->query(
373 + "
374 + CREATE TABLE IF NOT EXISTS {$this->tb_lp_upgrade_db}(
375 + step varchar(50) PRIMARY KEY UNIQUE,
376 + status varchar(10),
377 + KEY status (status)
378 + ) $collate
379 + "
380 + );
381 +
382 + $this->check_execute_has_error();
383 +
384 + return $execute;
385 + }
386 +
387 + /**
388 + * Set step completed.
389 + *
390 + * @param string $step .
391 + * @param string $status .
392 + *
393 + * @return int|bool
394 + */
395 + public function set_step_complete( string $step, string $status ) {
396 + if ( ! current_user_can( 'administrator' ) ) {
397 + return false;
398 + }
399 +
400 + return $this->wpdb->insert(
401 + $this->tb_lp_upgrade_db,
402 + array(
403 + 'step' => $step,
404 + 'status' => $status,
405 + ),
406 + array( '%s', '%s' )
407 + );
408 + }
409 +
410 + /**
411 + * Get steps completed.
412 + *
413 + * @return array|object|null
414 + */
415 + public function get_steps_completed() {
416 + return $this->wpdb->get_results( "SELECT step, status FROM {$this->tb_lp_upgrade_db}", OBJECT_K );
417 + }
418 +
419 + /**
420 + * Check execute current has any errors.
421 + *
422 + * @throws Exception
423 + */
424 + public function check_execute_has_error() {
425 + if ( $this->wpdb->last_error ) {
426 + throw new Exception( $this->wpdb->last_error );
427 + }
428 + }
429 +
430 + /**
431 + * Important: Reason need set again indexes for table options of WP
432 + * because if want change value of "option_name" will error "database error Duplicate entry"
433 + * So before set must drop and add when done all
434 + *
435 + * @throws Exception
436 + * @version 1.0.0
437 + * @since 4.0.3
438 + * @author tungnx
439 + */
440 + public function create_indexes_tb_options() {
441 + $this->drop_indexs_table( $this->tb_options );
442 + $result = $this->wpdb->query(
443 + "
444 + ALTER TABLE $this->tb_options
445 + ADD UNIQUE option_name (option_name),
446 + ADD INDEX autoload (autoload)
447 + "
448 + );
449 +
450 + $this->check_execute_has_error();
451 +
452 + return $result;
453 + }
454 +
455 + /**
456 + * Rename table
457 + *
458 + * @throws Exception
459 + * @version 1.0.0
460 + * @since 4.0.3
461 + * @author tungnx
462 + */
463 + public function rename_table( string $name_table = '', string $new_name = '' ) {
464 + if ( ! current_user_can( ADMIN_ROLE ) ) {
465 + throw new Exception( 'You don\'t have permission' );
466 + }
467 +
468 + $tb_exists = $this->check_table_exists( $name_table );
469 +
470 + if ( ! $tb_exists ) {
471 + throw new Exception( 'Table not exists' );
472 + }
473 +
474 + $result = $this->wpdb->query(
475 + "
476 + ALTER TABLE $name_table
477 + RENAME $new_name
478 + "
479 + );
480 + $this->check_execute_has_error();
481 +
482 + return $result;
483 + }
484 +
485 + /**
486 + * Check key postmeta exist on Database
487 + *
488 + * @param int $post_id
489 + * @param string $key
490 + *
491 + * @return bool|int
492 + */
493 + public function check_key_postmeta_exists( int $post_id = 0, string $key = '' ) {
494 + return $this->wpdb->query(
495 + $this->wpdb->prepare(
496 + "
497 + SELECT meta_id FROM $this->tb_postmeta
498 + WHERE meta_key = %s
499 + AND post_id = %d
500 + ",
501 + $key,
502 + $post_id
503 + )
504 + );
505 + }
506 +
507 + /**
508 + * Get total pages
509 + *
510 + * @param int $limit
511 + * @param int $total_rows
512 + *
513 + * @return int
514 + */
515 + public static function get_total_pages( int $limit = 0, int $total_rows = 0 ): int {
516 + if ( $limit == 0 ) {
517 + return 0;
518 + }
519 +
520 + $total_pages = (int) ceil( $total_rows / $limit );
521 +
522 + return (int) $total_pages;
523 + }
524 +
525 + /**
526 + * Get query string single row
527 + *
528 + * @param FilterBase $filter
529 + *
530 + * @since 4.2.5
531 + * @version 1.0.1
532 + */
533 + public function get_query_single_row( &$filter ) {
534 + $filter->limit = 1;
535 + $filter->return_string_query = true;
536 + $filter->run_query_count = false;
537 + }
538 +
539 + /**
540 + * Get result query
541 + *
542 + * @param FilterBase $filter
543 + * @param int $total_rows
544 + *
545 + * @return array|object|null|int|string
546 + * @throws Exception
547 + * @author tungnx
548 + * @version 1.0.2
549 + * @since 4.1.6
550 + */
551 + public function execute( $filter, int &$total_rows = 0 ) {
552 + $result = null;
553 +
554 + // Where
555 + $WHERE = array( 'WHERE 1=1' );
556 +
557 + // Fields select
558 + $FIELDS = '*';
559 + if ( ! empty( $filter->only_fields ) ) {
560 + $FIELDS = implode( ',', array_unique( $filter->only_fields ) );
561 + } elseif ( ! empty( $filter->fields ) ) {
562 + // exclude more fields
563 + if ( ! empty( $filter->exclude_fields ) ) {
564 + foreach ( $filter->exclude_fields as $field ) {
565 + $index_field = array_search( $field, $filter->fields );
566 + if ( $index_field ) {
567 + unset( $filter->fields[ $index_field ] );
568 + }
569 + }
570 + }
571 +
572 + foreach ( $filter->fields as $key => $field ) {
573 + if ( $field === 'order' ) {
574 + // Replace order with `order` to avoid conflict with SQL reserved word.
575 + $filter->fields[ $key ] = '`order`';
576 + break;
577 + }
578 + }
579 +
580 + $FIELDS = implode( ',', array_unique( $filter->fields ) );
581 + }
582 + $FIELDS = apply_filters( 'lp/query/fields', $FIELDS, $filter );
583 +
584 + $INNER_JOIN = array();
585 + $INNER_JOIN = array_merge( $INNER_JOIN, $filter->join );
586 + $INNER_JOIN = apply_filters( 'lp/query/inner_join', $INNER_JOIN, $filter );
587 + $INNER_JOIN = implode( ' ', array_unique( $INNER_JOIN ) );
588 +
589 + $WHERE = array_merge( $WHERE, $filter->where );
590 + $WHERE = apply_filters( 'lp/query/where', $WHERE, $filter );
591 + $WHERE = implode( ' ', array_unique( $WHERE ) );
592 +
593 + // Group by
594 + $GROUP_BY = '';
595 + if ( $filter->group_by ) {
596 + $GROUP_BY .= 'GROUP BY ' . $filter->group_by;
597 + $GROUP_BY = apply_filters( 'lp/query/group_by', $GROUP_BY, $filter );
598 + }
599 +
600 + // Order by
601 + $ORDER_BY = '';
602 + if ( $filter->order_by ) {
603 + $filter->order = strtoupper( $filter->order );
604 + if ( ! in_array( $filter->order, [ 'DESC', 'ASC' ] ) ) {
605 + $filter->order = 'DESC';
606 + }
607 +
608 + $ORDER_BY .= 'ORDER BY ' . $filter->order_by . ' ' . $filter->order . ' ';
609 + $ORDER_BY = apply_filters( 'lp/query/order_by', $ORDER_BY, $filter );
610 + }
611 +
612 + // Limit
613 + $LIMIT = '';
614 + if ( $filter->limit != - 1 ) {
615 + $filter->limit = absint( $filter->limit );
616 + /*if ( $filter->limit > $filter->max_limit ) {
617 + $filter->limit = $filter->max_limit;
618 + }*/
619 + $offset = $filter->limit * ( $filter->page - 1 );
620 + $LIMIT = $this->wpdb->prepare( 'LIMIT %d, %d', $offset, $filter->limit );
621 + }
622 +
623 + // For nest query
624 + if ( $filter->return_string_query ) {
625 + $LIMIT = '';
626 + }
627 +
628 + // From table or group select
629 + $COLLECTION = '';
630 + if ( ! empty( $filter->collection ) ) {
631 + $COLLECTION = $filter->collection;
632 + }
633 +
634 + // Alias table
635 + $ALIAS_COLLECTION = 'X';
636 + if ( ! empty( $filter->collection_alias ) ) {
637 + $ALIAS_COLLECTION = $filter->collection_alias;
638 + }
639 +
640 + // Query
641 + $query = "SELECT $FIELDS FROM $COLLECTION AS $ALIAS_COLLECTION
642 + $INNER_JOIN
643 + $WHERE
644 + $GROUP_BY
645 + $ORDER_BY
646 + $LIMIT
647 + ";
648 +
649 + if ( $filter->return_string_query ) {
650 + return $query;
651 + } elseif ( ! empty( $filter->union ) ) {
652 + $query = implode( ' UNION ', array_unique( $filter->union ) );
653 + $query .= $GROUP_BY;
654 + $query .= $ORDER_BY;
655 + $query .= $LIMIT;
656 + }
657 +
658 + if ( ! $filter->query_count ) {
659 + // Debug string query
660 + if ( $filter->debug_string_query ) {
661 + return $query;
662 + }
663 +
664 + $result = $this->wpdb->get_results( $query );
665 + }
666 +
667 + // Query total rows
668 + if ( $filter->run_query_count ) {
669 + $query = str_replace( array( $LIMIT, $ORDER_BY ), '', $query );
670 + $query_total = "SELECT COUNT($filter->field_count) FROM ($query) AS $ALIAS_COLLECTION";
671 + $total_rows = (int) $this->wpdb->get_var( $query_total );
672 +
673 + $this->check_execute_has_error();
674 +
675 + if ( $filter->query_count ) {
676 + // Debug string query
677 + if ( $filter->debug_string_query ) {
678 + return $query_total;
679 + }
680 +
681 + return $total_rows;
682 + }
683 + }
684 +
685 + $this->check_execute_has_error();
686 +
687 + return $result;
688 + }
689 +
690 + /**
691 + * Query update
692 + *
693 + * @param FilterBase $filter
694 + *
695 + * @throws Exception
696 + * @since 4.1.7
697 + * @version 1.0.1
698 + */
699 + public function update_execute( $filter ) {
700 +
701 + $COLLECTION = $filter->collection;
702 +
703 + // SET value
704 + $SET = apply_filters( 'lp/query/update/set', $filter->set, $filter );
705 + $SET = implode( ',', array_unique( $SET ) );
706 +
707 + // Where
708 + $WHERE = array( 'WHERE 1=1' );
709 + $WHERE = array_merge( $WHERE, $filter->where );
710 + $WHERE = apply_filters( 'lp/query/update/where', $WHERE, $filter );
711 + $WHERE = implode( ' ', array_unique( $WHERE ) );
712 +
713 + $query = "
714 + UPDATE $COLLECTION
715 + SET $SET
716 + $WHERE
717 + ";
718 +
719 + $result = $this->wpdb->query( $query );
720 +
721 + $this->check_execute_has_error();
722 +
723 + return $result;
724 + }
725 +
726 + /**
727 + * Query delete
728 + *
729 + * @param FilterBase $filter
730 + * @param string $table
731 + *
732 + * @return bool|int|\mysqli_result|string|null
733 + * @throws Exception
734 + * @since 4.1.7
735 + * @version 1.0.1
736 + */
737 + public function delete_execute( $filter, string $table = '' ) {
738 + $COLLECTION = $filter->collection;
739 +
740 + // Where
741 + $WHERE = array( 'WHERE 1=1' );
742 + $WHERE = array_merge( $WHERE, $filter->where );
743 + $WHERE = apply_filters( 'lp/query/delete/where', $WHERE, $filter );
744 + $WHERE = implode( ' ', array_unique( $WHERE ) );
745 +
746 + // Join
747 + $INNER_JOIN = array();
748 + $INNER_JOIN = array_merge( $INNER_JOIN, $filter->join );
749 + $INNER_JOIN = apply_filters( 'lp/query/delete/inner_join', $INNER_JOIN, $filter );
750 + $INNER_JOIN = implode( ' ', array_unique( $INNER_JOIN ) );
751 +
752 + $query = "
753 + DELETE $table FROM $COLLECTION
754 + $INNER_JOIN
755 + $WHERE
756 + ";
757 +
758 + if ( $filter->return_string_query ) {
759 + return $query;
760 + }
761 +
762 + $result = $this->wpdb->query( $query );
763 +
764 + $this->check_execute_has_error();
765 +
766 + return $result;
767 + }
768 +
769 + /**
770 + * Get values of list object by key
771 + *
772 + * @param array $arr_object
773 + * @param string $key
774 + *
775 + * @return array
776 + */
777 + public static function get_values_by_key( array $arr_object, string $key = 'ID' ): array {
778 + $arr_object_ids = array();
779 + foreach ( $arr_object as $object ) {
780 + $arr_object_ids[] = $object->{$key};
781 + }
782 +
783 + return $arr_object_ids;
784 + }
785 +
786 + /**
787 + * Insert data
788 + *
789 + * @param array $args [ 'data' => [], 'filter' => FilterBase, 'table_name' => '', 'key_auto_increment' => '' ]
790 + *
791 + * @return int
792 + * @throws Exception
793 + * @version 1.0.1
794 + * @since 4.2.9
795 + */
796 + public function insert_data( array $args ): int {
797 + $data = $args['data'] ?? [];
798 + $filter = $args['filter'] ?? null;
799 + $table_name = $args['table_name'] ?? '';
800 + $key_auto_increment = $args['key_auto_increment'] ?? '';
801 +
802 + if ( empty( $data ) || ! is_array( $data ) ) {
803 + throw new Exception( __( 'Data must be an array!', 'learnpress' ) . ' | ' . __FUNCTION__ );
804 + }
805 +
806 + /*if ( ! $filter instanceof FilterBase ) {
807 + throw new Exception( __( 'Invalid filter!', 'learnpress' ) . ' | ' . __FUNCTION__ );
808 + }*/
809 +
810 + if ( empty( $filter->all_fields ) ) {
811 + throw new Exception( __( 'Filter must have property all_fields!', 'learnpress' ) . ' | ' . __FUNCTION__ );
812 + }
813 +
814 + if ( empty( $table_name ) ) {
815 + throw new Exception( __( 'Table name is required!', 'learnpress' ) . ' | ' . __FUNCTION__ );
816 + }
817 +
818 + if ( empty( $key_auto_increment ) || ! is_string( $key_auto_increment ) ) {
819 + throw new Exception( __( 'Key auto increment must be a string!', 'learnpress' ) . ' | ' . __FUNCTION__ );
820 + }
821 +
822 + foreach ( $data as $col_name => $value ) {
823 + if ( ! in_array( $col_name, $filter->all_fields ) ) {
824 + unset( $data[ $col_name ] );
825 + }
826 + }
827 +
828 + // unset key is auto increment.
829 + unset( $data[ $key_auto_increment ] );
830 +
831 + $this->wpdb->insert( $table_name, $data );
832 +
833 + $this->check_execute_has_error();
834 +
835 + return $this->wpdb->insert_id;
836 + }
837 +
838 + /**
839 + * Update data
840 + *
841 + * @param array $args
842 + *
843 + * @return bool
844 + *
845 + * @throws Exception
846 + * @since 4.2.9
847 + * @version 1.0.2
848 + */
849 + public function update_data( array $args ): bool {
850 + $data = $args['data'] ?? [];
851 + $filter = $args['filter'] ?? null;
852 + $table_name = $args['table_name'] ?? '';
853 + $where_key = $args['where_key'] ?? '';
854 +
855 + /*if ( ! $filter instanceof FilterBase ) {
856 + throw new Exception( __( 'Invalid filter!', 'learnpress' ) . ' | ' . __FUNCTION__ );
857 + }*/
858 +
859 + if ( empty( $filter->all_fields ) ) {
860 + throw new Exception( __( 'Filter must have property all_fields!', 'learnpress' ) . ' | ' . __FUNCTION__ );
861 + }
862 +
863 + if ( empty( $data ) || ! is_array( $data ) ) {
864 + throw new Exception( __( 'Data must be an array!', 'learnpress' ) . ' | ' . __FUNCTION__ );
865 + }
866 +
867 + if ( empty( $where_key ) ) {
868 + throw new Exception( __( 'Invalid where key!', 'learnpress' ) . ' | ' . __FUNCTION__ );
869 + }
870 +
871 + if ( empty( $table_name ) ) {
872 + throw new Exception( __( 'Table name is required!', 'learnpress' ) . ' | ' . __FUNCTION__ );
873 + }
874 +
875 + $filter->collection = $table_name;
876 + foreach ( $data as $col_name => $value ) {
877 + if ( ! in_array( $col_name, $filter->all_fields ) ) {
878 + continue;
879 + }
880 +
881 + // Key `order` is reserved keyword in MySQL
882 + if ( $col_name === 'order' ) {
883 + $col_name = '`order`';
884 + }
885 +
886 + if ( is_null( $value ) ) {
887 + $filter->set[] = $col_name . ' = null';
888 + } else {
889 + $filter->set[] = $this->wpdb->prepare( $col_name . ' = %s', $value );
890 + }
891 + }
892 +
893 + $filter->where[] = $this->wpdb->prepare( "AND $where_key = %d", $data[ $where_key ] );
894 + $this->update_execute( $filter );
895 +
896 + return true;
897 + }
898 +}