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