PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.9
4.4.9 4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 All 140 releases
← All changes | inc/user-item/class-lp-user-item-course.php +1219 -1219 4.3.8 → 4.4.9 View file →
@@ -1,1219 +1,1219 @@
1 -<?php
2 -
3 -use LearnPress\Filters\UserItemsFilter;
4 -use LearnPress\Models\UserItems\UserCourseModel;
5 -
6 -/**
7 - * Class LP_User_Item_Course
8 - */
9 -
10 -class LP_User_Item_Course extends LP_User_Item {
11 - public $_item_type = LP_COURSE_CPT;
12 - public $_ref_type = LP_ORDER_CPT;
13 -
14 - /**
15 - * Course
16 - *
17 - * @var LP_Course
18 - */
19 - protected $_course = 0;
20 -
21 - /**
22 - * @var LP_User
23 - */
24 - protected $_user = 0;
25 -
26 - /**
27 - * @var array
28 - */
29 - protected $_items_by_item_ids = array();
30 -
31 - /**
32 - * @var array
33 - */
34 - protected $_items_by_order = array();
35 -
36 - /**
37 - * @var bool
38 - */
39 - protected $_loaded = false;
40 -
41 - /**
42 - * @var LP_User_CURD
43 - */
44 - protected $_curd = null;
45 -
46 - /**
47 - * LP_User_Item_Course constructor.
48 - *
49 - * @param object|array $item
50 - */
51 - public function __construct( $item ) {
52 - /**
53 - * Todo: Fix for item is course_id, will be removed when change all to array or object
54 - * @editor tungnx 4.1.6.9
55 - */
56 - if ( gettype( $item ) == 'integer' ) {
57 - $item_id = $item;
58 - $item = [];
59 - $item['item_id'] = $item_id;
60 - }
61 -
62 - $item = (array) $item;
63 - $item['item_type'] = $this->_item_type;
64 - $item['ref_type'] = $this->_ref_type;
65 -
66 - if ( isset( $item['item_id'] ) ) {
67 - $this->_course = learn_press_get_course( $item['item_id'] );
68 - }
69 -
70 - parent::__construct( $item );
71 -
72 - $this->_curd = new LP_User_CURD();
73 - $this->_changes = array();
74 - }
75 -
76 - /*public function load() {
77 - if ( ! $this->_loaded ) {
78 - $this->read_items();
79 -
80 - $this->_loaded = true;
81 - }
82 - }*/
83 -
84 - /**
85 - * Read items' data of course for the user.
86 - *
87 - * @param bool $refresh .
88 - *
89 - * @return array|bool
90 - */
91 - public function read_items( $refresh = false ) {
92 - $user_course_item_id = $this->get_user_item_id();
93 -
94 - if ( ! $this->_course || ( ! $user_course_item_id ) ) {
95 - return false;
96 - }
97 -
98 - $course_items = $this->_course->get_item_ids();
99 - $total_items = $this->_course->count_items();
100 -
101 - if ( empty( $total_items ) ) {
102 - return false;
103 - }
104 -
105 - $filter = new LP_User_Items_Filter();
106 - $filter->parent_id = $user_course_item_id;
107 - $filter->user_id = $this->get_user_id();
108 - $user_course_items = LP_User_Items_DB::getInstance()->get_user_course_items( $filter );
109 -
110 - if ( $user_course_items ) {
111 - $tmp = array();
112 - // Convert keys of array from numeric to keys is item id
113 - foreach ( $user_course_items as $user_course_item ) {
114 - $tmp[ $user_course_item->item_id ] = $user_course_item;
115 - }
116 -
117 - $user_course_items = $tmp;
118 - unset( $tmp );
119 - } else {
120 - $user_course_items = array();
121 - }
122 -
123 - $items = array();
124 -
125 - foreach ( $course_items as $item_id ) {
126 - if ( ! empty( $user_course_items[ $item_id ] ) ) {
127 - $user_course_item = (array) $user_course_items[ $item_id ];
128 - } else {
129 - $user_course_item = array(
130 - 'item_id' => $item_id,
131 - 'ref_id' => $this->get_id(),
132 - 'parent_id' => $user_course_item_id,
133 - );
134 - }
135 -
136 - $course_item = apply_filters(
137 - 'learn-press/user-course-item',
138 - LP_User_Item::get_item_object( $user_course_item ),
139 - $user_course_item,
140 - $this
141 - );
142 -
143 - if ( $course_item ) {
144 - $items[ $item_id ] = $course_item;
145 - }
146 - }
147 -
148 - return $items;
149 - }
150 -
151 - /**
152 - * Get Id of course.
153 - *
154 - * @return int
155 - * @since 3.3.0
156 - */
157 - public function get_course_id() {
158 - return $this->get_data( 'item_id' );
159 - }
160 -
161 - /**
162 - * @deprecated 4.1.7.3
163 - */
164 - public function get_finishing_type() {
165 - _deprecated_function( __METHOD__, '4.1.7.3' );
166 - /*$type = $this->get_meta( 'finishing_type' );
167 -
168 - if ( ! $type ) {
169 - $type = $this->is_exceeded() <= 0 ? 'exceeded' : 'click';
170 -
171 - learn_press_update_user_item_meta( $this->get_user_item_id(), 'finishing_type', $type );
172 -
173 - $this->set_meta( 'finishing_type', $type );
174 - }
175 -
176 - return $type;*/
177 - }
178 -
179 - public function offsetSet( $offset, $value ) {
180 - // $this->set_data( $offset, $value );
181 - // Do not allow to set value directly!
182 - }
183 -
184 - public function offsetUnset( $offset ) {
185 - // Do not allow to unset value directly!
186 - }
187 -
188 - public function offsetGet( $offset ) {
189 - $items = $this->read_items();
190 -
191 - return $items && array_key_exists( $offset, $items ) ? $items[ $offset ] : false;
192 - }
193 -
194 - public function offsetExists( $offset ) {
195 - $items = $this->read_items();
196 -
197 - return array_key_exists( $offset, (array) $items );
198 - }
199 -
200 - /**
201 - * @return LP_User_Item|bool
202 - * @deprecated 4.1.6.9.2
203 - */
204 - /*public function get_viewing_item() {
205 - $item = LP_Global::course_item();
206 - if ( $item ) {
207 - return $this[ $item->get_id() ];
208 - }
209 -
210 - return false;
211 - }*/
212 -
213 - /**
214 - * Get course.
215 - *
216 - * @param string $return
217 - *
218 - * @return bool|LP_Course|int|mixed
219 - */
220 - public function get_course( string $return = '' ) {
221 - $course_id = $this->get_data( 'item_id', 0 );
222 - if ( $return == '' ) {
223 - return $course_id ? learn_press_get_course( $course_id ) : false;
224 - }
225 -
226 - return $course_id;
227 - }
228 -
229 - /**
230 - * Get result/processing course
231 - *
232 - * @param string $prop
233 - *
234 - * @return mixed
235 - */
236 - public function get_result( $prop = '' ) {
237 - $results = $this->calculate_course_results();
238 -
239 - // Fix temporary for case call 'grade' - addons called
240 - if ( 'grade' === $prop ) {
241 - if ( $results['pass'] ) {
242 - $results['grade'] = 'passed';
243 - } else {
244 - $results['grade'] = 'failed';
245 - }
246 - }
247 -
248 - return $prop && $results && array_key_exists( $prop, $results ) ? $results[ $prop ] : $results;
249 - }
250 -
251 - /**
252 - * Get current progress of course for an user.
253 - * Firstly, get data from cache if it is already loaded.
254 - * If data is not loaded to cache then get from meta data.
255 - * If meta data is not updated then calculate and update it
256 - *
257 - * @updated 3.1.0
258 - *
259 - * @param string $prop
260 - *
261 - * @return float|int
262 - */
263 - public function get_results( $prop = 'result' ) {
264 - $course = $this->get_course();
265 -
266 - if ( ! $course ) {
267 - return false;
268 - }
269 -
270 - $results = LP_Object_Cache::get(
271 - 'course-' . $this->get_item_id() . '-' . $this->get_user_id(),
272 - 'course-results'
273 - );
274 -
275 - if ( $results === false ) {
276 - $results = $this->calculate_course_results();
277 -
278 - LP_Object_Cache::set(
279 - 'course-' . $this->get_item_id() . '-' . $this->get_user_id(),
280 - $results,
281 - 'course-results'
282 - );
283 - }
284 -
285 - return $prop && $results && array_key_exists( $prop, $results ) ? $results[ $prop ] : $results;
286 - }
287 -
288 - /**
289 - * Calculate course result
290 - */
291 - public function calculate_course_results( bool $force_cache = false ) {
292 - $results = array(
293 - 'count_items' => 0,
294 - 'completed_items' => 0,
295 - 'items' => array(),
296 - 'evaluate_type' => '',
297 - 'pass' => 0,
298 - 'result' => 0,
299 - );
300 -
301 - try {
302 - $userCourseModel = UserCourseModel::find( $this->get_user_id(), $this->get_course_id(), true );
303 - if ( ! $userCourseModel instanceof UserCourseModel ) {
304 - return $results;
305 - }
306 -
307 - $results = $userCourseModel->calculate_course_results();
308 - } catch ( Throwable $e ) {
309 - LP_Debug::error_log( $e );
310 - }
311 -
312 - return $results;
313 -
314 - // Code old
315 - $items = array();
316 - $results = array(
317 - 'count_items' => 0,
318 - 'completed_items' => 0,
319 - 'items' => array(),
320 - 'evaluate_type' => '',
321 - 'pass' => 0,
322 - 'result' => 0,
323 - );
324 -
325 - try {
326 - $course = learn_press_get_course( $this->get_course_id() );
327 -
328 - if ( ! $course ) {
329 - throw new Exception( 'Course invalid!' );
330 - }
331 -
332 - $key_first_cache = 'calculate_course/' . $this->get_user_id() . '/' . $course->get_id();
333 - $results_cache = LP_Cache::cache_load_first( 'get', $key_first_cache );
334 - if ( false !== $results_cache && ! $force_cache ) {
335 - return $results_cache;
336 - }
337 -
338 - $this->_course = $course;
339 -
340 - if ( $this->is_finished() ) {
341 - // Get result from lp_user_item_results
342 - // Todo: tungnx - set cache
343 - return LP_User_Items_Result_DB::instance()->get_result( $this->get_user_item_id() );
344 - }
345 -
346 - if ( $this->get_status() !== LP_COURSE_ENROLLED ) {
347 - return $results;
348 - }
349 -
350 - $count_items = $course->count_items();
351 - $count_items_completed = $this->count_items_completed();
352 -
353 - $evaluate_type = get_post_meta( $course->get_id(), '_lp_course_result', true );
354 - if ( ! $evaluate_type ) {
355 - $evaluate_type = 'evaluate_lesson';
356 - }
357 - switch ( $evaluate_type ) {
358 - case 'evaluate_lesson':
359 - $results_evaluate = $this->evaluate_course_by_lesson( $count_items_completed, $course->count_items( LP_LESSON_CPT ) );
360 - break;
361 - case 'evaluate_final_quiz':
362 - $results_evaluate = $this->evaluate_course_by_final_quiz();
363 - break;
364 - case 'evaluate_quiz':
365 - $results_evaluate = $this->evaluate_course_by_quizzes_passed( $count_items_completed, $course->count_items( LP_QUIZ_CPT ) );
366 - break;
367 - case 'evaluate_questions':
368 - case 'evaluate_mark':
369 - $results_evaluate = $this->evaluate_course_by_question( $evaluate_type );
370 - break;
371 - default:
372 - $results_evaluate = apply_filters( 'learn-press/evaluate_passed_conditions', $results, $evaluate_type, $this );
373 - break;
374 - }
375 -
376 - if ( ! is_array( $results_evaluate ) ) {
377 - $results_evaluate = array(
378 - 'result' => 0,
379 - 'pass' => 0,
380 - );
381 - }
382 -
383 - $results_evaluate['result'] = round( $results_evaluate['result'], 2 );
384 -
385 - $completed_items = intval( $count_items_completed->count_status ?? 0 );
386 -
387 - $item_types = learn_press_get_course_item_types();
388 - foreach ( $item_types as $item_type ) {
389 - $item_type_key = str_replace( 'lp_', '', $item_type );
390 -
391 - $items[ $item_type_key ] = array(
392 - 'completed' => $count_items_completed->{$item_type . '_status_completed'} ?? 0,
393 - 'passed' => $count_items_completed->{$item_type . '_graduation_passed'} ?? 0,
394 - 'total' => $course->count_items( $item_type ),
395 - );
396 - }
397 -
398 - $results = array_merge(
399 - $results_evaluate,
400 - compact( 'count_items', 'completed_items', 'items', 'evaluate_type' )
401 - );
402 -
403 - $results = apply_filters(
404 - 'learn-press/update-course-results',
405 - $results,
406 - $this->get_item_id(),
407 - $this->get_user_id(),
408 - $this
409 - );
410 -
411 - LP_Cache::cache_load_first( 'set', $key_first_cache, $results );
412 - } catch ( Throwable $e ) {
413 - error_log( __METHOD__ . ': ' . $e->getMessage() );
414 - }
415 -
416 - return $results;
417 - }
418 -
419 - /**
420 - * Get graduation
421 - *
422 - * @param string $context
423 - *
424 - * @return string
425 - * @deprecated 4.1.6.9.3
426 - */
427 - public function get_grade( string $context = '' ): string {
428 - $grade = $this->get_graduation() ?? '';
429 -
430 - return $context == 'display' ? learn_press_course_grade_html( $grade, false ) : $grade;
431 - }
432 -
433 - /**
434 - * @param int $decimal
435 - *
436 - * @return int|string
437 - */
438 - public function get_percent_result( $decimal = 1 ) {
439 - return round( $this->get_result( 'result' ), $decimal );
440 - }
441 -
442 - /**
443 - * Evaluate course result by lessons.
444 - *
445 - * @param $count_items_completed
446 - * @param int $total_item_lesson
447 - *
448 - * @return array
449 - * @author tungnx
450 - * @since 4.1.4.1
451 - * @version 1.0.0
452 - */
453 - protected function evaluate_course_by_lesson( $count_items_completed, int $total_item_lesson = 0 ): array {
454 - $evaluate = array(
455 - 'result' => 0,
456 - 'pass' => 0,
457 - );
458 -
459 - $count_items_completed = intval( $count_items_completed->{LP_LESSON_CPT . '_status_completed'} ?? 0 );
460 -
461 - if ( $total_item_lesson && $count_items_completed ) {
462 - $evaluate['result'] = $count_items_completed * 100 / $total_item_lesson;
463 - }
464 -
465 - $passing_condition = $this->_course->get_passing_condition();
466 - if ( $evaluate['result'] >= $passing_condition ) {
467 - $evaluate['pass'] = 1;
468 - }
469 -
470 - return $evaluate;
471 - }
472 -
473 - /**
474 - * Evaluate course result by final quiz.
475 - *
476 - * @return array
477 - */
478 - protected function evaluate_course_by_final_quiz(): array {
479 - $lp_user_items_db = LP_User_Items_DB::getInstance();
480 - $lp_user_item_result_db = LP_User_Items_Result_DB::instance();
481 - $evaluate = array(
482 - 'result' => 0,
483 - 'pass' => 0,
484 - );
485 -
486 - try {
487 - $quiz_final_id = get_post_meta( $this->get_course_id(), '_lp_final_quiz', true );
488 -
489 - if ( ! $quiz_final_id ) {
490 - throw new Exception( '' );
491 - }
492 -
493 - $quiz_final = learn_press_get_quiz( $quiz_final_id );
494 -
495 - if ( ! $quiz_final ) {
496 - throw new Exception( 'Quiz final invalid' );
497 - }
498 -
499 - $user_course = $this->get_last_user_course();
500 -
501 - if ( ! $user_course ) {
502 - throw new Exception( 'User course not exists' );
503 - }
504 -
505 - $filter = new LP_User_Items_Filter();
506 - $filter->query_type = 'get_row';
507 - $filter->parent_id = $user_course->user_item_id;
508 - $filter->item_type = LP_QUIZ_CPT;
509 - $filter->item_id = $quiz_final_id;
510 - $user_quiz = $lp_user_items_db->get_user_course_items_by_item_type( $filter );
511 -
512 - if ( ! $user_quiz ) {
513 - throw new Exception();
514 - }
515 -
516 - // Get result did quiz
517 - $quiz_result = $lp_user_item_result_db->get_result( $user_quiz->user_item_id );
518 -
519 - if ( $quiz_result ) {
520 - if ( ! isset( $quiz_result['result'] ) ) {
521 - $evaluate['result'] = $quiz_result['user_mark'] * 100 / $quiz_result['mark'];
522 - } else {
523 - $evaluate['result'] = $quiz_result['result'];
524 - }
525 -
526 - $passing_condition = floatval( $quiz_final->get_data( 'passing_grade', 0 ) );
527 - if ( $evaluate['result'] >= $passing_condition ) {
528 - $evaluate['pass'] = 1;
529 - }
530 - }
531 - } catch ( Throwable $e ) {
532 -
533 - }
534 -
535 - return $evaluate;
536 - }
537 -
538 - /**
539 - * Evaluate course results by count quizzes passed/all quizzes.
540 - *
541 - * @author tungnx
542 - * @since 4.1.4.1
543 - * @version 1.0.0
544 - */
545 - protected function evaluate_course_by_quizzes_passed( $count_items_completed, $total_item_quizzes ): array {
546 - $evaluate = array(
547 - 'result' => 0,
548 - 'pass' => 0,
549 - );
550 -
551 - $count_items_completed = intval( $count_items_completed->{LP_QUIZ_CPT . '_graduation_passed'} ?? 0 );
552 -
553 - if ( $total_item_quizzes && $count_items_completed ) {
554 - $evaluate['result'] = $count_items_completed * 100 / $total_item_quizzes;
555 -
556 - $passing_condition = $this->_course->get_passing_condition();
557 - if ( $evaluate['result'] >= $passing_condition ) {
558 - $evaluate['pass'] = 1;
559 - }
560 - }
561 -
562 - return $evaluate;
563 - }
564 -
565 - /**
566 - * Evaluate course results by count questions true/all questions.
567 - *
568 - * @author tungnx
569 - * @since 4.1.4.1
570 - * @version 1.0.0
571 - */
572 - private function evaluate_course_by_questions( &$evaluate, $lp_quizzes, $total_questions ) {
573 - $lp_user_item_results_db = LP_User_Items_Result_DB::instance();
574 - $count_questions_correct = 0;
575 -
576 - // get questions correct
577 - foreach ( $lp_quizzes as $lp_quiz ) {
578 - $lp_quiz_result = $lp_user_item_results_db->get_result( $lp_quiz->user_item_id );
579 - if ( $lp_quiz_result ) {
580 - $count_questions_correct += $lp_quiz_result['question_correct'];
581 - }
582 - }
583 -
584 - if ( $total_questions && $count_questions_correct ) {
585 - $evaluate['result'] = $count_questions_correct * 100 / $total_questions;
586 -
587 - $passing_condition = $this->_course->get_passing_condition();
588 - if ( $evaluate['result'] >= $passing_condition ) {
589 - $evaluate['pass'] = 1;
590 - }
591 - }
592 - }
593 -
594 - /**
595 - * Evaluate course results by total mark of questions.
596 - *
597 - * @author tungnx
598 - * @since 4.1.4.1
599 - * @version 1.0.0
600 - */
601 - private function evaluate_course_by_mark( &$evaluate, $lp_quizzes, $total_mark_questions ) {
602 - $lp_user_item_results_db = LP_User_Items_Result_DB::instance();
603 - $count_mark_questions_receiver = 0;
604 -
605 - foreach ( $lp_quizzes as $lp_quiz ) {
606 - $lp_quiz_result = $lp_user_item_results_db->get_result( $lp_quiz->user_item_id );
607 - if ( $lp_quiz_result ) {
608 - $count_mark_questions_receiver += $lp_quiz_result['user_mark'];
609 - }
610 - }
611 -
612 - if ( $count_mark_questions_receiver && $total_mark_questions ) {
613 - $evaluate['result'] = $count_mark_questions_receiver * 100 / $total_mark_questions;
614 -
615 - $passing_condition = floatval( $this->_course->get_passing_condition() );
616 - if ( $evaluate['result'] >= $passing_condition ) {
617 - $evaluate['pass'] = 1;
618 - }
619 - }
620 - }
621 -
622 - /**
623 - * Evaluate course results by total mark of questions.
624 - *
625 - * @author tungnx
626 - * @since 4.1.4.1
627 - * @version 1.0.0
628 - */
629 - protected function evaluate_course_by_question( string $evaluate_type ): array {
630 - $lp_user_items_db = LP_User_Items_DB::getInstance();
631 - $evaluate = array(
632 - 'result' => 0,
633 - 'pass' => 0,
634 - );
635 -
636 - try {
637 - $user_course = $this->get_last_user_course();
638 -
639 - if ( ! $user_course ) {
640 - throw new Exception( 'User course not exists!' );
641 - }
642 -
643 - // get quiz_ids
644 - $filter_get_quiz_ids = new LP_User_Items_Filter();
645 - $filter_get_quiz_ids->parent_id = $user_course->user_item_id;
646 - $filter_get_quiz_ids->item_type = LP_QUIZ_CPT;
647 - $lp_quizzes = $lp_user_items_db->get_user_course_items_by_item_type( $filter_get_quiz_ids );
648 -
649 - // Get total questions, mark
650 - // Todo: Tungnx - save (questions, mark) total when save quiz, course, if not query again
651 - $course = $this->_course;
652 - if ( is_int( $course ) ) {
653 - $course = learn_press_get_course( $course );
654 - }
655 -
656 - $total_questions = 0;
657 - $total_mark_question = 0;
658 -
659 - // Get all items' course
660 - $sections_items = $course->get_full_sections_and_items_course();
661 -
662 - foreach ( $sections_items as $section_items ) {
663 - foreach ( $section_items->items as $item ) {
664 - $itemObj = $course->get_item( $item->id );
665 -
666 - if ( ! $itemObj instanceof LP_Course_Item ) {
667 - continue;
668 - }
669 -
670 - if ( $item->type == LP_QUIZ_CPT ) {
671 - $total_questions += count( $itemObj->get_question_ids() );
672 - $total_mark_question += $itemObj->get_mark();
673 - }
674 - }
675 - }
676 - // End get total questions, mark
677 -
678 - switch ( $evaluate_type ) {
679 - case 'evaluate_questions':
680 - $this->evaluate_course_by_questions( $evaluate, $lp_quizzes, $total_questions );
681 - break;
682 - case 'evaluate_mark':
683 - $this->evaluate_course_by_mark( $evaluate, $lp_quizzes, $total_mark_question );
684 - break;
685 - default:
686 - break;
687 - }
688 -
689 - // Get results of each quiz - has questions
690 - } catch ( Throwable $e ) {
691 - error_log( __FUNCTION__ . ': ' . $e->getMessage() );
692 - }
693 -
694 - return $evaluate;
695 - }
696 -
697 - /**
698 - * Check course of use has enrolled
699 - */
700 - public function is_enrolled(): bool {
701 - return $this->get_status() == LP_COURSE_ENROLLED;
702 - }
703 -
704 - /**
705 - * Check course of use has purchased
706 - * @author tungnx
707 - * @since 4.1.3
708 - * @version 1.0.0
709 - */
710 - public function is_purchased(): bool {
711 - return $this->get_status() == LP_COURSE_PURCHASED;
712 - }
713 -
714 - public function get_level() {
715 - if ( ! $this->is_exists() ) {
716 - return 0;
717 - }
718 -
719 - $level = 10;
720 -
721 - switch ( $this->get_status() ) {
722 - case 'enrolled':
723 - $level = 20;
724 - break;
725 - case 'finished':
726 - $level = 30;
727 - break;
728 -
729 - }
730 -
731 - return $level;
732 - }
733 -
734 - /**
735 - * @deprecated 4.1.6.9.2
736 - */
737 - /*protected function _is_passed( $result ) {
738 - $is_passed = LP_COURSE_GRADUATION_FAILED;
739 - $result = round( $result, 2 );
740 -
741 - if ( $result >= $this->get_passing_condition() ) {
742 - $is_passed = LP_COURSE_GRADUATION_PASSED;
743 - }
744 -
745 - return apply_filters( 'learnpress/user/course/is-passed', $is_passed, $result );
746 - }*/
747 -
748 - /**
749 - * Get completed items.
750 - *
751 - * @param string $type - Optional. Filter by type (such lp_quiz, lp_lesson) if passed
752 - * @param bool $with_total - Optional. Include total if TRUE
753 - * @param int $section_id - Optional. Get in specific section
754 - *
755 - * @return array|bool|mixed
756 - * @editor tungnx
757 - */
758 - public function get_completed_items( $type = '', $with_total = false, $section_id = 0 ) {
759 -
760 - $this->read_items();
761 -
762 - // $completed_items = array(0,100);
763 - // return $with_total ? $completed_items : $completed_items[0];
764 -
765 - if ( ! $this->_course ) {
766 - return 0;
767 - }
768 -
769 - $key = sprintf(
770 - '%d-%d-%s',
771 - $this->get_user_id(),
772 - $this->_course->get_id(),
773 - md5( build_query( func_get_args() ) )
774 - );
775 -
776 - $completed_items = LP_Object_Cache::get( $key, 'learn-press/user-completed-items' );
777 -
778 - if ( false === $completed_items ) {
779 - $completed = 0;
780 - $total = 0;
781 - $section_items = array();
782 -
783 - if ( $section_id ) {
784 - $section = $this->_course->get_sections( 'object', $section_id );
785 -
786 - if ( $section ) {
787 - $section_items = $section->get_items();
788 -
789 - if ( $section_items ) {
790 - $section_items = array_keys( $section_items );
791 - }
792 - }
793 - }
794 -
795 - $items = $this->get_items();
796 - if ( $items ) {
797 - foreach ( $items as $item ) {
798 -
799 - if ( $section_id && ! in_array( $item->get_id(), $section_items ) ) {
800 - continue;
801 - }
802 -
803 - if ( $type ) {
804 - $item_type = $item->get_data( 'item_type' );
805 - } else {
806 - $item_type = '';
807 - }
808 -
809 - if ( $type === $item_type ) {
810 - if ( $item->get_status() == 'completed' ) {
811 - ++$completed;
812 - }
813 - $completed = apply_filters(
814 - 'learn-press/course-item/completed',
815 - $completed,
816 - $item,
817 - $item->get_status()
818 - );
819 - // if ( ! $item->is_preview() ) {
820 - ++$total;
821 - // }
822 - }
823 - }
824 - }
825 - $completed_items = array( $completed, $total );
826 - LP_Object_Cache::set( $key, $completed_items, 'learn-press/user-completed-items' );
827 - }
828 -
829 - return $with_total ? $completed_items : $completed_items[0];
830 - }
831 -
832 - /**
833 - * Get completed items.
834 - *
835 - * @return object
836 - * @editor tungnx
837 - * @modify 4.1.4.1
838 - * @since 4.0.0
839 - * @version 4.0.1
840 - */
841 - public function count_items_completed() {
842 - $lp_user_items_db = LP_User_Items_DB::getInstance();
843 - $count_items_completed = new stdClass();
844 -
845 - try {
846 - $course = learn_press_get_course( $this->get_course_id() );
847 - if ( ! $course ) {
848 - throw new Exception( 'Course is invalid!' );
849 - }
850 -
851 - $user_course = $this->get_last_user_course();
852 - if ( ! $user_course ) {
853 - throw new Exception( 'User course is invalid!' );
854 - }
855 -
856 - $filter_count = new LP_User_Items_Filter();
857 - $filter_count->parent_id = $user_course->user_item_id;
858 - $filter_count->item_id = $this->get_course_id();
859 - $filter_count->user_id = $this->get_user_id();
860 - $filter_count->status = 'completed';
861 - $filter_count->graduation = LP_COURSE_GRADUATION_PASSED;
862 - $count_items_completed = $lp_user_items_db->count_items_of_course_with_status( $filter_count );
863 - } catch ( Throwable $e ) {
864 - error_log( __METHOD__ . ': ' . $e->getMessage() );
865 - }
866 -
867 - return $count_items_completed;
868 - }
869 -
870 - /**
871 - * Get items completed by percentage.
872 - *
873 - * @param string $type - Optional. Filter by type or not
874 - * @param int $section_id - Optional. Get in specific section
875 - *
876 - * @return float|int
877 - */
878 - public function get_percent_completed_items( $type = '', $section_id = 0 ) {
879 - $values = $this->get_completed_items( $type, true, $section_id );
880 - if ( $values[1] ) {
881 - return $values[0] / $values[1] * 100;
882 - }
883 -
884 - return 0;
885 - }
886 -
887 - /**
888 - * Get passing condition criteria.
889 - *
890 - * @return string
891 - */
892 - public function get_passing_condition() {
893 - return $this->_course->get_passing_condition();
894 - }
895 -
896 - /**
897 - * Get all items in course.
898 - *
899 - * @param bool $refresh
900 - *
901 - * @return LP_User_Item[]
902 - */
903 - public function get_items( $refresh = false ) {
904 - return $this->read_items();
905 -
906 - /*
907 - return LP_Object_Cache::get(
908 - $this->get_user_id() . '-' . $this->get_id(),
909 - 'learn-press/user-course-item-objects'
910 - );*/
911 - }
912 -
913 - /**
914 - * Check course is completed or not.
915 - *
916 - * @return bool
917 - * @editor tungnx
918 - * @modify 4.1.3
919 - */
920 - public function is_finished(): bool {
921 - return $this->get_status() == LP_COURSE_FINISHED;
922 - }
923 -
924 - /**
925 - * Check course graduation is passed or not.
926 - *
927 - * @return bool
928 - */
929 - public function is_graduated() {
930 - return $this->get_graduation();
931 - }
932 -
933 - /**
934 - * @return bool
935 - * @deprecated 4.1.6.9.2
936 - */
937 - /*public function can_graduated() {
938 - return $this->get_results( 'result' ) >= $this->get_passing_condition();
939 - }*/
940 -
941 - function __destruct() {
942 - // TODO: Implement __unset() method.
943 - }
944 -
945 - /**
946 - * Get item user attend on course by item_id.
947 - *
948 - * @param int $item_id
949 - *
950 - * @return bool|LP_User_Item
951 - * @editor tungnx
952 - * @modify 4.1.6.9
953 - * @since 3.0.0
954 - * @version 4.0.1
955 - */
956 - public function get_item( $item_id ) {
957 - $item = false;
958 -
959 - try {
960 - $filter = new LP_User_Items_Filter();
961 - $filter->item_id = $item_id;
962 - $filter->ref_id = $this->get_course_id();
963 - $filter->user_id = $this->get_user();
964 - $item_result = LP_User_Items_DB::getInstance()->get_user_course_item( $filter );
965 -
966 - if ( $item_result ) {
967 - $item_result = (array) $item_result;
968 - $item = LP_User_Item::get_item_object( $item_result );
969 - }
970 - } catch ( Throwable $e ) {
971 - error_log( $e->getMessage() );
972 - }
973 -
974 - return $item;
975 - }
976 -
977 - /**
978 - * @param $item_id
979 - * @param string $prop
980 - *
981 - * @return bool|float|int
982 - * @throws Exception
983 - */
984 - public function get_item_result( $item_id, $prop = 'result' ) {
985 - $item = $this->get_item( $item_id );
986 -
987 - if ( $item instanceof LP_User_Item_Quiz ) {
988 - /**
989 - * @var LP_User_Item_Quiz $item
990 - */
991 - return $item->get_graduation();
992 - } elseif ( $item ) {
993 - return $item->get_result( $prop );
994 - }
995 -
996 - return false;
997 - }
998 -
999 - /**
1000 - * @param $id
1001 - *
1002 - * @return LP_User_Item_Quiz|bool
1003 - */
1004 - public function get_item_quiz( $id ) {
1005 -
1006 - return $this->get_item( $id );
1007 - }
1008 -
1009 - /**
1010 - * Get number of retaken times for user course.
1011 - *
1012 - * @return int
1013 - */
1014 - public function get_retaken_count(): int {
1015 - return (int) ( learn_press_get_user_item_meta( $this->get_user_item_id(), '_lp_retaken_count' ) );
1016 - }
1017 -
1018 - /**
1019 - * Increase retaken count.
1020 - *
1021 - * @return bool|int
1022 - */
1023 - public function increase_retake_count() {
1024 - $count = $this->get_retaken_count();
1025 - ++$count;
1026 -
1027 - return $this->update_meta( '_lp_retaken_count', $count );
1028 - }
1029 -
1030 - /**
1031 - * Update course item and it's child.
1032 - *
1033 - * @TODO: tungnx - review to modify
1034 - * @deprecated 4.1.7.3
1035 - */
1036 - public function save() {
1037 - _deprecated_function( __METHOD__, '4.1.7.3' );
1038 - /**
1039 - * @var LP_User_Item $item
1040 - */
1041 - $this->update();
1042 - $items = $this->get_items();
1043 - if ( ! $items ) {
1044 - return false;
1045 - }
1046 -
1047 - foreach ( $items as $item_id => $item ) {
1048 - if ( ! $item->get_status() ) {
1049 - continue;
1050 - }
1051 -
1052 - /**
1053 - * Autofill the end-time if it isn't already set
1054 - */
1055 - if ( in_array( $item->get_status(), array( 'completed', 'finished' ) ) ) {
1056 - if ( ! $item->get_end_time() || $item->get_end_time()->is_null() ) {
1057 - $item->set_end_time( current_time( 'mysql', 1 ) );
1058 - }
1059 - }
1060 -
1061 - $item->update();
1062 - }
1063 -
1064 - return true;
1065 - }
1066 -
1067 - /**
1068 - * Get passed items.
1069 - *
1070 - * @param string $type - Optional. Filter by type (such lp_quiz, lp_lesson) if passed
1071 - * @param bool $with_total - Optional. Include total if TRUE
1072 - * @param int $section_id - Optional. Get in specific section
1073 - *
1074 - * @return array|bool|mixed
1075 - * @deprecated 4.1.6.9
1076 - */
1077 - public function get_passed_items( $type = '', $with_total = false, $section_id = 0 ) {
1078 - _deprecated_function( __FUNCTION__, '4.1.6.9' );
1079 - $this->read_items();
1080 -
1081 - $key = sprintf(
1082 - '%d-%d-%s',
1083 - $this->get_user_id(),
1084 - $this->_course->get_id(),
1085 - md5( build_query( func_get_args() ) )
1086 - );
1087 - $passed_items = LP_Object_Cache::get( $key, 'learn-press/user-passed-items' );
1088 -
1089 - if ( false === $passed_items ) {
1090 - $passed = 0;
1091 - $total = 0;
1092 - $section_items = array();
1093 -
1094 - $section = $this->_course->get_sections( 'object', $section_id );
1095 -
1096 - if ( $section_id && $section ) {
1097 - $section_items = $section->get_items();
1098 -
1099 - if ( $section_items ) {
1100 - $section_items = array_keys( $section_items );
1101 - }
1102 - }
1103 -
1104 - $items = $this->get_items();
1105 -
1106 - if ( $items ) {
1107 - foreach ( $items as $item ) {
1108 -
1109 - if ( $section_id && ! in_array( $item->get_id(), $section_items ) ) {
1110 - continue;
1111 - }
1112 -
1113 - if ( $type ) {
1114 - $item_type = $item->get_data( 'item_type' );
1115 - } else {
1116 - $item_type = '';
1117 - }
1118 -
1119 - if ( $type === $item_type ) {
1120 - if ( $item->get_status( 'graduation' ) == 'passed' ) {
1121 - ++$passed;
1122 - }
1123 - $passed = apply_filters(
1124 - 'learn-press/course-item/passed',
1125 - $passed,
1126 - $item,
1127 - $item->get_status()
1128 - );
1129 - // if ( ! $item->is_preview() ) {
1130 - ++$total;
1131 - // }
1132 - }
1133 - }
1134 - }
1135 - $passed_items = array( $passed, $total );
1136 - LP_Object_Cache::set( $key, $passed_items, 'learn-press/user-passed-items' );
1137 - }
1138 -
1139 - return $with_total ? $passed_items : $passed_items[0];
1140 - }
1141 -
1142 - /**
1143 - * Get Order ID
1144 - *
1145 - * @return array|mixed
1146 - * @since 4.1.3
1147 - * @version 1.0.0
1148 - * @author tungnx
1149 - */
1150 - public function get_order_id() {
1151 - return $this->get_data( 'ref_id', 0 );
1152 - }
1153 -
1154 - /**
1155 - * Get Order
1156 - *
1157 - * @throws Exception
1158 - * @since 4.1.3
1159 - * @version 1.0.0
1160 - * @author tungnx
1161 - */
1162 - public function get_order() {
1163 - $order = false;
1164 -
1165 - if ( $this->get_order_id() ) {
1166 - $order = new LP_Order( $this->get_order_id() );
1167 - }
1168 -
1169 - return $order;
1170 - }
1171 -
1172 - /**
1173 - * Get child item ids by type item
1174 - *
1175 - * @return object|null
1176 - */
1177 - public function get_last_user_course() {
1178 - $lp_user_items_db = LP_User_Items_DB::getInstance();
1179 - $user_course = null;
1180 -
1181 - try {
1182 - $filter_user_course = new LP_User_Items_Filter();
1183 - $filter_user_course->item_id = $this->get_course_id();
1184 - $filter_user_course->user_id = $this->get_user_id();
1185 - $user_course = $lp_user_items_db->get_last_user_course( $filter_user_course );
1186 - } catch ( Throwable $e ) {
1187 - error_log( __FUNCTION__ . ':' . $e->getMessage() );
1188 - }
1189 -
1190 - return $user_course;
1191 - }
1192 -
1193 - /**
1194 - * Get courses only by course's user are learning
1195 - *
1196 - * @param LP_User_Items_Filter|UserItemsFilter $filter
1197 - * @param int $total_rows return total row query
1198 - *
1199 - * @return array|null|int|string
1200 - */
1201 - public static function get_user_courses( $filter, int &$total_rows = 0 ) {
1202 - try {
1203 - /*$key_cache = md5( json_encode( $filter ) );
1204 - $courses_cache = LP_Cache::instance()->get_cache( $key_cache );
1205 -
1206 - if ( false !== $courses_cache ) {
1207 - return $courses_cache;
1208 - }*/
1209 -
1210 - $courses = LP_User_Items_DB::getInstance()->get_user_courses( $filter, $total_rows );
1211 - //LP_Cache::instance()->set_cache( $key_cache, $courses );
1212 - } catch ( Throwable $e ) {
1213 - $courses = null;
1214 - error_log( __FUNCTION__ . ': ' . $e->getMessage() );
1215 - }
1216 -
1217 - return $courses;
1218 - }
1219 -}
1 +<?php
2 +
3 +use LearnPress\Filters\UserItemsFilter;
4 +use LearnPress\Models\UserItems\UserCourseModel;
5 +
6 +/**
7 + * Class LP_User_Item_Course
8 + */
9 +
10 +class LP_User_Item_Course extends LP_User_Item {
11 + public $_item_type = LP_COURSE_CPT;
12 + public $_ref_type = LP_ORDER_CPT;
13 +
14 + /**
15 + * Course
16 + *
17 + * @var LP_Course
18 + */
19 + protected $_course = 0;
20 +
21 + /**
22 + * @var LP_User
23 + */
24 + protected $_user = 0;
25 +
26 + /**
27 + * @var array
28 + */
29 + protected $_items_by_item_ids = array();
30 +
31 + /**
32 + * @var array
33 + */
34 + protected $_items_by_order = array();
35 +
36 + /**
37 + * @var bool
38 + */
39 + protected $_loaded = false;
40 +
41 + /**
42 + * @var LP_User_CURD
43 + */
44 + protected $_curd = null;
45 +
46 + /**
47 + * LP_User_Item_Course constructor.
48 + *
49 + * @param object|array $item
50 + */
51 + public function __construct( $item ) {
52 + /**
53 + * Todo: Fix for item is course_id, will be removed when change all to array or object
54 + * @editor tungnx 4.1.6.9
55 + */
56 + if ( gettype( $item ) == 'integer' ) {
57 + $item_id = $item;
58 + $item = [];
59 + $item['item_id'] = $item_id;
60 + }
61 +
62 + $item = (array) $item;
63 + $item['item_type'] = $this->_item_type;
64 + $item['ref_type'] = $this->_ref_type;
65 +
66 + if ( isset( $item['item_id'] ) ) {
67 + $this->_course = learn_press_get_course( $item['item_id'] );
68 + }
69 +
70 + parent::__construct( $item );
71 +
72 + $this->_curd = new LP_User_CURD();
73 + $this->_changes = array();
74 + }
75 +
76 + /*public function load() {
77 + if ( ! $this->_loaded ) {
78 + $this->read_items();
79 +
80 + $this->_loaded = true;
81 + }
82 + }*/
83 +
84 + /**
85 + * Read items' data of course for the user.
86 + *
87 + * @param bool $refresh .
88 + *
89 + * @return array|bool
90 + */
91 + public function read_items( $refresh = false ) {
92 + $user_course_item_id = $this->get_user_item_id();
93 +
94 + if ( ! $this->_course || ( ! $user_course_item_id ) ) {
95 + return false;
96 + }
97 +
98 + $course_items = $this->_course->get_item_ids();
99 + $total_items = $this->_course->count_items();
100 +
101 + if ( empty( $total_items ) ) {
102 + return false;
103 + }
104 +
105 + $filter = new LP_User_Items_Filter();
106 + $filter->parent_id = $user_course_item_id;
107 + $filter->user_id = $this->get_user_id();
108 + $user_course_items = LP_User_Items_DB::getInstance()->get_user_course_items( $filter );
109 +
110 + if ( $user_course_items ) {
111 + $tmp = array();
112 + // Convert keys of array from numeric to keys is item id
113 + foreach ( $user_course_items as $user_course_item ) {
114 + $tmp[ $user_course_item->item_id ] = $user_course_item;
115 + }
116 +
117 + $user_course_items = $tmp;
118 + unset( $tmp );
119 + } else {
120 + $user_course_items = array();
121 + }
122 +
123 + $items = array();
124 +
125 + foreach ( $course_items as $item_id ) {
126 + if ( ! empty( $user_course_items[ $item_id ] ) ) {
127 + $user_course_item = (array) $user_course_items[ $item_id ];
128 + } else {
129 + $user_course_item = array(
130 + 'item_id' => $item_id,
131 + 'ref_id' => $this->get_id(),
132 + 'parent_id' => $user_course_item_id,
133 + );
134 + }
135 +
136 + $course_item = apply_filters(
137 + 'learn-press/user-course-item',
138 + LP_User_Item::get_item_object( $user_course_item ),
139 + $user_course_item,
140 + $this
141 + );
142 +
143 + if ( $course_item ) {
144 + $items[ $item_id ] = $course_item;
145 + }
146 + }
147 +
148 + return $items;
149 + }
150 +
151 + /**
152 + * Get Id of course.
153 + *
154 + * @return int
155 + * @since 3.3.0
156 + */
157 + public function get_course_id() {
158 + return $this->get_data( 'item_id' );
159 + }
160 +
161 + /**
162 + * @deprecated 4.1.7.3
163 + */
164 + public function get_finishing_type() {
165 + _deprecated_function( __METHOD__, '4.1.7.3' );
166 + /*$type = $this->get_meta( 'finishing_type' );
167 +
168 + if ( ! $type ) {
169 + $type = $this->is_exceeded() <= 0 ? 'exceeded' : 'click';
170 +
171 + learn_press_update_user_item_meta( $this->get_user_item_id(), 'finishing_type', $type );
172 +
173 + $this->set_meta( 'finishing_type', $type );
174 + }
175 +
176 + return $type;*/
177 + }
178 +
179 + public function offsetSet( $offset, $value ) {
180 + // $this->set_data( $offset, $value );
181 + // Do not allow to set value directly!
182 + }
183 +
184 + public function offsetUnset( $offset ) {
185 + // Do not allow to unset value directly!
186 + }
187 +
188 + public function offsetGet( $offset ) {
189 + $items = $this->read_items();
190 +
191 + return $items && array_key_exists( $offset, $items ) ? $items[ $offset ] : false;
192 + }
193 +
194 + public function offsetExists( $offset ) {
195 + $items = $this->read_items();
196 +
197 + return array_key_exists( $offset, (array) $items );
198 + }
199 +
200 + /**
201 + * @return LP_User_Item|bool
202 + * @deprecated 4.1.6.9.2
203 + */
204 + /*public function get_viewing_item() {
205 + $item = LP_Global::course_item();
206 + if ( $item ) {
207 + return $this[ $item->get_id() ];
208 + }
209 +
210 + return false;
211 + }*/
212 +
213 + /**
214 + * Get course.
215 + *
216 + * @param string $return
217 + *
218 + * @return bool|LP_Course|int|mixed
219 + */
220 + public function get_course( string $return = '' ) {
221 + $course_id = $this->get_data( 'item_id', 0 );
222 + if ( $return == '' ) {
223 + return $course_id ? learn_press_get_course( $course_id ) : false;
224 + }
225 +
226 + return $course_id;
227 + }
228 +
229 + /**
230 + * Get result/processing course
231 + *
232 + * @param string $prop
233 + *
234 + * @return mixed
235 + */
236 + public function get_result( $prop = '' ) {
237 + $results = $this->calculate_course_results();
238 +
239 + // Fix temporary for case call 'grade' - addons called
240 + if ( 'grade' === $prop ) {
241 + if ( $results['pass'] ) {
242 + $results['grade'] = 'passed';
243 + } else {
244 + $results['grade'] = 'failed';
245 + }
246 + }
247 +
248 + return $prop && $results && array_key_exists( $prop, $results ) ? $results[ $prop ] : $results;
249 + }
250 +
251 + /**
252 + * Get current progress of course for an user.
253 + * Firstly, get data from cache if it is already loaded.
254 + * If data is not loaded to cache then get from meta data.
255 + * If meta data is not updated then calculate and update it
256 + *
257 + * @updated 3.1.0
258 + *
259 + * @param string $prop
260 + *
261 + * @return float|int
262 + */
263 + public function get_results( $prop = 'result' ) {
264 + $course = $this->get_course();
265 +
266 + if ( ! $course ) {
267 + return false;
268 + }
269 +
270 + $results = LP_Object_Cache::get(
271 + 'course-' . $this->get_item_id() . '-' . $this->get_user_id(),
272 + 'course-results'
273 + );
274 +
275 + if ( $results === false ) {
276 + $results = $this->calculate_course_results();
277 +
278 + LP_Object_Cache::set(
279 + 'course-' . $this->get_item_id() . '-' . $this->get_user_id(),
280 + $results,
281 + 'course-results'
282 + );
283 + }
284 +
285 + return $prop && $results && array_key_exists( $prop, $results ) ? $results[ $prop ] : $results;
286 + }
287 +
288 + /**
289 + * Calculate course result
290 + */
291 + public function calculate_course_results( bool $force_cache = false ) {
292 + $results = array(
293 + 'count_items' => 0,
294 + 'completed_items' => 0,
295 + 'items' => array(),
296 + 'evaluate_type' => '',
297 + 'pass' => 0,
298 + 'result' => 0,
299 + );
300 +
301 + try {
302 + $userCourseModel = UserCourseModel::find( $this->get_user_id(), $this->get_course_id(), true );
303 + if ( ! $userCourseModel instanceof UserCourseModel ) {
304 + return $results;
305 + }
306 +
307 + $results = $userCourseModel->calculate_course_results();
308 + } catch ( Throwable $e ) {
309 + LP_Debug::error_log( $e );
310 + }
311 +
312 + return $results;
313 +
314 + // Code old
315 + $items = array();
316 + $results = array(
317 + 'count_items' => 0,
318 + 'completed_items' => 0,
319 + 'items' => array(),
320 + 'evaluate_type' => '',
321 + 'pass' => 0,
322 + 'result' => 0,
323 + );
324 +
325 + try {
326 + $course = learn_press_get_course( $this->get_course_id() );
327 +
328 + if ( ! $course ) {
329 + throw new Exception( 'Course invalid!' );
330 + }
331 +
332 + $key_first_cache = 'calculate_course/' . $this->get_user_id() . '/' . $course->get_id();
333 + $results_cache = LP_Cache::cache_load_first( 'get', $key_first_cache );
334 + if ( false !== $results_cache && ! $force_cache ) {
335 + return $results_cache;
336 + }
337 +
338 + $this->_course = $course;
339 +
340 + if ( $this->is_finished() ) {
341 + // Get result from lp_user_item_results
342 + // Todo: tungnx - set cache
343 + return LP_User_Items_Result_DB::instance()->get_result( $this->get_user_item_id() );
344 + }
345 +
346 + if ( $this->get_status() !== LP_COURSE_ENROLLED ) {
347 + return $results;
348 + }
349 +
350 + $count_items = $course->count_items();
351 + $count_items_completed = $this->count_items_completed();
352 +
353 + $evaluate_type = get_post_meta( $course->get_id(), '_lp_course_result', true );
354 + if ( ! $evaluate_type ) {
355 + $evaluate_type = 'evaluate_lesson';
356 + }
357 + switch ( $evaluate_type ) {
358 + case 'evaluate_lesson':
359 + $results_evaluate = $this->evaluate_course_by_lesson( $count_items_completed, $course->count_items( LP_LESSON_CPT ) );
360 + break;
361 + case 'evaluate_final_quiz':
362 + $results_evaluate = $this->evaluate_course_by_final_quiz();
363 + break;
364 + case 'evaluate_quiz':
365 + $results_evaluate = $this->evaluate_course_by_quizzes_passed( $count_items_completed, $course->count_items( LP_QUIZ_CPT ) );
366 + break;
367 + case 'evaluate_questions':
368 + case 'evaluate_mark':
369 + $results_evaluate = $this->evaluate_course_by_question( $evaluate_type );
370 + break;
371 + default:
372 + $results_evaluate = apply_filters( 'learn-press/evaluate_passed_conditions', $results, $evaluate_type, $this );
373 + break;
374 + }
375 +
376 + if ( ! is_array( $results_evaluate ) ) {
377 + $results_evaluate = array(
378 + 'result' => 0,
379 + 'pass' => 0,
380 + );
381 + }
382 +
383 + $results_evaluate['result'] = round( $results_evaluate['result'], 2 );
384 +
385 + $completed_items = intval( $count_items_completed->count_status ?? 0 );
386 +
387 + $item_types = learn_press_get_course_item_types();
388 + foreach ( $item_types as $item_type ) {
389 + $item_type_key = str_replace( 'lp_', '', $item_type );
390 +
391 + $items[ $item_type_key ] = array(
392 + 'completed' => $count_items_completed->{$item_type . '_status_completed'} ?? 0,
393 + 'passed' => $count_items_completed->{$item_type . '_graduation_passed'} ?? 0,
394 + 'total' => $course->count_items( $item_type ),
395 + );
396 + }
397 +
398 + $results = array_merge(
399 + $results_evaluate,
400 + compact( 'count_items', 'completed_items', 'items', 'evaluate_type' )
401 + );
402 +
403 + $results = apply_filters(
404 + 'learn-press/update-course-results',
405 + $results,
406 + $this->get_item_id(),
407 + $this->get_user_id(),
408 + $this
409 + );
410 +
411 + LP_Cache::cache_load_first( 'set', $key_first_cache, $results );
412 + } catch ( Throwable $e ) {
413 + error_log( __METHOD__ . ': ' . $e->getMessage() );
414 + }
415 +
416 + return $results;
417 + }
418 +
419 + /**
420 + * Get graduation
421 + *
422 + * @param string $context
423 + *
424 + * @return string
425 + * @deprecated 4.1.6.9.3
426 + */
427 + public function get_grade( string $context = '' ): string {
428 + $grade = $this->get_graduation() ?? '';
429 +
430 + return $context == 'display' ? learn_press_course_grade_html( $grade, false ) : $grade;
431 + }
432 +
433 + /**
434 + * @param int $decimal
435 + *
436 + * @return int|string
437 + */
438 + public function get_percent_result( $decimal = 1 ) {
439 + return round( $this->get_result( 'result' ), $decimal );
440 + }
441 +
442 + /**
443 + * Evaluate course result by lessons.
444 + *
445 + * @param $count_items_completed
446 + * @param int $total_item_lesson
447 + *
448 + * @return array
449 + * @author tungnx
450 + * @since 4.1.4.1
451 + * @version 1.0.0
452 + */
453 + protected function evaluate_course_by_lesson( $count_items_completed, int $total_item_lesson = 0 ): array {
454 + $evaluate = array(
455 + 'result' => 0,
456 + 'pass' => 0,
457 + );
458 +
459 + $count_items_completed = intval( $count_items_completed->{LP_LESSON_CPT . '_status_completed'} ?? 0 );
460 +
461 + if ( $total_item_lesson && $count_items_completed ) {
462 + $evaluate['result'] = $count_items_completed * 100 / $total_item_lesson;
463 + }
464 +
465 + $passing_condition = $this->_course->get_passing_condition();
466 + if ( $evaluate['result'] >= $passing_condition ) {
467 + $evaluate['pass'] = 1;
468 + }
469 +
470 + return $evaluate;
471 + }
472 +
473 + /**
474 + * Evaluate course result by final quiz.
475 + *
476 + * @return array
477 + */
478 + protected function evaluate_course_by_final_quiz(): array {
479 + $lp_user_items_db = LP_User_Items_DB::getInstance();
480 + $lp_user_item_result_db = LP_User_Items_Result_DB::instance();
481 + $evaluate = array(
482 + 'result' => 0,
483 + 'pass' => 0,
484 + );
485 +
486 + try {
487 + $quiz_final_id = get_post_meta( $this->get_course_id(), '_lp_final_quiz', true );
488 +
489 + if ( ! $quiz_final_id ) {
490 + throw new Exception( '' );
491 + }
492 +
493 + $quiz_final = learn_press_get_quiz( $quiz_final_id );
494 +
495 + if ( ! $quiz_final ) {
496 + throw new Exception( 'Quiz final invalid' );
497 + }
498 +
499 + $user_course = $this->get_last_user_course();
500 +
501 + if ( ! $user_course ) {
502 + throw new Exception( 'User course not exists' );
503 + }
504 +
505 + $filter = new LP_User_Items_Filter();
506 + $filter->query_type = 'get_row';
507 + $filter->parent_id = $user_course->user_item_id;
508 + $filter->item_type = LP_QUIZ_CPT;
509 + $filter->item_id = $quiz_final_id;
510 + $user_quiz = $lp_user_items_db->get_user_course_items_by_item_type( $filter );
511 +
512 + if ( ! $user_quiz ) {
513 + throw new Exception();
514 + }
515 +
516 + // Get result did quiz
517 + $quiz_result = $lp_user_item_result_db->get_result( $user_quiz->user_item_id );
518 +
519 + if ( $quiz_result ) {
520 + if ( ! isset( $quiz_result['result'] ) ) {
521 + $evaluate['result'] = $quiz_result['user_mark'] * 100 / $quiz_result['mark'];
522 + } else {
523 + $evaluate['result'] = $quiz_result['result'];
524 + }
525 +
526 + $passing_condition = floatval( $quiz_final->get_data( 'passing_grade', 0 ) );
527 + if ( $evaluate['result'] >= $passing_condition ) {
528 + $evaluate['pass'] = 1;
529 + }
530 + }
531 + } catch ( Throwable $e ) {
532 +
533 + }
534 +
535 + return $evaluate;
536 + }
537 +
538 + /**
539 + * Evaluate course results by count quizzes passed/all quizzes.
540 + *
541 + * @author tungnx
542 + * @since 4.1.4.1
543 + * @version 1.0.0
544 + */
545 + protected function evaluate_course_by_quizzes_passed( $count_items_completed, $total_item_quizzes ): array {
546 + $evaluate = array(
547 + 'result' => 0,
548 + 'pass' => 0,
549 + );
550 +
551 + $count_items_completed = intval( $count_items_completed->{LP_QUIZ_CPT . '_graduation_passed'} ?? 0 );
552 +
553 + if ( $total_item_quizzes && $count_items_completed ) {
554 + $evaluate['result'] = $count_items_completed * 100 / $total_item_quizzes;
555 +
556 + $passing_condition = $this->_course->get_passing_condition();
557 + if ( $evaluate['result'] >= $passing_condition ) {
558 + $evaluate['pass'] = 1;
559 + }
560 + }
561 +
562 + return $evaluate;
563 + }
564 +
565 + /**
566 + * Evaluate course results by count questions true/all questions.
567 + *
568 + * @author tungnx
569 + * @since 4.1.4.1
570 + * @version 1.0.0
571 + */
572 + private function evaluate_course_by_questions( &$evaluate, $lp_quizzes, $total_questions ) {
573 + $lp_user_item_results_db = LP_User_Items_Result_DB::instance();
574 + $count_questions_correct = 0;
575 +
576 + // get questions correct
577 + foreach ( $lp_quizzes as $lp_quiz ) {
578 + $lp_quiz_result = $lp_user_item_results_db->get_result( $lp_quiz->user_item_id );
579 + if ( $lp_quiz_result ) {
580 + $count_questions_correct += $lp_quiz_result['question_correct'];
581 + }
582 + }
583 +
584 + if ( $total_questions && $count_questions_correct ) {
585 + $evaluate['result'] = $count_questions_correct * 100 / $total_questions;
586 +
587 + $passing_condition = $this->_course->get_passing_condition();
588 + if ( $evaluate['result'] >= $passing_condition ) {
589 + $evaluate['pass'] = 1;
590 + }
591 + }
592 + }
593 +
594 + /**
595 + * Evaluate course results by total mark of questions.
596 + *
597 + * @author tungnx
598 + * @since 4.1.4.1
599 + * @version 1.0.0
600 + */
601 + private function evaluate_course_by_mark( &$evaluate, $lp_quizzes, $total_mark_questions ) {
602 + $lp_user_item_results_db = LP_User_Items_Result_DB::instance();
603 + $count_mark_questions_receiver = 0;
604 +
605 + foreach ( $lp_quizzes as $lp_quiz ) {
606 + $lp_quiz_result = $lp_user_item_results_db->get_result( $lp_quiz->user_item_id );
607 + if ( $lp_quiz_result ) {
608 + $count_mark_questions_receiver += $lp_quiz_result['user_mark'];
609 + }
610 + }
611 +
612 + if ( $count_mark_questions_receiver && $total_mark_questions ) {
613 + $evaluate['result'] = $count_mark_questions_receiver * 100 / $total_mark_questions;
614 +
615 + $passing_condition = floatval( $this->_course->get_passing_condition() );
616 + if ( $evaluate['result'] >= $passing_condition ) {
617 + $evaluate['pass'] = 1;
618 + }
619 + }
620 + }
621 +
622 + /**
623 + * Evaluate course results by total mark of questions.
624 + *
625 + * @author tungnx
626 + * @since 4.1.4.1
627 + * @version 1.0.0
628 + */
629 + protected function evaluate_course_by_question( string $evaluate_type ): array {
630 + $lp_user_items_db = LP_User_Items_DB::getInstance();
631 + $evaluate = array(
632 + 'result' => 0,
633 + 'pass' => 0,
634 + );
635 +
636 + try {
637 + $user_course = $this->get_last_user_course();
638 +
639 + if ( ! $user_course ) {
640 + throw new Exception( 'User course not exists!' );
641 + }
642 +
643 + // get quiz_ids
644 + $filter_get_quiz_ids = new LP_User_Items_Filter();
645 + $filter_get_quiz_ids->parent_id = $user_course->user_item_id;
646 + $filter_get_quiz_ids->item_type = LP_QUIZ_CPT;
647 + $lp_quizzes = $lp_user_items_db->get_user_course_items_by_item_type( $filter_get_quiz_ids );
648 +
649 + // Get total questions, mark
650 + // Todo: Tungnx - save (questions, mark) total when save quiz, course, if not query again
651 + $course = $this->_course;
652 + if ( is_int( $course ) ) {
653 + $course = learn_press_get_course( $course );
654 + }
655 +
656 + $total_questions = 0;
657 + $total_mark_question = 0;
658 +
659 + // Get all items' course
660 + $sections_items = $course->get_full_sections_and_items_course();
661 +
662 + foreach ( $sections_items as $section_items ) {
663 + foreach ( $section_items->items as $item ) {
664 + $itemObj = $course->get_item( $item->id );
665 +
666 + if ( ! $itemObj instanceof LP_Course_Item ) {
667 + continue;
668 + }
669 +
670 + if ( $item->type == LP_QUIZ_CPT ) {
671 + $total_questions += count( $itemObj->get_question_ids() );
672 + $total_mark_question += $itemObj->get_mark();
673 + }
674 + }
675 + }
676 + // End get total questions, mark
677 +
678 + switch ( $evaluate_type ) {
679 + case 'evaluate_questions':
680 + $this->evaluate_course_by_questions( $evaluate, $lp_quizzes, $total_questions );
681 + break;
682 + case 'evaluate_mark':
683 + $this->evaluate_course_by_mark( $evaluate, $lp_quizzes, $total_mark_question );
684 + break;
685 + default:
686 + break;
687 + }
688 +
689 + // Get results of each quiz - has questions
690 + } catch ( Throwable $e ) {
691 + error_log( __FUNCTION__ . ': ' . $e->getMessage() );
692 + }
693 +
694 + return $evaluate;
695 + }
696 +
697 + /**
698 + * Check course of use has enrolled
699 + */
700 + public function is_enrolled(): bool {
701 + return $this->get_status() == LP_COURSE_ENROLLED;
702 + }
703 +
704 + /**
705 + * Check course of use has purchased
706 + * @author tungnx
707 + * @since 4.1.3
708 + * @version 1.0.0
709 + */
710 + public function is_purchased(): bool {
711 + return $this->get_status() == LP_COURSE_PURCHASED;
712 + }
713 +
714 + public function get_level() {
715 + if ( ! $this->is_exists() ) {
716 + return 0;
717 + }
718 +
719 + $level = 10;
720 +
721 + switch ( $this->get_status() ) {
722 + case 'enrolled':
723 + $level = 20;
724 + break;
725 + case 'finished':
726 + $level = 30;
727 + break;
728 +
729 + }
730 +
731 + return $level;
732 + }
733 +
734 + /**
735 + * @deprecated 4.1.6.9.2
736 + */
737 + /*protected function _is_passed( $result ) {
738 + $is_passed = LP_COURSE_GRADUATION_FAILED;
739 + $result = round( $result, 2 );
740 +
741 + if ( $result >= $this->get_passing_condition() ) {
742 + $is_passed = LP_COURSE_GRADUATION_PASSED;
743 + }
744 +
745 + return apply_filters( 'learnpress/user/course/is-passed', $is_passed, $result );
746 + }*/
747 +
748 + /**
749 + * Get completed items.
750 + *
751 + * @param string $type - Optional. Filter by type (such lp_quiz, lp_lesson) if passed
752 + * @param bool $with_total - Optional. Include total if TRUE
753 + * @param int $section_id - Optional. Get in specific section
754 + *
755 + * @return array|bool|mixed
756 + * @editor tungnx
757 + */
758 + public function get_completed_items( $type = '', $with_total = false, $section_id = 0 ) {
759 +
760 + $this->read_items();
761 +
762 + // $completed_items = array(0,100);
763 + // return $with_total ? $completed_items : $completed_items[0];
764 +
765 + if ( ! $this->_course ) {
766 + return 0;
767 + }
768 +
769 + $key = sprintf(
770 + '%d-%d-%s',
771 + $this->get_user_id(),
772 + $this->_course->get_id(),
773 + md5( build_query( func_get_args() ) )
774 + );
775 +
776 + $completed_items = LP_Object_Cache::get( $key, 'learn-press/user-completed-items' );
777 +
778 + if ( false === $completed_items ) {
779 + $completed = 0;
780 + $total = 0;
781 + $section_items = array();
782 +
783 + if ( $section_id ) {
784 + $section = $this->_course->get_sections( 'object', $section_id );
785 +
786 + if ( $section ) {
787 + $section_items = $section->get_items();
788 +
789 + if ( $section_items ) {
790 + $section_items = array_keys( $section_items );
791 + }
792 + }
793 + }
794 +
795 + $items = $this->get_items();
796 + if ( $items ) {
797 + foreach ( $items as $item ) {
798 +
799 + if ( $section_id && ! in_array( $item->get_id(), $section_items ) ) {
800 + continue;
801 + }
802 +
803 + if ( $type ) {
804 + $item_type = $item->get_data( 'item_type' );
805 + } else {
806 + $item_type = '';
807 + }
808 +
809 + if ( $type === $item_type ) {
810 + if ( $item->get_status() == 'completed' ) {
811 + ++$completed;
812 + }
813 + $completed = apply_filters(
814 + 'learn-press/course-item/completed',
815 + $completed,
816 + $item,
817 + $item->get_status()
818 + );
819 + // if ( ! $item->is_preview() ) {
820 + ++$total;
821 + // }
822 + }
823 + }
824 + }
825 + $completed_items = array( $completed, $total );
826 + LP_Object_Cache::set( $key, $completed_items, 'learn-press/user-completed-items' );
827 + }
828 +
829 + return $with_total ? $completed_items : $completed_items[0];
830 + }
831 +
832 + /**
833 + * Get completed items.
834 + *
835 + * @return object
836 + * @editor tungnx
837 + * @modify 4.1.4.1
838 + * @since 4.0.0
839 + * @version 4.0.1
840 + */
841 + public function count_items_completed() {
842 + $lp_user_items_db = LP_User_Items_DB::getInstance();
843 + $count_items_completed = new stdClass();
844 +
845 + try {
846 + $course = learn_press_get_course( $this->get_course_id() );
847 + if ( ! $course ) {
848 + throw new Exception( 'Course is invalid!' );
849 + }
850 +
851 + $user_course = $this->get_last_user_course();
852 + if ( ! $user_course ) {
853 + throw new Exception( 'User course is invalid!' );
854 + }
855 +
856 + $filter_count = new LP_User_Items_Filter();
857 + $filter_count->parent_id = $user_course->user_item_id;
858 + $filter_count->item_id = $this->get_course_id();
859 + $filter_count->user_id = $this->get_user_id();
860 + $filter_count->status = 'completed';
861 + $filter_count->graduation = LP_COURSE_GRADUATION_PASSED;
862 + $count_items_completed = $lp_user_items_db->count_items_of_course_with_status( $filter_count );
863 + } catch ( Throwable $e ) {
864 + error_log( __METHOD__ . ': ' . $e->getMessage() );
865 + }
866 +
867 + return $count_items_completed;
868 + }
869 +
870 + /**
871 + * Get items completed by percentage.
872 + *
873 + * @param string $type - Optional. Filter by type or not
874 + * @param int $section_id - Optional. Get in specific section
875 + *
876 + * @return float|int
877 + */
878 + public function get_percent_completed_items( $type = '', $section_id = 0 ) {
879 + $values = $this->get_completed_items( $type, true, $section_id );
880 + if ( $values[1] ) {
881 + return $values[0] / $values[1] * 100;
882 + }
883 +
884 + return 0;
885 + }
886 +
887 + /**
888 + * Get passing condition criteria.
889 + *
890 + * @return string
891 + */
892 + public function get_passing_condition() {
893 + return $this->_course->get_passing_condition();
894 + }
895 +
896 + /**
897 + * Get all items in course.
898 + *
899 + * @param bool $refresh
900 + *
901 + * @return LP_User_Item[]
902 + */
903 + public function get_items( $refresh = false ) {
904 + return $this->read_items();
905 +
906 + /*
907 + return LP_Object_Cache::get(
908 + $this->get_user_id() . '-' . $this->get_id(),
909 + 'learn-press/user-course-item-objects'
910 + );*/
911 + }
912 +
913 + /**
914 + * Check course is completed or not.
915 + *
916 + * @return bool
917 + * @editor tungnx
918 + * @modify 4.1.3
919 + */
920 + public function is_finished(): bool {
921 + return $this->get_status() == LP_COURSE_FINISHED;
922 + }
923 +
924 + /**
925 + * Check course graduation is passed or not.
926 + *
927 + * @return bool
928 + */
929 + public function is_graduated() {
930 + return $this->get_graduation();
931 + }
932 +
933 + /**
934 + * @return bool
935 + * @deprecated 4.1.6.9.2
936 + */
937 + /*public function can_graduated() {
938 + return $this->get_results( 'result' ) >= $this->get_passing_condition();
939 + }*/
940 +
941 + function __destruct() {
942 + // TODO: Implement __unset() method.
943 + }
944 +
945 + /**
946 + * Get item user attend on course by item_id.
947 + *
948 + * @param int $item_id
949 + *
950 + * @return bool|LP_User_Item
951 + * @editor tungnx
952 + * @modify 4.1.6.9
953 + * @since 3.0.0
954 + * @version 4.0.1
955 + */
956 + public function get_item( $item_id ) {
957 + $item = false;
958 +
959 + try {
960 + $filter = new LP_User_Items_Filter();
961 + $filter->item_id = $item_id;
962 + $filter->ref_id = $this->get_course_id();
963 + $filter->user_id = $this->get_user();
964 + $item_result = LP_User_Items_DB::getInstance()->get_user_course_item( $filter );
965 +
966 + if ( $item_result ) {
967 + $item_result = (array) $item_result;
968 + $item = LP_User_Item::get_item_object( $item_result );
969 + }
970 + } catch ( Throwable $e ) {
971 + error_log( $e->getMessage() );
972 + }
973 +
974 + return $item;
975 + }
976 +
977 + /**
978 + * @param $item_id
979 + * @param string $prop
980 + *
981 + * @return bool|float|int
982 + * @throws Exception
983 + */
984 + public function get_item_result( $item_id, $prop = 'result' ) {
985 + $item = $this->get_item( $item_id );
986 +
987 + if ( $item instanceof LP_User_Item_Quiz ) {
988 + /**
989 + * @var LP_User_Item_Quiz $item
990 + */
991 + return $item->get_graduation();
992 + } elseif ( $item ) {
993 + return $item->get_result( $prop );
994 + }
995 +
996 + return false;
997 + }
998 +
999 + /**
1000 + * @param $id
1001 + *
1002 + * @return LP_User_Item_Quiz|bool
1003 + */
1004 + public function get_item_quiz( $id ) {
1005 +
1006 + return $this->get_item( $id );
1007 + }
1008 +
1009 + /**
1010 + * Get number of retaken times for user course.
1011 + *
1012 + * @return int
1013 + */
1014 + public function get_retaken_count(): int {
1015 + return (int) ( learn_press_get_user_item_meta( $this->get_user_item_id(), '_lp_retaken_count' ) );
1016 + }
1017 +
1018 + /**
1019 + * Increase retaken count.
1020 + *
1021 + * @return bool|int
1022 + */
1023 + public function increase_retake_count() {
1024 + $count = $this->get_retaken_count();
1025 + ++$count;
1026 +
1027 + return $this->update_meta( '_lp_retaken_count', $count );
1028 + }
1029 +
1030 + /**
1031 + * Update course item and it's child.
1032 + *
1033 + * @TODO: tungnx - review to modify
1034 + * @deprecated 4.1.7.3
1035 + */
1036 + public function save() {
1037 + _deprecated_function( __METHOD__, '4.1.7.3' );
1038 + /**
1039 + * @var LP_User_Item $item
1040 + */
1041 + $this->update();
1042 + $items = $this->get_items();
1043 + if ( ! $items ) {
1044 + return false;
1045 + }
1046 +
1047 + foreach ( $items as $item_id => $item ) {
1048 + if ( ! $item->get_status() ) {
1049 + continue;
1050 + }
1051 +
1052 + /**
1053 + * Autofill the end-time if it isn't already set
1054 + */
1055 + if ( in_array( $item->get_status(), array( 'completed', 'finished' ) ) ) {
1056 + if ( ! $item->get_end_time() || $item->get_end_time()->is_null() ) {
1057 + $item->set_end_time( current_time( 'mysql', 1 ) );
1058 + }
1059 + }
1060 +
1061 + $item->update();
1062 + }
1063 +
1064 + return true;
1065 + }
1066 +
1067 + /**
1068 + * Get passed items.
1069 + *
1070 + * @param string $type - Optional. Filter by type (such lp_quiz, lp_lesson) if passed
1071 + * @param bool $with_total - Optional. Include total if TRUE
1072 + * @param int $section_id - Optional. Get in specific section
1073 + *
1074 + * @return array|bool|mixed
1075 + * @deprecated 4.1.6.9
1076 + */
1077 + public function get_passed_items( $type = '', $with_total = false, $section_id = 0 ) {
1078 + _deprecated_function( __FUNCTION__, '4.1.6.9' );
1079 + $this->read_items();
1080 +
1081 + $key = sprintf(
1082 + '%d-%d-%s',
1083 + $this->get_user_id(),
1084 + $this->_course->get_id(),
1085 + md5( build_query( func_get_args() ) )
1086 + );
1087 + $passed_items = LP_Object_Cache::get( $key, 'learn-press/user-passed-items' );
1088 +
1089 + if ( false === $passed_items ) {
1090 + $passed = 0;
1091 + $total = 0;
1092 + $section_items = array();
1093 +
1094 + $section = $this->_course->get_sections( 'object', $section_id );
1095 +
1096 + if ( $section_id && $section ) {
1097 + $section_items = $section->get_items();
1098 +
1099 + if ( $section_items ) {
1100 + $section_items = array_keys( $section_items );
1101 + }
1102 + }
1103 +
1104 + $items = $this->get_items();
1105 +
1106 + if ( $items ) {
1107 + foreach ( $items as $item ) {
1108 +
1109 + if ( $section_id && ! in_array( $item->get_id(), $section_items ) ) {
1110 + continue;
1111 + }
1112 +
1113 + if ( $type ) {
1114 + $item_type = $item->get_data( 'item_type' );
1115 + } else {
1116 + $item_type = '';
1117 + }
1118 +
1119 + if ( $type === $item_type ) {
1120 + if ( $item->get_status( 'graduation' ) == 'passed' ) {
1121 + ++$passed;
1122 + }
1123 + $passed = apply_filters(
1124 + 'learn-press/course-item/passed',
1125 + $passed,
1126 + $item,
1127 + $item->get_status()
1128 + );
1129 + // if ( ! $item->is_preview() ) {
1130 + ++$total;
1131 + // }
1132 + }
1133 + }
1134 + }
1135 + $passed_items = array( $passed, $total );
1136 + LP_Object_Cache::set( $key, $passed_items, 'learn-press/user-passed-items' );
1137 + }
1138 +
1139 + return $with_total ? $passed_items : $passed_items[0];
1140 + }
1141 +
1142 + /**
1143 + * Get Order ID
1144 + *
1145 + * @return array|mixed
1146 + * @since 4.1.3
1147 + * @version 1.0.0
1148 + * @author tungnx
1149 + */
1150 + public function get_order_id() {
1151 + return $this->get_data( 'ref_id', 0 );
1152 + }
1153 +
1154 + /**
1155 + * Get Order
1156 + *
1157 + * @throws Exception
1158 + * @since 4.1.3
1159 + * @version 1.0.0
1160 + * @author tungnx
1161 + */
1162 + public function get_order() {
1163 + $order = false;
1164 +
1165 + if ( $this->get_order_id() ) {
1166 + $order = new LP_Order( $this->get_order_id() );
1167 + }
1168 +
1169 + return $order;
1170 + }
1171 +
1172 + /**
1173 + * Get child item ids by type item
1174 + *
1175 + * @return object|null
1176 + */
1177 + public function get_last_user_course() {
1178 + $lp_user_items_db = LP_User_Items_DB::getInstance();
1179 + $user_course = null;
1180 +
1181 + try {
1182 + $filter_user_course = new LP_User_Items_Filter();
1183 + $filter_user_course->item_id = $this->get_course_id();
1184 + $filter_user_course->user_id = $this->get_user_id();
1185 + $user_course = $lp_user_items_db->get_last_user_course( $filter_user_course );
1186 + } catch ( Throwable $e ) {
1187 + error_log( __FUNCTION__ . ':' . $e->getMessage() );
1188 + }
1189 +
1190 + return $user_course;
1191 + }
1192 +
1193 + /**
1194 + * Get courses only by course's user are learning
1195 + *
1196 + * @param LP_User_Items_Filter|UserItemsFilter $filter
1197 + * @param int $total_rows return total row query
1198 + *
1199 + * @return array|null|int|string
1200 + */
1201 + public static function get_user_courses( $filter, int &$total_rows = 0 ) {
1202 + try {
1203 + /*$key_cache = md5( json_encode( $filter ) );
1204 + $courses_cache = LP_Cache::instance()->get_cache( $key_cache );
1205 +
1206 + if ( false !== $courses_cache ) {
1207 + return $courses_cache;
1208 + }*/
1209 +
1210 + $courses = LP_User_Items_DB::getInstance()->get_user_courses( $filter, $total_rows );
1211 + //LP_Cache::instance()->set_cache( $key_cache, $courses );
1212 + } catch ( Throwable $e ) {
1213 + $courses = null;
1214 + error_log( __FUNCTION__ . ': ' . $e->getMessage() );
1215 + }
1216 +
1217 + return $courses;
1218 + }
1219 +}