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-user-items-db.php +938 -938 4.3.94.4.8 View file →
@@ -1,938 +1,938 @@
1 -<?php
2 -
3 -use LearnPress\Filters\UserItemsFilter;
4 -use LearnPress\Models\CourseModel;
5 -use LearnPress\Models\UserItems\UserItemModel;
6 -
7 -if ( ! defined( 'ABSPATH' ) ) {
8 - exit; // Exit if accessed directly
9 -}
10 -
11 -/**
12 - * Class LP_User_Items_DB
13 - *
14 - * @since 3.2.8.6
15 - * @version 1.0.5
16 - * @author tungnx
17 - */
18 -class LP_User_Items_DB extends LP_Database {
19 -
20 - private static $_instance;
21 - public static $user_item_id_col = 'learnpress_user_item_id';
22 - public static $extra_value_col = 'extra_value';
23 -
24 - protected function __construct() {
25 - parent::__construct();
26 - }
27 -
28 - public static function getInstance() {
29 - if ( is_null( self::$_instance ) ) {
30 - self::$_instance = new self();
31 - }
32 -
33 - return self::$_instance;
34 - }
35 -
36 - /**
37 - * Insert data
38 - *
39 - * @param array $data [ user_id, item_id, start_time, end_time, item_type, status, graduation, ref_id, ref_type, parent_id ]
40 - *
41 - * @return int
42 - * @throws Exception
43 - * @version 1.0.1
44 - * @since 4.2.5
45 - */
46 - public function insert_data( array $data ): int {
47 - $filter = new LP_User_Items_Filter();
48 - foreach ( $data as $col_name => $value ) {
49 - if ( ! in_array( $col_name, $filter->all_fields ) ) {
50 - unset( $data[ $col_name ] );
51 - continue;
52 - }
53 -
54 - if ( in_array( $col_name, [ 'start_time', 'end_time' ] ) && empty( $value ) ) {
55 - unset( $data[ $col_name ] );
56 - }
57 - }
58 -
59 - // Remove user_item_id (if exists) to insert new row, because user_item_id is auto increment.
60 - unset( $data['user_item_id'] );
61 -
62 - $this->wpdb->insert( $this->tb_lp_user_items, $data );
63 -
64 - $this->check_execute_has_error();
65 -
66 - return $this->wpdb->insert_id;
67 - }
68 -
69 - /**
70 - * Update data
71 - *
72 - * @param array $data [ 'user_item_id', user_id, item_id, start_time, end_time, item_type, status, graduation, ref_id, ref_type, parent_id ]
73 - * @return bool
74 - *
75 - * @throws Exception
76 - * @since 4.2.5
77 - * @version 1.0.0
78 - */
79 - public function update_data( array $data ): bool {
80 - if ( empty( $data['user_item_id'] ) ) {
81 - throw new Exception( __( 'Invalid user item id!', 'learnpress' ) . ' | ' . __FUNCTION__ );
82 - }
83 -
84 - $filter = new LP_User_Items_Filter();
85 - $filter->collection = $this->tb_lp_user_items;
86 - foreach ( $data as $col_name => $value ) {
87 - if ( ! in_array( $col_name, $filter->all_fields ) ) {
88 - continue;
89 - }
90 -
91 - if ( is_null( $value ) ) {
92 - $filter->set[] = $col_name . ' = null';
93 - } else {
94 - $filter->set[] = $this->wpdb->prepare( $col_name . ' = %s', $value );
95 - }
96 - }
97 - $filter->where[] = $this->wpdb->prepare( 'AND user_item_id = %d', $data['user_item_id'] );
98 - $this->update_execute( $filter );
99 -
100 - return true;
101 - }
102 -
103 - /**
104 - * Get users items
105 - *
106 - * @param LP_User_Items_Filter|UserItemsFilter $filter
107 - *
108 - * @return array|null|int|string
109 - * @throws Exception
110 - * @since 4.1.6.9
111 - * @version 1.0.5
112 - */
113 - public function get_user_items( $filter, int &$total_rows = 0 ) {
114 - $filter->fields = array_merge( $filter->all_fields, $filter->fields );
115 -
116 - if ( empty( $filter->collection ) ) {
117 - $filter->collection = $this->tb_lp_user_items;
118 - }
119 -
120 - if ( empty( $filter->collection_alias ) ) {
121 - $filter->collection_alias = 'ui';
122 - }
123 -
124 - if ( ! empty( $filter->ref_id ) ) {
125 - $filter->where[] = $this->wpdb->prepare( 'AND ui.ref_id = %d', $filter->ref_id );
126 - }
127 -
128 - if ( ! empty( $filter->ref_type ) ) {
129 - $filter->where[] = $this->wpdb->prepare( 'AND ui.ref_type = %s', $filter->ref_type );
130 - }
131 -
132 - if ( ! empty( $filter->user_item_id ) ) {
133 - $filter->where[] = $this->wpdb->prepare( 'AND ui.user_item_id = %d', $filter->user_item_id );
134 - }
135 -
136 - // Get by user_item_ids
137 - if ( ! empty( $filter->user_item_ids ) ) {
138 - $user_item_ids_format = LP_Helper::db_format_array( $filter->user_item_ids );
139 - $filter->where[] = $this->wpdb->prepare( 'AND ui.user_item_id IN (' . $user_item_ids_format . ')', $filter->user_item_ids );
140 - }
141 -
142 - if ( $filter->user_id !== false ) {
143 - $filter->where[] = $this->wpdb->prepare( 'AND ui.user_id = %d', $filter->user_id );
144 - }
145 -
146 - if ( ! empty( $filter->item_type ) ) {
147 - $filter->where[] = $this->wpdb->prepare( 'AND ui.item_type = %s', $filter->item_type );
148 - }
149 -
150 - if ( ! empty( $filter->item_ids ) ) {
151 - $item_ids_format = LP_Helper::db_format_array( $filter->item_ids, '%d' );
152 - $filter->where[] = $this->wpdb->prepare( 'AND ui.item_id IN (' . $item_ids_format . ')', $filter->item_ids );
153 - }
154 -
155 - if ( ! empty( $filter->item_id ) ) {
156 - $filter->where[] = $this->wpdb->prepare( 'AND ui.item_id = %s', $filter->item_id );
157 - }
158 -
159 - if ( ! empty( $filter->status ) ) {
160 - $filter->where[] = $this->wpdb->prepare( 'AND ui.status = %s', $filter->status );
161 - }
162 -
163 - if ( ! empty( $filter->graduation ) ) {
164 - $filter->where[] = $this->wpdb->prepare( 'AND ui.graduation = %s', $filter->graduation );
165 - }
166 -
167 - if ( ! empty( $filter->parent_id ) ) {
168 - $filter->where[] = $this->wpdb->prepare( 'AND ui.parent_id = %s', $filter->parent_id );
169 - }
170 -
171 - $filter = apply_filters( 'lp/user_items/query/filter', $filter );
172 -
173 - return $this->execute( $filter, $total_rows );
174 - }
175 -
176 - /**
177 - * Get items by user_item_id | this is id where item_id = course_id
178 - *
179 - * @param LP_User_Items_Filter|UserItemsFilter $filter
180 - * @param bool $force_cache
181 - *
182 - * @return object
183 - * @throws Exception
184 - * Todo: tungnx need set paginate - apply when do load API
185 - */
186 - public function get_user_course_items( $filter, bool $force_cache = false ) {
187 - $key_first_cache = 'course_items/' . $filter->user_id . '/' . $filter->parent_id;
188 - $course_items_cache = LP_Cache::cache_load_first( 'get', $key_first_cache );
189 - if ( false !== $course_items_cache && ! $force_cache ) {
190 - return $course_items_cache;
191 - }
192 -
193 - $query = $this->wpdb->prepare(
194 - "SELECT * FROM $this->tb_lp_user_items
195 - WHERE parent_id = %d
196 - AND ref_type = %s
197 - AND user_id = %d
198 - ",
199 - $filter->parent_id,
200 - LP_COURSE_CPT,
201 - $filter->user_id
202 - );
203 -
204 - $course_items = $this->wpdb->get_results( $query );
205 -
206 - $this->check_execute_has_error();
207 -
208 - LP_Cache::cache_load_first( 'set', $key_first_cache, $course_items );
209 -
210 - return $course_items;
211 - }
212 -
213 - /**
214 - * Remove items' of course and user learned
215 - *
216 - * @param LP_User_Items_Filter|UserItemsFilter $filter .
217 - *
218 - * @return bool|int
219 - * @throws Exception .
220 - * @TODO tungnx - recheck this function
221 - */
222 - public function remove_items_of_user_course( $filter ) {
223 - $query_extra = '';
224 -
225 - // Check valid user.
226 - if ( ! is_user_logged_in() || ( ! current_user_can( ADMIN_ROLE ) && get_current_user_id() != $filter->user_id ) ) {
227 - throw new Exception( __( 'Invalid user!', 'learnpress' ) . ' | ' . __FUNCTION__ );
228 - }
229 -
230 - if ( - 1 < $filter->limit ) {
231 - $query_extra .= " LIMIT $filter->limit";
232 - }
233 -
234 - $query = $this->wpdb->prepare(
235 - "DELETE FROM {$this->tb_lp_user_items}
236 - WHERE parent_id = %d
237 - $query_extra;
238 - ",
239 - $filter->parent_id
240 - );
241 -
242 - return $this->wpdb->query( $query );
243 - }
244 -
245 - /*public function get_item_status( $item_id, $course_id ) {
246 - $query = $this->wpdb->prepare(
247 - "
248 - SELECT status FROM {$this->tb_lp_user_items}
249 - WHERE ref_id = %d
250 - AND ref_type = %s
251 - AND item_id = %d
252 - ",
253 - $course_id,
254 - 'lp_course',
255 - $item_id
256 - );
257 -
258 - return $this->wpdb->get_var( $query );
259 - }*/
260 -
261 - /**
262 - * Insert/Update extra value
263 - *
264 - * @param int $user_item_id
265 - * @param string $meta_key
266 - * @param string $value
267 - * @since 4.0.0
268 - * @version 1.0.0
269 - * @author tungnx
270 - *
271 - * @return int|false The number of rows inserted|updated, or false on error.
272 - */
273 - public function update_extra_value( $user_item_id = 0, $meta_key = '', $value = '' ) {
274 - $result = false;
275 -
276 - $data = array(
277 - 'learnpress_user_item_id' => $user_item_id,
278 - 'meta_key' => $meta_key,
279 - 'extra_value' => $value,
280 - );
281 - $format = array( '%d', '%s', '%s' );
282 -
283 - $check_exist_data = $this->wpdb->get_var(
284 - $this->wpdb->prepare(
285 - "
286 - SELECT meta_id FROM $this->tb_lp_user_itemmeta
287 - WHERE " . self::$user_item_id_col . ' = %d
288 - AND meta_key = %s
289 - ',
290 - $user_item_id,
291 - $meta_key
292 - )
293 - );
294 -
295 - if ( $check_exist_data ) {
296 - $result = $this->wpdb->update(
297 - $this->tb_lp_user_itemmeta,
298 - $data,
299 - array(
300 - self::$user_item_id_col => $user_item_id,
301 - 'meta_key' => $meta_key,
302 - ),
303 - $format
304 - );
305 - } else {
306 - $result = $this->wpdb->insert( $this->tb_lp_user_itemmeta, $data, $format );
307 - }
308 -
309 - return $result;
310 - }
311 -
312 - /**
313 - * Get extra value
314 - *
315 - * @param int $user_item_id
316 - * @param string $meta_key
317 - */
318 - public function get_extra_value( $user_item_id = 0, $meta_key = '' ) {
319 - return $this->wpdb->get_var(
320 - $this->wpdb->prepare(
321 - '
322 - SELECT ' . self::$extra_value_col . " FROM $this->tb_lp_user_itemmeta
323 - WHERE " . self::$user_item_id_col . ' = %d
324 - AND meta_key = %s
325 - ',
326 - $user_item_id,
327 - $meta_key
328 - )
329 - );
330 - }
331 -
332 - /**
333 - * Re-set current item
334 - * @param $course_id
335 - * @param $item_id
336 - * @editor hungkv
337 - */
338 - public function reset_course_current_item( $course_id, $item_id ) {
339 - // Select all course enrolled
340 - $query = $this->wpdb->prepare(
341 - "
342 - SELECT user_item_id
343 - FROM {$this->wpdb->prefix}learnpress_user_items
344 - WHERE status = %s AND item_id = %d AND graduation = %s
345 - ",
346 - 'enrolled',
347 - $course_id,
348 - 'in-progress'
349 - );
350 - $user_item_ids = $this->wpdb->get_col( $query );
351 - if ( ! empty( $user_item_ids ) ) {
352 - foreach ( $user_item_ids as $user_item_id ) {
353 - // Check item is current item of all course
354 - $query = $this->wpdb->prepare(
355 - "
356 - SELECT meta_value
357 - FROM {$this->wpdb->prefix}learnpress_user_itemmeta
358 - WHERE learnpress_user_item_id = %d
359 - ",
360 - $user_item_id
361 - );
362 - $meta_value_id = $this->wpdb->get_var( $query );
363 - // Check if the deleted item is current item or not
364 - if ( $meta_value_id == $item_id ) {
365 - $course = learn_press_get_course( $course_id );
366 - // update _curent_item to database
367 - learn_press_update_user_item_meta( $user_item_id, '_current_item', $course->get_first_item_id() );
368 - }
369 - }
370 - }
371 - }
372 -
373 - /**
374 - * Get number status by status, graduation...
375 - *
376 - * @param LP_User_Items_Filter|UserItemsFilter $filter {user_id, item_type}
377 - *
378 - * @author tungnx
379 - * @since 4.1.5
380 - * @version 1.0.2
381 - * @return object|null
382 - * @throws Exception
383 - */
384 - public function count_status_by_items( $filter ) {
385 - $filter->only_fields[] = $this->wpdb->prepare( 'SUM(ui.graduation = %s) AS %s', LP_COURSE_GRADUATION_IN_PROGRESS, LP_COURSE_GRADUATION_IN_PROGRESS );
386 - $filter->only_fields[] = $this->wpdb->prepare( 'SUM(ui.graduation = %s) AS %s', LP_COURSE_GRADUATION_FAILED, LP_COURSE_GRADUATION_FAILED );
387 - $filter->only_fields[] = $this->wpdb->prepare( 'SUM(ui.graduation = %s) AS %s', LP_COURSE_GRADUATION_PASSED, LP_COURSE_GRADUATION_PASSED );
388 - $filter->only_fields[] = $this->wpdb->prepare( 'SUM(ui.status = %s) AS %s', LP_COURSE_ENROLLED, LP_COURSE_ENROLLED );
389 - $filter->only_fields[] = $this->wpdb->prepare( 'SUM(ui.status = %s) AS %s', LP_COURSE_PURCHASED, LP_COURSE_PURCHASED );
390 - $filter->only_fields[] = $this->wpdb->prepare( 'SUM(ui.status = %s) AS %s', LP_COURSE_FINISHED, LP_COURSE_FINISHED );
391 -
392 - if ( $filter->user_id ) {
393 - $filter_user_attend_courses = new LP_User_Items_Filter();
394 - $filter_user_attend_courses->only_fields = array( 'MAX(ui.user_item_id) AS user_item_id' );
395 - $filter_user_attend_courses->where[] = $this->wpdb->prepare( 'AND ui.user_id = %s', $filter->user_id );
396 - $filter_user_attend_courses->where[] = $this->wpdb->prepare( 'AND ui.status != %s', UserItemModel::STATUS_CANCEL );
397 - $filter_user_attend_courses->group_by = 'ui.item_id';
398 - $filter_user_attend_courses->return_string_query = true;
399 - $query_get_course_attend = $this->get_user_courses( $filter_user_attend_courses );
400 - $filter->where[] = 'AND ui.user_item_id IN (' . $query_get_course_attend . ')';
401 - }
402 -
403 - $filter->return_string_query = true;
404 -
405 - $filter = apply_filters( 'lp/user/course/query/count-status', $filter );
406 -
407 - $query = $this->get_user_courses( $filter );
408 -
409 - $this->check_execute_has_error();
410 -
411 - return $this->wpdb->get_row( $query );
412 - }
413 -
414 - /**
415 - * Get the newest item is course of user
416 - *
417 - * @param LP_User_Items_Filter|UserItemsFilter $filter {course_id, user_id}
418 - * @param bool $force_cache Reset first cache
419 - *
420 - * @return null|object
421 - * @throws Exception
422 - */
423 - public function get_last_user_course( $filter, bool $force_cache = false ) {
424 - $query = $this->wpdb->prepare(
425 - "SELECT user_item_id, user_id, item_id, item_type, status, graduation, ref_id, ref_type, start_time, end_time
426 - FROM $this->tb_lp_user_items
427 - WHERE item_type = %s
428 - AND item_id = %d
429 - AND user_id = %d
430 - ORDER BY user_item_id DESC
431 - LIMIT 1
432 - ",
433 - LP_COURSE_CPT,
434 - $filter->item_id,
435 - $filter->user_id
436 - );
437 -
438 - $result = $this->wpdb->get_row( $query );
439 -
440 - $this->check_execute_has_error();
441 -
442 - return $result;
443 - }
444 -
445 - /**
446 - * Get item of user and course
447 - *
448 - * @param LP_User_Items_Filter|UserItemsFilter $filter {parent_id, item_id, user_id}
449 - * @param bool $force_cache Reset first cache
450 - *
451 - * @return null|object
452 - * @throws Exception
453 - */
454 - public function get_user_course_item( $filter, bool $force_cache = false ) {
455 - $key_load_first = 'user_course_item/' . $filter->user_id . '/' . $filter->item_id;
456 - $user_course = LP_Cache::cache_load_first( 'get', $key_load_first );
457 -
458 - if ( false !== $user_course && ! $force_cache ) {
459 - return $user_course;
460 - }
461 -
462 - $WHERE = 'WHERE 1=1 ';
463 -
464 - if ( $filter->parent_id ) {
465 - $WHERE .= $this->wpdb->prepare( 'AND parent_id = %d ', $filter->parent_id );
466 - }
467 -
468 - if ( $filter->ref_id ) {
469 - $WHERE .= $this->wpdb->prepare( 'AND ref_id = %d ', $filter->ref_id );
470 - }
471 -
472 - if ( $filter->ref_type ) {
473 - $WHERE .= $this->wpdb->prepare( 'AND ref_type = %s ', $filter->ref_type );
474 - }
475 -
476 - if ( $filter->item_type ) {
477 - $WHERE .= $this->wpdb->prepare( 'AND item_type = %s ', $filter->item_type );
478 - }
479 -
480 - $query = $this->wpdb->prepare(
481 - "SELECT user_item_id, user_id, item_id, item_type, status, graduation, ref_id, ref_type, start_time, end_time, parent_id
482 - FROM $this->tb_lp_user_items
483 - $WHERE
484 - AND item_id = %d
485 - AND user_id = %d
486 - ORDER BY user_item_id DESC
487 - LIMIT 1
488 - ",
489 - $filter->item_id,
490 - $filter->user_id
491 - );
492 -
493 - $result = $this->wpdb->get_row( $query );
494 -
495 - $this->check_execute_has_error();
496 -
497 - LP_Cache::cache_load_first( 'set', $key_load_first, $result );
498 -
499 - return $result;
500 - }
501 -
502 - /**
503 - * Get items of course by item type
504 - *
505 - * @param LP_User_Items_Filter|UserItemsFilter $filter {$filter->parent_id, $filter->item_type, [$filter->item_id]}
506 - * @throws Exception
507 - */
508 - public function get_user_course_items_by_item_type( $filter ) {
509 -
510 - $AND = '';
511 -
512 - if ( $filter->item_type ) {
513 - $AND .= $this->wpdb->prepare( ' AND item_type = %s', $filter->item_type );
514 - }
515 -
516 - if ( $filter->item_id ) {
517 - $AND .= $this->wpdb->prepare( ' AND item_id = %d', $filter->item_id );
518 - }
519 -
520 - $query = $this->wpdb->prepare(
521 - "SELECT user_item_id, user_id, item_id, item_type, status, graduation, ref_id, ref_type, start_time, end_time, parent_id
522 - FROM $this->tb_lp_user_items
523 - WHERE parent_id = %d
524 - $AND
525 - ",
526 - $filter->parent_id
527 - );
528 -
529 - $result = $this->wpdb->{$filter->query_type}( $query );
530 -
531 - $this->check_execute_has_error();
532 -
533 - return $result;
534 - }
535 -
536 - /**
537 - * Get user_item_id by course_id
538 - *
539 - * @param LP_User_Items_Filter|UserItemsFilter $filter $filter->item_id
540 - *
541 - * @return array
542 - */
543 - public function get_user_items_by_course( $filter ): array {
544 - try {
545 - // Check valid user.
546 - if ( ! is_user_logged_in() ) {
547 - throw new Exception( __( 'Invalid user!', 'learnpress' ) . ' | ' . __FUNCTION__ );
548 - }
549 -
550 - $query = $this->wpdb->prepare(
551 - "SELECT user_item_id FROM $this->tb_lp_user_items
552 - WHERE item_id = %d
553 - AND item_type = %s
554 - ",
555 - $filter->item_id,
556 - LP_COURSE_CPT
557 - );
558 -
559 - return $this->wpdb->get_col( $query );
560 - } catch ( Throwable $e ) {
561 - error_log( __FUNCTION__ . ':' . $e->getMessage() );
562 - return array();
563 - }
564 - }
565 -
566 - /**
567 - * Get items of course has user
568 - *
569 - * @param LP_User_Items_Filter|UserItemsFilter $filter user_item_ids
570 - *
571 - * @throws Exception
572 - * @since 4.1.4
573 - * @version 1.0.0
574 - */
575 - public function get_item_ids_of_user_course( $filter ): array {
576 - if ( empty( $filter->user_item_ids ) ) {
577 - return [];
578 - }
579 -
580 - $where = 'WHERE 1=1 ';
581 -
582 - $where .= $this->wpdb->prepare(
583 - 'AND parent_id IN(' . LP_Helper::db_format_array( $filter->user_item_ids, '%d' ) . ')',
584 - $filter->user_item_ids
585 - );
586 -
587 - return $this->wpdb->get_col(
588 - "SELECT user_item_id FROM {$this->tb_lp_user_items}
589 - {$where}
590 - "
591 - );
592 - }
593 -
594 - /**
595 - * Remove rows IN user_item_ids
596 - *
597 - * @param LP_User_Items_Filter|UserItemsFilter $filter $filter->user_item_ids, $filter->user_id
598 - *
599 - * @throws Exception
600 - * @since 4.1.4
601 - * @version 1.0.0
602 - */
603 - public function remove_user_item_ids( $filter ) {
604 - // Check valid user.
605 - /*if ( ! is_user_logged_in() || ( ! current_user_can( ADMIN_ROLE ) && get_current_user_id() != $filter->user_id ) ) {
606 - throw new Exception( __( 'User invalid!', 'learnpress' ) . ' | ' . __FUNCTION__ );
607 - }*/
608 -
609 - if ( empty( $filter->user_item_ids ) ) {
610 - return 1;
611 - }
612 -
613 - $where = 'WHERE 1=1 ';
614 -
615 - $where .= $this->wpdb->prepare(
616 - 'AND user_item_id IN(' . LP_Helper::db_format_array( $filter->user_item_ids, '%d' ) . ')',
617 - $filter->user_item_ids
618 - );
619 -
620 - return $this->wpdb->query(
621 - "DELETE FROM {$this->tb_lp_user_items}
622 - {$where}
623 - "
624 - );
625 - }
626 -
627 - /**
628 - * Remove user_itemmeta has list user_item_ids
629 - *
630 - * @param LP_User_Items_Filter|UserItemsFilter $filter $filter->user_item_ids, $filter->user_id
631 - *
632 - * @throws Exception
633 - * @since 4.1.4
634 - * @version 1.0.0
635 - */
636 - public function remove_user_itemmeta( $filter ) {
637 - // Check valid user.
638 - /*if ( ! is_user_logged_in() || ( ! current_user_can( ADMIN_ROLE ) && get_current_user_id() != $filter->user_id ) ) {
639 - throw new Exception( __( 'User invalid!', 'learnpress' ) . ' | ' . __FUNCTION__ );
640 - }*/
641 -
642 - if ( empty( $filter->user_item_ids ) ) {
643 - return 1;
644 - }
645 -
646 - $where = 'WHERE 1=1 ';
647 -
648 - $where .= $this->wpdb->prepare(
649 - 'AND learnpress_user_item_id IN(' . LP_Helper::db_format_array( $filter->user_item_ids, '%d' ) . ')',
650 - $filter->user_item_ids
651 - );
652 -
653 - return $this->wpdb->query(
654 - "DELETE FROM {$this->tb_lp_user_itemmeta}
655 - {$where}
656 - "
657 - );
658 - }
659 -
660 - /**
661 - * Delete user_item_ids by user_id and course_id
662 - *
663 - * @param int $user_id
664 - * @param int $course_id
665 - * @author tungnx
666 - * @since 4.1.4
667 - * @version 1.0.0
668 - */
669 - public function delete_user_items_old( int $user_id = 0, int $course_id = 0 ) {
670 - $lp_user_items_db = LP_User_Items_DB::getInstance();
671 - $lp_user_item_results = LP_User_Items_Result_DB::instance();
672 -
673 - try {
674 - // Check valid user.
675 - /*if ( ! is_user_logged_in() || ( ! current_user_can( ADMIN_ROLE ) && get_current_user_id() != $user_id ) ) {
676 - throw new Exception( __( 'User invalid!', 'learnpress' ) . ' | ' . __FUNCTION__ );
677 - }*/
678 -
679 - // Get all user_item_ids has user_id and course_id
680 - $filter = new LP_User_Items_Filter();
681 - $filter->user_id = $user_id;
682 - $filter->item_id = $course_id;
683 - $filter->item_type = LP_COURSE_CPT;
684 - $filter->only_fields = [ 'user_item_id' ];
685 - $filter->run_query_count = false;
686 - $filter->return_string_query = true;
687 - $user_course_ids_query = $lp_user_items_db->get_user_items( $filter );
688 - $user_course_ids = $this->wpdb->get_col( $user_course_ids_query );
689 - if ( empty( $user_course_ids ) ) {
690 - return;
691 - }
692 -
693 - $course = learn_press_get_course( $course_id );
694 - if ( ! $course ) {
695 - return;
696 - }
697 -
698 - $course->delete_user_item_and_result( $user_course_ids );
699 -
700 - // Clear cache total students enrolled of one course.
701 - $lp_course_cache = new LP_Course_Cache( true );
702 - $lp_course_cache->clean_total_students_enrolled( $course_id );
703 - $lp_course_cache->clean_total_students_enrolled_or_purchased( $course_id );
704 - // Clear cache count students many courses.
705 - $lp_courses_cache = new LP_Courses_Cache( true );
706 - $lp_courses_cache->clear_cache_on_group( LP_Courses_Cache::KEYS_COUNT_STUDENT_COURSES );
707 - // Clear cache user course.
708 - $lp_user_items_cache = new LP_User_Items_Cache();
709 - $lp_user_items_cache->clean_user_item(
710 - [
711 - $user_id,
712 - $course_id,
713 - LP_COURSE_CPT,
714 - ]
715 - );
716 - // Clear userCourseModel cache.
717 - $key_cache = "userCourseModel/find/{$user_id}/{$course_id}/" . LP_COURSE_CPT;
718 - $lpUserCourseCache = new LP_Cache();
719 - $lpUserCourseCache->clear( $key_cache );
720 -
721 - do_action( 'learn-press/user-item-old/delete', $user_id, $course_id );
722 - } catch ( Throwable $e ) {
723 - error_log( __FUNCTION__ . ': ' . $e->getMessage() );
724 - }
725 - }
726 -
727 - /**
728 - * Update user_id for lp_user_item with Order buy User Guest
729 - *
730 - * @param LP_User_Items_Filter|UserItemsFilter $filter
731 - *
732 - * @return bool|int
733 - * @throws Exception
734 - */
735 - public function update_user_id_by_order( $filter ) {
736 - // Check valid user.
737 - if ( ! is_user_logged_in() || ( ! current_user_can( ADMIN_ROLE ) && get_current_user_id() != $filter->user_id ) ) {
738 - throw new Exception( __FUNCTION__ . ': Invalid user!' );
739 - }
740 -
741 - $query = $this->wpdb->prepare(
742 - "UPDATE {$this->tb_lp_user_items}
743 - SET user_id = %d
744 - WHERE ref_type = %s
745 - AND ref_id = %d
746 - ",
747 - $filter->user_id,
748 - LP_ORDER_CPT,
749 - $filter->ref_id
750 - );
751 -
752 - return $this->wpdb->query( $query );
753 - }
754 -
755 - /**
756 - * Count items by type and total by status
757 - *
758 - * @param LP_User_Items_Filter|UserItemsFilter $filter {parent_id, status, graduation}
759 - *
760 - * @throws Exception
761 - *
762 - * @return null|object
763 - */
764 - public function count_items_of_course_with_status( $filter ) {
765 - $item_types = CourseModel::item_types_support();
766 - $count_item_types = count( $item_types );
767 - $i = 0;
768 -
769 - //$user_course = $this->get_last_user_course( $filter );
770 -
771 - $query_count = '';
772 - $query_count .= $this->wpdb->prepare( 'SUM(ui.status = %s) AS count_status,', $filter->status );
773 -
774 - foreach ( $item_types as $item_type ) {
775 - ++$i;
776 - $query_count .= $this->wpdb->prepare( 'SUM(ui.status = %s AND ui.item_type = %s) AS %s,', $filter->status, $item_type, $item_type . '_status_' . $filter->status );
777 - $query_count .= $this->wpdb->prepare( 'SUM(ui.graduation = %s AND ui.item_type = %s) AS %s', $filter->graduation, $item_type, $item_type . '_graduation_' . $filter->graduation );
778 -
779 - if ( $i < $count_item_types ) {
780 - $query_count .= ',';
781 - }
782 - }
783 -
784 - $query = $this->wpdb->prepare(
785 - 'SELECT ' . $query_count . ' FROM ' . $this->tb_lp_user_items . ' ui
786 - WHERE parent_id = %d
787 - ',
788 - $filter->parent_id
789 - );
790 -
791 - $total_items = $this->wpdb->get_row( $query );
792 -
793 - return $total_items;
794 - }
795 -
796 - /**
797 - * Get quizzes of user
798 - *
799 - * @param LP_User_Items_Filter|UserItemsFilter $filter
800 - * @param int $total_rows
801 - *
802 - * @return array|int|string|null
803 - * @throws Exception
804 - * @since 4.1.4.1
805 - * @version 1.0.2
806 - */
807 - public function get_user_quizzes( $filter, int &$total_rows = 0 ) {
808 - $filter->item_type = LP_QUIZ_CPT;
809 - $filter->ref_type = LP_COURSE_CPT;
810 -
811 - return $this->get_user_items( $filter, $total_rows );
812 - }
813 -
814 - /**
815 - * Get courses only by course's user are learning
816 - *
817 - * @param LP_User_Items_Filter|UserItemsFilter $filter
818 - * @param int $total_rows
819 - *
820 - * @author tungnx
821 - * @version 1.0.2
822 - * @since 4.1.5
823 - * @return null|array|string|int
824 - * @throws Exception
825 - */
826 - public function get_user_courses( $filter, int &$total_rows = 0 ) {
827 - $filter->collection_alias = 'ui';
828 -
829 - // Get courses publish, private
830 - $filter->join[] = "INNER JOIN {$this->tb_posts} AS p ON p.ID = $filter->collection_alias.item_id";
831 - $filter->where[] = $this->wpdb->prepare( 'AND ( p.post_status = %s OR p.post_status = %s )', 'publish', 'private' );
832 - $filter->item_type = LP_COURSE_CPT;
833 -
834 - $filter = apply_filters( 'lp/user/course/query/filter', $filter );
835 -
836 - return $this->get_user_items( $filter, $total_rows );
837 - }
838 -
839 - /**
840 - * Get total users attend courses of Author
841 - *
842 - * @param int $author_id
843 - *
844 - * @return LP_User_Items_Filter
845 - * @since 4.1.6
846 - * @version 1.0.1
847 - * @throws Exception
848 - */
849 - public function count_user_attend_courses_of_author( int $author_id ): LP_User_Items_Filter {
850 - $filter_course = new LP_Course_Filter();
851 - $filter_course->only_fields = array( 'ID' );
852 - $filter_course->post_author = $author_id;
853 - $filter_course->post_status = [ 'publish', 'private' ];
854 - $filter_course->return_string_query = true;
855 - $query_courses_str = LP_Course_DB::getInstance()->get_courses( $filter_course );
856 -
857 - $filter = new LP_User_Items_Filter();
858 - $filter->item_type = LP_COURSE_CPT;
859 - $filter->only_fields = array( 'ui.user_id' );
860 - $filter->field_count = 'ui.user_id';
861 - $filter->where[] = "AND item_id IN ({$query_courses_str})";
862 - $filter->query_count = true;
863 -
864 - return apply_filters( 'lp/user/course/query/filter/count-users-attend-courses-of-author', $filter );
865 - }
866 -
867 - /**
868 - * Get list students attend
869 - *
870 - * @param LP_User_Items_Filter|UserItemsFilter $filter
871 - * @param int $total_rows
872 - *
873 - * @return array|int|string|null
874 - * @since 4.1.6.9
875 - * @throws Exception
876 - */
877 - public function get_students( $filter, int &$total_rows = 0 ) {
878 - $default_fields = $this->get_cols_of_table( $this->tb_users );
879 - $filter->fields = array_merge( $default_fields, $filter->fields );
880 - $filter->exclude_fields = [ 'user_pass', 'user_login', 'user_status', 'user_activation_key' ];
881 - $filter->field_count = 'ID';
882 -
883 - if ( empty( $filter->collection ) ) {
884 - $filter->collection = $this->tb_users;
885 - }
886 -
887 - if ( empty( $filter->collection_alias ) ) {
888 - $filter->collection_alias = 'u';
889 - }
890 -
891 - // Filter
892 - $filter->join[] = "INNER JOIN $this->tb_lp_user_items AS ui ON u.ID = ui.user_id";
893 - $filter->where[] = $this->wpdb->prepare( 'AND item_type =%s', LP_COURSE_CPT );
894 -
895 - // Filter by user ids
896 - if ( ! empty( $filter->user_ids ) ) {
897 - $term_ids_format = LP_Helper::db_format_array( $filter->user_ids, '%d' );
898 - $filter->where[] = $this->wpdb->prepare( 'AND r_term.term_taxonomy_id IN (' . $term_ids_format . ')', $filter->user_ids );
899 - }
900 -
901 - // Filter
902 -
903 - $filter->group_by = 'ID';
904 -
905 - // End filter
906 -
907 - $filter = apply_filters( 'lp/course/query/students', $filter );
908 -
909 - return $this->execute( $filter, $total_rows );
910 - }
911 -
912 - /**
913 - * Count students on category course.
914 - *
915 - * @param LP_User_Items_Filter|UserItemsFilter $filter
916 - * @return int
917 - * @since 4.2.5.4
918 - * @version 1.0.0
919 - */
920 - public function count_students( $filter ): int {
921 - $count = 0;
922 -
923 - try {
924 - $filter->query_count = true;
925 - $filter->only_fields = [ 'ui.user_id' ];
926 - $filter->field_count = 'ui.user_id';
927 - $filter->item_type = LP_COURSE_CPT;
928 - $filter->where[] = 'AND ui.user_id != 0';
929 - $this->get_user_items( $filter, $count );
930 - } catch ( Throwable $e ) {
931 - error_log( __METHOD__ . ': ' . $e->getMessage() );
932 - }
933 -
934 - return $count;
935 - }
936 -}
937 -
938 -LP_Course_DB::getInstance();
1 +<?php
2 +
3 +use LearnPress\Filters\UserItemsFilter;
4 +use LearnPress\Models\CourseModel;
5 +use LearnPress\Models\UserItems\UserItemModel;
6 +
7 +if ( ! defined( 'ABSPATH' ) ) {
8 + exit; // Exit if accessed directly
9 +}
10 +
11 +/**
12 + * Class LP_User_Items_DB
13 + *
14 + * @since 3.2.8.6
15 + * @version 1.0.5
16 + * @author tungnx
17 + */
18 +class LP_User_Items_DB extends LP_Database {
19 +
20 + private static $_instance;
21 + public static $user_item_id_col = 'learnpress_user_item_id';
22 + public static $extra_value_col = 'extra_value';
23 +
24 + protected function __construct() {
25 + parent::__construct();
26 + }
27 +
28 + public static function getInstance() {
29 + if ( is_null( self::$_instance ) ) {
30 + self::$_instance = new self();
31 + }
32 +
33 + return self::$_instance;
34 + }
35 +
36 + /**
37 + * Insert data
38 + *
39 + * @param array $data [ user_id, item_id, start_time, end_time, item_type, status, graduation, ref_id, ref_type, parent_id ]
40 + *
41 + * @return int
42 + * @throws Exception
43 + * @version 1.0.1
44 + * @since 4.2.5
45 + */
46 + public function insert_data( array $data ): int {
47 + $filter = new LP_User_Items_Filter();
48 + foreach ( $data as $col_name => $value ) {
49 + if ( ! in_array( $col_name, $filter->all_fields ) ) {
50 + unset( $data[ $col_name ] );
51 + continue;
52 + }
53 +
54 + if ( in_array( $col_name, [ 'start_time', 'end_time' ] ) && empty( $value ) ) {
55 + unset( $data[ $col_name ] );
56 + }
57 + }
58 +
59 + // Remove user_item_id (if exists) to insert new row, because user_item_id is auto increment.
60 + unset( $data['user_item_id'] );
61 +
62 + $this->wpdb->insert( $this->tb_lp_user_items, $data );
63 +
64 + $this->check_execute_has_error();
65 +
66 + return $this->wpdb->insert_id;
67 + }
68 +
69 + /**
70 + * Update data
71 + *
72 + * @param array $data [ 'user_item_id', user_id, item_id, start_time, end_time, item_type, status, graduation, ref_id, ref_type, parent_id ]
73 + * @return bool
74 + *
75 + * @throws Exception
76 + * @since 4.2.5
77 + * @version 1.0.0
78 + */
79 + public function update_data( array $data ): bool {
80 + if ( empty( $data['user_item_id'] ) ) {
81 + throw new Exception( __( 'Invalid user item id!', 'learnpress' ) . ' | ' . __FUNCTION__ );
82 + }
83 +
84 + $filter = new LP_User_Items_Filter();
85 + $filter->collection = $this->tb_lp_user_items;
86 + foreach ( $data as $col_name => $value ) {
87 + if ( ! in_array( $col_name, $filter->all_fields ) ) {
88 + continue;
89 + }
90 +
91 + if ( is_null( $value ) ) {
92 + $filter->set[] = $col_name . ' = null';
93 + } else {
94 + $filter->set[] = $this->wpdb->prepare( $col_name . ' = %s', $value );
95 + }
96 + }
97 + $filter->where[] = $this->wpdb->prepare( 'AND user_item_id = %d', $data['user_item_id'] );
98 + $this->update_execute( $filter );
99 +
100 + return true;
101 + }
102 +
103 + /**
104 + * Get users items
105 + *
106 + * @param LP_User_Items_Filter|UserItemsFilter $filter
107 + *
108 + * @return array|null|int|string
109 + * @throws Exception
110 + * @since 4.1.6.9
111 + * @version 1.0.5
112 + */
113 + public function get_user_items( $filter, int &$total_rows = 0 ) {
114 + $filter->fields = array_merge( $filter->all_fields, $filter->fields );
115 +
116 + if ( empty( $filter->collection ) ) {
117 + $filter->collection = $this->tb_lp_user_items;
118 + }
119 +
120 + if ( empty( $filter->collection_alias ) ) {
121 + $filter->collection_alias = 'ui';
122 + }
123 +
124 + if ( ! empty( $filter->ref_id ) ) {
125 + $filter->where[] = $this->wpdb->prepare( 'AND ui.ref_id = %d', $filter->ref_id );
126 + }
127 +
128 + if ( ! empty( $filter->ref_type ) ) {
129 + $filter->where[] = $this->wpdb->prepare( 'AND ui.ref_type = %s', $filter->ref_type );
130 + }
131 +
132 + if ( ! empty( $filter->user_item_id ) ) {
133 + $filter->where[] = $this->wpdb->prepare( 'AND ui.user_item_id = %d', $filter->user_item_id );
134 + }
135 +
136 + // Get by user_item_ids
137 + if ( ! empty( $filter->user_item_ids ) ) {
138 + $user_item_ids_format = LP_Helper::db_format_array( $filter->user_item_ids );
139 + $filter->where[] = $this->wpdb->prepare( 'AND ui.user_item_id IN (' . $user_item_ids_format . ')', $filter->user_item_ids );
140 + }
141 +
142 + if ( $filter->user_id !== false ) {
143 + $filter->where[] = $this->wpdb->prepare( 'AND ui.user_id = %d', $filter->user_id );
144 + }
145 +
146 + if ( ! empty( $filter->item_type ) ) {
147 + $filter->where[] = $this->wpdb->prepare( 'AND ui.item_type = %s', $filter->item_type );
148 + }
149 +
150 + if ( ! empty( $filter->item_ids ) ) {
151 + $item_ids_format = LP_Helper::db_format_array( $filter->item_ids, '%d' );
152 + $filter->where[] = $this->wpdb->prepare( 'AND ui.item_id IN (' . $item_ids_format . ')', $filter->item_ids );
153 + }
154 +
155 + if ( ! empty( $filter->item_id ) ) {
156 + $filter->where[] = $this->wpdb->prepare( 'AND ui.item_id = %s', $filter->item_id );
157 + }
158 +
159 + if ( ! empty( $filter->status ) ) {
160 + $filter->where[] = $this->wpdb->prepare( 'AND ui.status = %s', $filter->status );
161 + }
162 +
163 + if ( ! empty( $filter->graduation ) ) {
164 + $filter->where[] = $this->wpdb->prepare( 'AND ui.graduation = %s', $filter->graduation );
165 + }
166 +
167 + if ( ! empty( $filter->parent_id ) ) {
168 + $filter->where[] = $this->wpdb->prepare( 'AND ui.parent_id = %s', $filter->parent_id );
169 + }
170 +
171 + $filter = apply_filters( 'lp/user_items/query/filter', $filter );
172 +
173 + return $this->execute( $filter, $total_rows );
174 + }
175 +
176 + /**
177 + * Get items by user_item_id | this is id where item_id = course_id
178 + *
179 + * @param LP_User_Items_Filter|UserItemsFilter $filter
180 + * @param bool $force_cache
181 + *
182 + * @return object
183 + * @throws Exception
184 + * Todo: tungnx need set paginate - apply when do load API
185 + */
186 + public function get_user_course_items( $filter, bool $force_cache = false ) {
187 + $key_first_cache = 'course_items/' . $filter->user_id . '/' . $filter->parent_id;
188 + $course_items_cache = LP_Cache::cache_load_first( 'get', $key_first_cache );
189 + if ( false !== $course_items_cache && ! $force_cache ) {
190 + return $course_items_cache;
191 + }
192 +
193 + $query = $this->wpdb->prepare(
194 + "SELECT * FROM $this->tb_lp_user_items
195 + WHERE parent_id = %d
196 + AND ref_type = %s
197 + AND user_id = %d
198 + ",
199 + $filter->parent_id,
200 + LP_COURSE_CPT,
201 + $filter->user_id
202 + );
203 +
204 + $course_items = $this->wpdb->get_results( $query );
205 +
206 + $this->check_execute_has_error();
207 +
208 + LP_Cache::cache_load_first( 'set', $key_first_cache, $course_items );
209 +
210 + return $course_items;
211 + }
212 +
213 + /**
214 + * Remove items' of course and user learned
215 + *
216 + * @param LP_User_Items_Filter|UserItemsFilter $filter .
217 + *
218 + * @return bool|int
219 + * @throws Exception .
220 + * @TODO tungnx - recheck this function
221 + */
222 + public function remove_items_of_user_course( $filter ) {
223 + $query_extra = '';
224 +
225 + // Check valid user.
226 + if ( ! is_user_logged_in() || ( ! current_user_can( ADMIN_ROLE ) && get_current_user_id() != $filter->user_id ) ) {
227 + throw new Exception( __( 'Invalid user!', 'learnpress' ) . ' | ' . __FUNCTION__ );
228 + }
229 +
230 + if ( - 1 < $filter->limit ) {
231 + $query_extra .= " LIMIT $filter->limit";
232 + }
233 +
234 + $query = $this->wpdb->prepare(
235 + "DELETE FROM {$this->tb_lp_user_items}
236 + WHERE parent_id = %d
237 + $query_extra;
238 + ",
239 + $filter->parent_id
240 + );
241 +
242 + return $this->wpdb->query( $query );
243 + }
244 +
245 + /*public function get_item_status( $item_id, $course_id ) {
246 + $query = $this->wpdb->prepare(
247 + "
248 + SELECT status FROM {$this->tb_lp_user_items}
249 + WHERE ref_id = %d
250 + AND ref_type = %s
251 + AND item_id = %d
252 + ",
253 + $course_id,
254 + 'lp_course',
255 + $item_id
256 + );
257 +
258 + return $this->wpdb->get_var( $query );
259 + }*/
260 +
261 + /**
262 + * Insert/Update extra value
263 + *
264 + * @param int $user_item_id
265 + * @param string $meta_key
266 + * @param string $value
267 + * @since 4.0.0
268 + * @version 1.0.0
269 + * @author tungnx
270 + *
271 + * @return int|false The number of rows inserted|updated, or false on error.
272 + */
273 + public function update_extra_value( $user_item_id = 0, $meta_key = '', $value = '' ) {
274 + $result = false;
275 +
276 + $data = array(
277 + 'learnpress_user_item_id' => $user_item_id,
278 + 'meta_key' => $meta_key,
279 + 'extra_value' => $value,
280 + );
281 + $format = array( '%d', '%s', '%s' );
282 +
283 + $check_exist_data = $this->wpdb->get_var(
284 + $this->wpdb->prepare(
285 + "
286 + SELECT meta_id FROM $this->tb_lp_user_itemmeta
287 + WHERE " . self::$user_item_id_col . ' = %d
288 + AND meta_key = %s
289 + ',
290 + $user_item_id,
291 + $meta_key
292 + )
293 + );
294 +
295 + if ( $check_exist_data ) {
296 + $result = $this->wpdb->update(
297 + $this->tb_lp_user_itemmeta,
298 + $data,
299 + array(
300 + self::$user_item_id_col => $user_item_id,
301 + 'meta_key' => $meta_key,
302 + ),
303 + $format
304 + );
305 + } else {
306 + $result = $this->wpdb->insert( $this->tb_lp_user_itemmeta, $data, $format );
307 + }
308 +
309 + return $result;
310 + }
311 +
312 + /**
313 + * Get extra value
314 + *
315 + * @param int $user_item_id
316 + * @param string $meta_key
317 + */
318 + public function get_extra_value( $user_item_id = 0, $meta_key = '' ) {
319 + return $this->wpdb->get_var(
320 + $this->wpdb->prepare(
321 + '
322 + SELECT ' . self::$extra_value_col . " FROM $this->tb_lp_user_itemmeta
323 + WHERE " . self::$user_item_id_col . ' = %d
324 + AND meta_key = %s
325 + ',
326 + $user_item_id,
327 + $meta_key
328 + )
329 + );
330 + }
331 +
332 + /**
333 + * Re-set current item
334 + * @param $course_id
335 + * @param $item_id
336 + * @editor hungkv
337 + */
338 + public function reset_course_current_item( $course_id, $item_id ) {
339 + // Select all course enrolled
340 + $query = $this->wpdb->prepare(
341 + "
342 + SELECT user_item_id
343 + FROM {$this->wpdb->prefix}learnpress_user_items
344 + WHERE status = %s AND item_id = %d AND graduation = %s
345 + ",
346 + 'enrolled',
347 + $course_id,
348 + 'in-progress'
349 + );
350 + $user_item_ids = $this->wpdb->get_col( $query );
351 + if ( ! empty( $user_item_ids ) ) {
352 + foreach ( $user_item_ids as $user_item_id ) {
353 + // Check item is current item of all course
354 + $query = $this->wpdb->prepare(
355 + "
356 + SELECT meta_value
357 + FROM {$this->wpdb->prefix}learnpress_user_itemmeta
358 + WHERE learnpress_user_item_id = %d
359 + ",
360 + $user_item_id
361 + );
362 + $meta_value_id = $this->wpdb->get_var( $query );
363 + // Check if the deleted item is current item or not
364 + if ( $meta_value_id == $item_id ) {
365 + $course = learn_press_get_course( $course_id );
366 + // update _curent_item to database
367 + learn_press_update_user_item_meta( $user_item_id, '_current_item', $course->get_first_item_id() );
368 + }
369 + }
370 + }
371 + }
372 +
373 + /**
374 + * Get number status by status, graduation...
375 + *
376 + * @param LP_User_Items_Filter|UserItemsFilter $filter {user_id, item_type}
377 + *
378 + * @author tungnx
379 + * @since 4.1.5
380 + * @version 1.0.2
381 + * @return object|null
382 + * @throws Exception
383 + */
384 + public function count_status_by_items( $filter ) {
385 + $filter->only_fields[] = $this->wpdb->prepare( 'SUM(ui.graduation = %s) AS %s', LP_COURSE_GRADUATION_IN_PROGRESS, LP_COURSE_GRADUATION_IN_PROGRESS );
386 + $filter->only_fields[] = $this->wpdb->prepare( 'SUM(ui.graduation = %s) AS %s', LP_COURSE_GRADUATION_FAILED, LP_COURSE_GRADUATION_FAILED );
387 + $filter->only_fields[] = $this->wpdb->prepare( 'SUM(ui.graduation = %s) AS %s', LP_COURSE_GRADUATION_PASSED, LP_COURSE_GRADUATION_PASSED );
388 + $filter->only_fields[] = $this->wpdb->prepare( 'SUM(ui.status = %s) AS %s', LP_COURSE_ENROLLED, LP_COURSE_ENROLLED );
389 + $filter->only_fields[] = $this->wpdb->prepare( 'SUM(ui.status = %s) AS %s', LP_COURSE_PURCHASED, LP_COURSE_PURCHASED );
390 + $filter->only_fields[] = $this->wpdb->prepare( 'SUM(ui.status = %s) AS %s', LP_COURSE_FINISHED, LP_COURSE_FINISHED );
391 +
392 + if ( $filter->user_id ) {
393 + $filter_user_attend_courses = new LP_User_Items_Filter();
394 + $filter_user_attend_courses->only_fields = array( 'MAX(ui.user_item_id) AS user_item_id' );
395 + $filter_user_attend_courses->where[] = $this->wpdb->prepare( 'AND ui.user_id = %s', $filter->user_id );
396 + $filter_user_attend_courses->where[] = $this->wpdb->prepare( 'AND ui.status != %s', UserItemModel::STATUS_CANCEL );
397 + $filter_user_attend_courses->group_by = 'ui.item_id';
398 + $filter_user_attend_courses->return_string_query = true;
399 + $query_get_course_attend = $this->get_user_courses( $filter_user_attend_courses );
400 + $filter->where[] = 'AND ui.user_item_id IN (' . $query_get_course_attend . ')';
401 + }
402 +
403 + $filter->return_string_query = true;
404 +
405 + $filter = apply_filters( 'lp/user/course/query/count-status', $filter );
406 +
407 + $query = $this->get_user_courses( $filter );
408 +
409 + $this->check_execute_has_error();
410 +
411 + return $this->wpdb->get_row( $query );
412 + }
413 +
414 + /**
415 + * Get the newest item is course of user
416 + *
417 + * @param LP_User_Items_Filter|UserItemsFilter $filter {course_id, user_id}
418 + * @param bool $force_cache Reset first cache
419 + *
420 + * @return null|object
421 + * @throws Exception
422 + */
423 + public function get_last_user_course( $filter, bool $force_cache = false ) {
424 + $query = $this->wpdb->prepare(
425 + "SELECT user_item_id, user_id, item_id, item_type, status, graduation, ref_id, ref_type, start_time, end_time
426 + FROM $this->tb_lp_user_items
427 + WHERE item_type = %s
428 + AND item_id = %d
429 + AND user_id = %d
430 + ORDER BY user_item_id DESC
431 + LIMIT 1
432 + ",
433 + LP_COURSE_CPT,
434 + $filter->item_id,
435 + $filter->user_id
436 + );
437 +
438 + $result = $this->wpdb->get_row( $query );
439 +
440 + $this->check_execute_has_error();
441 +
442 + return $result;
443 + }
444 +
445 + /**
446 + * Get item of user and course
447 + *
448 + * @param LP_User_Items_Filter|UserItemsFilter $filter {parent_id, item_id, user_id}
449 + * @param bool $force_cache Reset first cache
450 + *
451 + * @return null|object
452 + * @throws Exception
453 + */
454 + public function get_user_course_item( $filter, bool $force_cache = false ) {
455 + $key_load_first = 'user_course_item/' . $filter->user_id . '/' . $filter->item_id;
456 + $user_course = LP_Cache::cache_load_first( 'get', $key_load_first );
457 +
458 + if ( false !== $user_course && ! $force_cache ) {
459 + return $user_course;
460 + }
461 +
462 + $WHERE = 'WHERE 1=1 ';
463 +
464 + if ( $filter->parent_id ) {
465 + $WHERE .= $this->wpdb->prepare( 'AND parent_id = %d ', $filter->parent_id );
466 + }
467 +
468 + if ( $filter->ref_id ) {
469 + $WHERE .= $this->wpdb->prepare( 'AND ref_id = %d ', $filter->ref_id );
470 + }
471 +
472 + if ( $filter->ref_type ) {
473 + $WHERE .= $this->wpdb->prepare( 'AND ref_type = %s ', $filter->ref_type );
474 + }
475 +
476 + if ( $filter->item_type ) {
477 + $WHERE .= $this->wpdb->prepare( 'AND item_type = %s ', $filter->item_type );
478 + }
479 +
480 + $query = $this->wpdb->prepare(
481 + "SELECT user_item_id, user_id, item_id, item_type, status, graduation, ref_id, ref_type, start_time, end_time, parent_id
482 + FROM $this->tb_lp_user_items
483 + $WHERE
484 + AND item_id = %d
485 + AND user_id = %d
486 + ORDER BY user_item_id DESC
487 + LIMIT 1
488 + ",
489 + $filter->item_id,
490 + $filter->user_id
491 + );
492 +
493 + $result = $this->wpdb->get_row( $query );
494 +
495 + $this->check_execute_has_error();
496 +
497 + LP_Cache::cache_load_first( 'set', $key_load_first, $result );
498 +
499 + return $result;
500 + }
501 +
502 + /**
503 + * Get items of course by item type
504 + *
505 + * @param LP_User_Items_Filter|UserItemsFilter $filter {$filter->parent_id, $filter->item_type, [$filter->item_id]}
506 + * @throws Exception
507 + */
508 + public function get_user_course_items_by_item_type( $filter ) {
509 +
510 + $AND = '';
511 +
512 + if ( $filter->item_type ) {
513 + $AND .= $this->wpdb->prepare( ' AND item_type = %s', $filter->item_type );
514 + }
515 +
516 + if ( $filter->item_id ) {
517 + $AND .= $this->wpdb->prepare( ' AND item_id = %d', $filter->item_id );
518 + }
519 +
520 + $query = $this->wpdb->prepare(
521 + "SELECT user_item_id, user_id, item_id, item_type, status, graduation, ref_id, ref_type, start_time, end_time, parent_id
522 + FROM $this->tb_lp_user_items
523 + WHERE parent_id = %d
524 + $AND
525 + ",
526 + $filter->parent_id
527 + );
528 +
529 + $result = $this->wpdb->{$filter->query_type}( $query );
530 +
531 + $this->check_execute_has_error();
532 +
533 + return $result;
534 + }
535 +
536 + /**
537 + * Get user_item_id by course_id
538 + *
539 + * @param LP_User_Items_Filter|UserItemsFilter $filter $filter->item_id
540 + *
541 + * @return array
542 + */
543 + public function get_user_items_by_course( $filter ): array {
544 + try {
545 + // Check valid user.
546 + if ( ! is_user_logged_in() ) {
547 + throw new Exception( __( 'Invalid user!', 'learnpress' ) . ' | ' . __FUNCTION__ );
548 + }
549 +
550 + $query = $this->wpdb->prepare(
551 + "SELECT user_item_id FROM $this->tb_lp_user_items
552 + WHERE item_id = %d
553 + AND item_type = %s
554 + ",
555 + $filter->item_id,
556 + LP_COURSE_CPT
557 + );
558 +
559 + return $this->wpdb->get_col( $query );
560 + } catch ( Throwable $e ) {
561 + error_log( __FUNCTION__ . ':' . $e->getMessage() );
562 + return array();
563 + }
564 + }
565 +
566 + /**
567 + * Get items of course has user
568 + *
569 + * @param LP_User_Items_Filter|UserItemsFilter $filter user_item_ids
570 + *
571 + * @throws Exception
572 + * @since 4.1.4
573 + * @version 1.0.0
574 + */
575 + public function get_item_ids_of_user_course( $filter ): array {
576 + if ( empty( $filter->user_item_ids ) ) {
577 + return [];
578 + }
579 +
580 + $where = 'WHERE 1=1 ';
581 +
582 + $where .= $this->wpdb->prepare(
583 + 'AND parent_id IN(' . LP_Helper::db_format_array( $filter->user_item_ids, '%d' ) . ')',
584 + $filter->user_item_ids
585 + );
586 +
587 + return $this->wpdb->get_col(
588 + "SELECT user_item_id FROM {$this->tb_lp_user_items}
589 + {$where}
590 + "
591 + );
592 + }
593 +
594 + /**
595 + * Remove rows IN user_item_ids
596 + *
597 + * @param LP_User_Items_Filter|UserItemsFilter $filter $filter->user_item_ids, $filter->user_id
598 + *
599 + * @throws Exception
600 + * @since 4.1.4
601 + * @version 1.0.0
602 + */
603 + public function remove_user_item_ids( $filter ) {
604 + // Check valid user.
605 + /*if ( ! is_user_logged_in() || ( ! current_user_can( ADMIN_ROLE ) && get_current_user_id() != $filter->user_id ) ) {
606 + throw new Exception( __( 'User invalid!', 'learnpress' ) . ' | ' . __FUNCTION__ );
607 + }*/
608 +
609 + if ( empty( $filter->user_item_ids ) ) {
610 + return 1;
611 + }
612 +
613 + $where = 'WHERE 1=1 ';
614 +
615 + $where .= $this->wpdb->prepare(
616 + 'AND user_item_id IN(' . LP_Helper::db_format_array( $filter->user_item_ids, '%d' ) . ')',
617 + $filter->user_item_ids
618 + );
619 +
620 + return $this->wpdb->query(
621 + "DELETE FROM {$this->tb_lp_user_items}
622 + {$where}
623 + "
624 + );
625 + }
626 +
627 + /**
628 + * Remove user_itemmeta has list user_item_ids
629 + *
630 + * @param LP_User_Items_Filter|UserItemsFilter $filter $filter->user_item_ids, $filter->user_id
631 + *
632 + * @throws Exception
633 + * @since 4.1.4
634 + * @version 1.0.0
635 + */
636 + public function remove_user_itemmeta( $filter ) {
637 + // Check valid user.
638 + /*if ( ! is_user_logged_in() || ( ! current_user_can( ADMIN_ROLE ) && get_current_user_id() != $filter->user_id ) ) {
639 + throw new Exception( __( 'User invalid!', 'learnpress' ) . ' | ' . __FUNCTION__ );
640 + }*/
641 +
642 + if ( empty( $filter->user_item_ids ) ) {
643 + return 1;
644 + }
645 +
646 + $where = 'WHERE 1=1 ';
647 +
648 + $where .= $this->wpdb->prepare(
649 + 'AND learnpress_user_item_id IN(' . LP_Helper::db_format_array( $filter->user_item_ids, '%d' ) . ')',
650 + $filter->user_item_ids
651 + );
652 +
653 + return $this->wpdb->query(
654 + "DELETE FROM {$this->tb_lp_user_itemmeta}
655 + {$where}
656 + "
657 + );
658 + }
659 +
660 + /**
661 + * Delete user_item_ids by user_id and course_id
662 + *
663 + * @param int $user_id
664 + * @param int $course_id
665 + * @author tungnx
666 + * @since 4.1.4
667 + * @version 1.0.0
668 + */
669 + public function delete_user_items_old( int $user_id = 0, int $course_id = 0 ) {
670 + $lp_user_items_db = LP_User_Items_DB::getInstance();
671 + $lp_user_item_results = LP_User_Items_Result_DB::instance();
672 +
673 + try {
674 + // Check valid user.
675 + /*if ( ! is_user_logged_in() || ( ! current_user_can( ADMIN_ROLE ) && get_current_user_id() != $user_id ) ) {
676 + throw new Exception( __( 'User invalid!', 'learnpress' ) . ' | ' . __FUNCTION__ );
677 + }*/
678 +
679 + // Get all user_item_ids has user_id and course_id
680 + $filter = new LP_User_Items_Filter();
681 + $filter->user_id = $user_id;
682 + $filter->item_id = $course_id;
683 + $filter->item_type = LP_COURSE_CPT;
684 + $filter->only_fields = [ 'user_item_id' ];
685 + $filter->run_query_count = false;
686 + $filter->return_string_query = true;
687 + $user_course_ids_query = $lp_user_items_db->get_user_items( $filter );
688 + $user_course_ids = $this->wpdb->get_col( $user_course_ids_query );
689 + if ( empty( $user_course_ids ) ) {
690 + return;
691 + }
692 +
693 + $course = learn_press_get_course( $course_id );
694 + if ( ! $course ) {
695 + return;
696 + }
697 +
698 + $course->delete_user_item_and_result( $user_course_ids );
699 +
700 + // Clear cache total students enrolled of one course.
701 + $lp_course_cache = new LP_Course_Cache( true );
702 + $lp_course_cache->clean_total_students_enrolled( $course_id );
703 + $lp_course_cache->clean_total_students_enrolled_or_purchased( $course_id );
704 + // Clear cache count students many courses.
705 + $lp_courses_cache = new LP_Courses_Cache( true );
706 + $lp_courses_cache->clear_cache_on_group( LP_Courses_Cache::KEYS_COUNT_STUDENT_COURSES );
707 + // Clear cache user course.
708 + $lp_user_items_cache = new LP_User_Items_Cache();
709 + $lp_user_items_cache->clean_user_item(
710 + [
711 + $user_id,
712 + $course_id,
713 + LP_COURSE_CPT,
714 + ]
715 + );
716 + // Clear userCourseModel cache.
717 + $key_cache = "userCourseModel/find/{$user_id}/{$course_id}/" . LP_COURSE_CPT;
718 + $lpUserCourseCache = new LP_Cache();
719 + $lpUserCourseCache->clear( $key_cache );
720 +
721 + do_action( 'learn-press/user-item-old/delete', $user_id, $course_id );
722 + } catch ( Throwable $e ) {
723 + error_log( __FUNCTION__ . ': ' . $e->getMessage() );
724 + }
725 + }
726 +
727 + /**
728 + * Update user_id for lp_user_item with Order buy User Guest
729 + *
730 + * @param LP_User_Items_Filter|UserItemsFilter $filter
731 + *
732 + * @return bool|int
733 + * @throws Exception
734 + */
735 + public function update_user_id_by_order( $filter ) {
736 + // Check valid user.
737 + if ( ! is_user_logged_in() || ( ! current_user_can( ADMIN_ROLE ) && get_current_user_id() != $filter->user_id ) ) {
738 + throw new Exception( __FUNCTION__ . ': Invalid user!' );
739 + }
740 +
741 + $query = $this->wpdb->prepare(
742 + "UPDATE {$this->tb_lp_user_items}
743 + SET user_id = %d
744 + WHERE ref_type = %s
745 + AND ref_id = %d
746 + ",
747 + $filter->user_id,
748 + LP_ORDER_CPT,
749 + $filter->ref_id
750 + );
751 +
752 + return $this->wpdb->query( $query );
753 + }
754 +
755 + /**
756 + * Count items by type and total by status
757 + *
758 + * @param LP_User_Items_Filter|UserItemsFilter $filter {parent_id, status, graduation}
759 + *
760 + * @throws Exception
761 + *
762 + * @return null|object
763 + */
764 + public function count_items_of_course_with_status( $filter ) {
765 + $item_types = CourseModel::item_types_support();
766 + $count_item_types = count( $item_types );
767 + $i = 0;
768 +
769 + //$user_course = $this->get_last_user_course( $filter );
770 +
771 + $query_count = '';
772 + $query_count .= $this->wpdb->prepare( 'SUM(ui.status = %s) AS count_status,', $filter->status );
773 +
774 + foreach ( $item_types as $item_type ) {
775 + ++$i;
776 + $query_count .= $this->wpdb->prepare( 'SUM(ui.status = %s AND ui.item_type = %s) AS %s,', $filter->status, $item_type, $item_type . '_status_' . $filter->status );
777 + $query_count .= $this->wpdb->prepare( 'SUM(ui.graduation = %s AND ui.item_type = %s) AS %s', $filter->graduation, $item_type, $item_type . '_graduation_' . $filter->graduation );
778 +
779 + if ( $i < $count_item_types ) {
780 + $query_count .= ',';
781 + }
782 + }
783 +
784 + $query = $this->wpdb->prepare(
785 + 'SELECT ' . $query_count . ' FROM ' . $this->tb_lp_user_items . ' ui
786 + WHERE parent_id = %d
787 + ',
788 + $filter->parent_id
789 + );
790 +
791 + $total_items = $this->wpdb->get_row( $query );
792 +
793 + return $total_items;
794 + }
795 +
796 + /**
797 + * Get quizzes of user
798 + *
799 + * @param LP_User_Items_Filter|UserItemsFilter $filter
800 + * @param int $total_rows
801 + *
802 + * @return array|int|string|null
803 + * @throws Exception
804 + * @since 4.1.4.1
805 + * @version 1.0.2
806 + */
807 + public function get_user_quizzes( $filter, int &$total_rows = 0 ) {
808 + $filter->item_type = LP_QUIZ_CPT;
809 + $filter->ref_type = LP_COURSE_CPT;
810 +
811 + return $this->get_user_items( $filter, $total_rows );
812 + }
813 +
814 + /**
815 + * Get courses only by course's user are learning
816 + *
817 + * @param LP_User_Items_Filter|UserItemsFilter $filter
818 + * @param int $total_rows
819 + *
820 + * @author tungnx
821 + * @version 1.0.2
822 + * @since 4.1.5
823 + * @return null|array|string|int
824 + * @throws Exception
825 + */
826 + public function get_user_courses( $filter, int &$total_rows = 0 ) {
827 + $filter->collection_alias = 'ui';
828 +
829 + // Get courses publish, private
830 + $filter->join[] = "INNER JOIN {$this->tb_posts} AS p ON p.ID = $filter->collection_alias.item_id";
831 + $filter->where[] = $this->wpdb->prepare( 'AND ( p.post_status = %s OR p.post_status = %s )', 'publish', 'private' );
832 + $filter->item_type = LP_COURSE_CPT;
833 +
834 + $filter = apply_filters( 'lp/user/course/query/filter', $filter );
835 +
836 + return $this->get_user_items( $filter, $total_rows );
837 + }
838 +
839 + /**
840 + * Get total users attend courses of Author
841 + *
842 + * @param int $author_id
843 + *
844 + * @return LP_User_Items_Filter
845 + * @since 4.1.6
846 + * @version 1.0.1
847 + * @throws Exception
848 + */
849 + public function count_user_attend_courses_of_author( int $author_id ): LP_User_Items_Filter {
850 + $filter_course = new LP_Course_Filter();
851 + $filter_course->only_fields = array( 'ID' );
852 + $filter_course->post_author = $author_id;
853 + $filter_course->post_status = [ 'publish', 'private' ];
854 + $filter_course->return_string_query = true;
855 + $query_courses_str = LP_Course_DB::getInstance()->get_courses( $filter_course );
856 +
857 + $filter = new LP_User_Items_Filter();
858 + $filter->item_type = LP_COURSE_CPT;
859 + $filter->only_fields = array( 'ui.user_id' );
860 + $filter->field_count = 'ui.user_id';
861 + $filter->where[] = "AND item_id IN ({$query_courses_str})";
862 + $filter->query_count = true;
863 +
864 + return apply_filters( 'lp/user/course/query/filter/count-users-attend-courses-of-author', $filter );
865 + }
866 +
867 + /**
868 + * Get list students attend
869 + *
870 + * @param LP_User_Items_Filter|UserItemsFilter $filter
871 + * @param int $total_rows
872 + *
873 + * @return array|int|string|null
874 + * @since 4.1.6.9
875 + * @throws Exception
876 + */
877 + public function get_students( $filter, int &$total_rows = 0 ) {
878 + $default_fields = $this->get_cols_of_table( $this->tb_users );
879 + $filter->fields = array_merge( $default_fields, $filter->fields );
880 + $filter->exclude_fields = [ 'user_pass', 'user_login', 'user_status', 'user_activation_key' ];
881 + $filter->field_count = 'ID';
882 +
883 + if ( empty( $filter->collection ) ) {
884 + $filter->collection = $this->tb_users;
885 + }
886 +
887 + if ( empty( $filter->collection_alias ) ) {
888 + $filter->collection_alias = 'u';
889 + }
890 +
891 + // Filter
892 + $filter->join[] = "INNER JOIN $this->tb_lp_user_items AS ui ON u.ID = ui.user_id";
893 + $filter->where[] = $this->wpdb->prepare( 'AND item_type =%s', LP_COURSE_CPT );
894 +
895 + // Filter by user ids
896 + if ( ! empty( $filter->user_ids ) ) {
897 + $term_ids_format = LP_Helper::db_format_array( $filter->user_ids, '%d' );
898 + $filter->where[] = $this->wpdb->prepare( 'AND r_term.term_taxonomy_id IN (' . $term_ids_format . ')', $filter->user_ids );
899 + }
900 +
901 + // Filter
902 +
903 + $filter->group_by = 'ID';
904 +
905 + // End filter
906 +
907 + $filter = apply_filters( 'lp/course/query/students', $filter );
908 +
909 + return $this->execute( $filter, $total_rows );
910 + }
911 +
912 + /**
913 + * Count students on category course.
914 + *
915 + * @param LP_User_Items_Filter|UserItemsFilter $filter
916 + * @return int
917 + * @since 4.2.5.4
918 + * @version 1.0.0
919 + */
920 + public function count_students( $filter ): int {
921 + $count = 0;
922 +
923 + try {
924 + $filter->query_count = true;
925 + $filter->only_fields = [ 'ui.user_id' ];
926 + $filter->field_count = 'ui.user_id';
927 + $filter->item_type = LP_COURSE_CPT;
928 + $filter->where[] = 'AND ui.user_id != 0';
929 + $this->get_user_items( $filter, $count );
930 + } catch ( Throwable $e ) {
931 + error_log( __METHOD__ . ': ' . $e->getMessage() );
932 + }
933 +
934 + return $count;
935 + }
936 +}
937 +
938 +LP_Course_DB::getInstance();