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/Models/UserItems/UserItemModel.php +657 -597 4.3.9.14.4.8 View file →
@@ -1,597 +1,657 @@
1 -<?php
2 -
3 -/**
4 - * Class UserItemModel
5 - * To replace class LP_User_Item
6 - *
7 - * @package LearnPress/Classes
8 - * @version 1.0.3
9 - * @since 4.2.5
10 - */
11 -
12 -namespace LearnPress\Models\UserItems;
13 -
14 -use Exception;
15 -use LearnPress\Filters\UserItemsFilter;
16 -use LearnPress\Models\CoursePostModel;
17 -use LearnPress\Models\PostModel;
18 -use LearnPress\Models\UserItemMeta\UserItemMetaModel;
19 -use LearnPress\Models\UserModel;
20 -use LP_Datetime;
21 -use LP_User_Item_Meta_DB;
22 -use LP_User_Item_Meta_Filter;
23 -use LP_User_Items_Cache;
24 -use LP_User_Items_DB;
25 -use LP_User_Items_Filter;
26 -use stdClass;
27 -use Throwable;
28 -
29 -class UserItemModel {
30 - /**
31 - * Auto increment, Primary key
32 - *
33 - * @var int
34 - */
35 - private $user_item_id = 0;
36 - /**
37 - * @var string User ID, foreign key
38 - */
39 - public $user_id = 0;
40 - /**
41 - * Item id (course, lesson, quiz ...)
42 - *
43 - * @var string foreign key
44 - */
45 - public $item_id = 0;
46 - /**
47 - * @var string Time start item
48 - */
49 - public $start_time = null;
50 - /**
51 - * @var string Time finish item
52 - */
53 - public $end_time = null;
54 - /**
55 - * Item type (course, lesson, quiz ...)
56 - *
57 - * @var string Item type
58 - */
59 - public $item_type = '';
60 - /**
61 - * Item status (completed, enrolled, finished ...)
62 - *
63 - * @var string
64 - */
65 - public $status = '';
66 - /**
67 - * Item graduation
68 - *
69 - * @var string (passed, failed, in-progress...)
70 - */
71 - public $graduation = null;
72 - /**
73 - * Ref id (Order, course ...)
74 - *
75 - * @var int Reference id
76 - */
77 - public $ref_id = 0;
78 - /**
79 - * Ref type (Order, course ...)
80 - *
81 - * @var string
82 - */
83 - public $ref_type = '';
84 - /**
85 - * Parent id
86 - *
87 - * @var int
88 - */
89 - public $parent_id = 0;
90 - /**
91 - * @var null|PostModel|CoursePostModel
92 - */
93 - public $item;
94 - /**
95 - * List UserItemMetaModel
96 - * object {meta_key: {meta_id, learnpress_user_item_id, meta_key, meta_value, extra_value}}
97 - *
98 - * @var {meta_key: UserItemMetaModel}
99 - */
100 - public $meta_data;
101 -
102 - // Constants
103 - const STATUS_COMPLETED = 'completed';
104 - const STATUS_FINISHED = 'finished';
105 - const STATUS_ENROLLED = 'enrolled';
106 - const STATUS_PURCHASED = 'purchased';
107 - const STATUS_CANCEL = 'cancel';
108 - const GRADUATION_IN_PROGRESS = 'in-progress';
109 - const GRADUATION_PASSED = 'passed';
110 - const GRADUATION_FAILED = 'failed';
111 -
112 - /**
113 - * If data get from database, map to object.
114 - * Else create new object to save data to database.
115 - *
116 - * @param array|object|mixed $data
117 - */
118 - public function __construct( $data = null ) {
119 - if ( $data ) {
120 - $this->map_to_object( $data );
121 - $this->get_user_model();
122 - }
123 -
124 - if ( ! $this->meta_data instanceof stdClass ) {
125 - $this->meta_data = new stdClass();
126 - }
127 - }
128 -
129 - /**
130 - * Get start time
131 - *
132 - * @return string
133 - */
134 - public function get_start_time(): string {
135 - return is_null( $this->start_time ) ? '' : $this->start_time;
136 - }
137 -
138 - /**
139 - * Get end time
140 - *
141 - * @return string
142 - */
143 - public function get_end_time(): string {
144 - return is_null( $this->end_time ) ? '' : $this->end_time;
145 - }
146 -
147 - /**
148 - * Get status
149 - *
150 - * @return string
151 - */
152 - public function get_status(): string {
153 - return $this->status;
154 - }
155 -
156 - /**
157 - * Get graduation
158 - *
159 - * @return string
160 - */
161 - public function get_graduation(): string {
162 - return is_null( $this->graduation ) ? '' : $this->graduation;
163 - }
164 -
165 -
166 - /**
167 - * Get user item id
168 - *
169 - * @return int
170 - */
171 - public function get_user_item_id(): int {
172 - return $this->user_item_id;
173 - }
174 -
175 - /**
176 - * Set user item id
177 - *
178 - * @param int $user_item_id
179 - */
180 - private function set_user_item_id( int $user_item_id ) {
181 - $this->user_item_id = $user_item_id;
182 - }
183 -
184 - /**
185 - * Get user model
186 - *
187 - * @return false|UserModel
188 - * @since 4.2.6
189 - * @version 1.0.1
190 - */
191 - public function get_user_model() {
192 - return UserModel::find( $this->user_id, true );
193 - }
194 -
195 - /**
196 - * Map array, object data to UserItemModel.
197 - * Use for data get from database.
198 - *
199 - * @param array|object|mixed $data
200 - *
201 - * @return UserItemModel
202 - */
203 - public function map_to_object( $data ): UserItemModel {
204 - foreach ( $data as $key => $value ) {
205 - if ( property_exists( $this, $key ) ) {
206 - $this->{$key} = $value;
207 - }
208 - }
209 -
210 - return $this;
211 - }
212 -
213 - /**
214 - * Get user item from database by user_id, item_id, item_type.
215 - * If not exists, return false.
216 - * If exists, return UserItemModel.
217 - *
218 - * @param LP_User_Items_Filter|UserItemsFilter $filter
219 - *
220 - * @return UserItemModel|false|static
221 - * @since 4.2.5
222 - * @version 1.0.2
223 - */
224 - public static function get_user_item_model_from_db( $filter ) {
225 - $lp_user_item_db = LP_User_Items_DB::getInstance();
226 - $user_item_model = false;
227 -
228 - try {
229 - // Set order by user_item_id DESC to get the latest user item.
230 - $filter->order = $filter::ORDER_DESC;
231 - $filter->order_by = $filter::COL_USER_ITEM_ID;
232 - if ( empty( $filter->item_type ) ) {
233 - $filter->item_type = ( new static() )->item_type;
234 - }
235 -
236 - $lp_user_item_db->get_query_single_row( $filter );
237 - $query_single_row = $lp_user_item_db->get_user_items( $filter );
238 - $user_item_rs = $lp_user_item_db->wpdb->get_row( $query_single_row );
239 - if ( $user_item_rs instanceof stdClass ) {
240 - $user_item_model = new static( $user_item_rs );
241 - }
242 - } catch ( Throwable $e ) {
243 - error_log( __METHOD__ . ': ' . $e->getMessage() );
244 - }
245 -
246 - return $user_item_model;
247 - }
248 -
249 - /**
250 - * Find User Item by user_id, item_id, item_type.
251 - *
252 - * @param int $user_id
253 - * @param int $item_id
254 - * @param string $item_type
255 - * @param int $ref_id
256 - * @param string $ref_type
257 - * @param bool $check_cache
258 - *
259 - * @return false|UserItemModel|static
260 - * @since 4.2.7.3
261 - * @version 1.0.2
262 - */
263 - public static function find_user_item(
264 - int $user_id,
265 - int $item_id,
266 - string $item_type,
267 - int $ref_id = 0,
268 - string $ref_type = '',
269 - bool $check_cache = false
270 - ) {
271 - $key_cache = "userItemModel/find/{$user_id}/{$item_id}/{$item_type}";
272 - $filter = new LP_User_Items_Filter();
273 - $filter->user_id = $user_id;
274 - $filter->item_id = $item_id;
275 - $filter->item_type = $item_type;
276 - if ( ! empty( $ref_id ) ) {
277 - $filter->ref_id = $ref_id;
278 - $key_cache .= "/{$ref_id}";
279 - }
280 - if ( ! empty( $ref_type ) ) {
281 - $filter->ref_type = $ref_type;
282 - $key_cache .= "/{$ref_type}";
283 - }
284 - $lpUserItemCache = new LP_User_Items_Cache();
285 -
286 - // Check cache
287 - if ( $check_cache ) {
288 - $userItemModel = $lpUserItemCache->get_cache( $key_cache );
289 - if ( $userItemModel instanceof UserItemModel ) {
290 - return new static( $userItemModel );
291 - }
292 - }
293 -
294 - $userItemModel = static::get_user_item_model_from_db( $filter );
295 - // Set cache
296 - if ( $userItemModel instanceof UserItemModel ) {
297 - if ( ! $userItemModel->meta_data instanceof stdClass ) {
298 - $userItemModel->meta_data = new stdClass();
299 - }
300 -
301 - $lpUserItemCache->set_cache( $key_cache, $userItemModel );
302 - }
303 -
304 - return $userItemModel;
305 - }
306 -
307 - /**
308 - * Get user item metadata from object meta_data or database by user_item_id, meta_key.
309 - *
310 - * @param string $key
311 - *
312 - * @return false|UserItemMetaModel
313 - * @since 4.2.5
314 - * @version 1.0.1
315 - */
316 - public function get_meta_model_from_key( string $key ) {
317 - $filter = new LP_User_Item_Meta_Filter();
318 - $filter->meta_key = $key;
319 - $filter->learnpress_user_item_id = $this->get_user_item_id();
320 -
321 - return UserItemMetaModel::get_user_item_meta_model_from_db( $filter );
322 - }
323 -
324 - /**
325 - * Get metadata from key
326 - *
327 - * @param string $key
328 - * @param mixed $default_value
329 - * @param bool $get_extra
330 - *
331 - * @return false|string
332 - * @since 4.2.5
333 - * @version 1.0.3
334 - */
335 - public function get_meta_value_from_key( string $key, $default_value = false, bool $get_extra = false ) {
336 - if ( $this->meta_data instanceof stdClass && isset( $this->meta_data->{$key} ) ) {
337 - return maybe_unserialize( $this->meta_data->{$key} );
338 - }
339 -
340 - $user_item_metadata = $this->get_meta_model_from_key( $key );
341 - if ( $user_item_metadata instanceof UserItemMetaModel ) {
342 - if ( ! $this->meta_data instanceof stdClass ) {
343 - $this->meta_data = new stdClass();
344 - }
345 -
346 - if ( $get_extra ) {
347 - $data = $user_item_metadata->extra_value;
348 - } else {
349 - $data = $user_item_metadata->meta_value;
350 - }
351 -
352 - $this->meta_data->{$key} = maybe_unserialize( $data );
353 - } else {
354 - $data = $default_value;
355 - }
356 -
357 - return $data;
358 - }
359 -
360 - /**
361 - * Update meta value for key.
362 - *
363 - * @param string $key
364 - * @param mixed $value
365 - * @param bool $is_extra
366 - *
367 - * @return void
368 - * @since 4.2.7.4
369 - * @version 1.0.0
370 - */
371 - public function set_meta_value_for_key( string $key, $value, bool $is_extra = false ) {
372 - if ( ! $this->meta_data instanceof stdClass ) {
373 - $this->meta_data = new stdClass();
374 - }
375 -
376 - $this->meta_data->{$key} = $value;
377 - $lp_db = LP_User_Items_DB::getInstance();
378 - if ( $is_extra ) {
379 - if ( is_object( $value ) || is_array( $value ) ) {
380 - $value = json_encode( $value );
381 - }
382 - $lp_db->update_extra_value( $this->get_user_item_id(), $key, $value );
383 - } else {
384 - learn_press_update_user_item_meta( $this->get_user_item_id(), $key, $value );
385 - }
386 -
387 - //$this->clean_caches();
388 - }
389 -
390 - /**
391 - * Delete meta from key.
392 - *
393 - * @param string $key
394 - *
395 - * @return void
396 - * @since 4.2.7.4
397 - * @version 1.0.0
398 - */
399 - public function delete_meta( string $key ) {
400 - $user_item_metadata = $this->get_meta_model_from_key( $key );
401 - if ( $user_item_metadata instanceof UserItemMetaModel ) {
402 - $user_item_metadata->delete();
403 - $this->meta_data->{$key} = null;
404 - $this->clean_caches();
405 - }
406 - }
407 -
408 - /**
409 - * Update data to database.
410 - *
411 - * If user_item_id is empty, insert new data, else update data.
412 - *
413 - * @return UserItemModel
414 - * @throws Exception
415 - * @since 4.2.5
416 - * @version 1.0.3
417 - */
418 - public function save(): UserItemModel {
419 - $lp_user_item_db = LP_User_Items_DB::getInstance();
420 - $user_item_id_new = 0;
421 - $data = get_object_vars( $this );
422 -
423 - if ( ! isset( $data['start_time'] ) ) {
424 - $data['start_time'] = gmdate( 'Y-m-d H:i:s', time() );
425 - $this->start_time = $data['start_time'];
426 - }
427 -
428 - // Check if exists user_item_id.
429 - if ( empty( $this->get_user_item_id() ) ) { // Insert data.
430 - if ( empty( $data['item_id'] ) ) {
431 - throw new Exception( 'Item ID is require.' );
432 - }
433 - if ( empty( $data['item_type'] ) ) {
434 - throw new Exception( 'Item Type is require.' );
435 - }
436 -
437 - // Guest can buy course if enable guest checkout.
438 - if ( empty( $data['user_id'] ) && LP_COURSE_CPT !== $data['item_type'] ) {
439 - throw new Exception( 'User ID is require.' );
440 - }
441 -
442 - $user_item_id_new = $lp_user_item_db->insert_data( $data );
443 - if ( empty( $user_item_id_new ) ) {
444 - throw new Exception( 'Cannot insert data to database.' );
445 - }
446 - } else { // Update data.
447 - $lp_user_item_db->update_data( $data );
448 - }
449 -
450 - if ( $user_item_id_new ) {
451 - $this->set_user_item_id( $user_item_id_new );
452 - }
453 -
454 - // Clear caches.
455 - $this->clean_caches();
456 -
457 - return $this;
458 - }
459 -
460 - /**
461 - * Get total timestamp complete, done item.
462 - *
463 - * @return int
464 - */
465 - public function get_total_timestamp_completed(): int {
466 - $time_interval = 0;
467 -
468 - if ( empty( $this->get_start_time() ) || empty( $this->get_end_time() ) ) {
469 - return $time_interval;
470 - }
471 -
472 - $start = new LP_Datetime( $this->get_start_time() );
473 - $end = new LP_Datetime( $this->get_end_time() );
474 -
475 - return $end->getTimestamp() - $start->getTimestamp();
476 - }
477 -
478 - /**
479 - * Get expiration time.
480 - *
481 - * @return null|LP_Datetime $time
482 - * @since 3.3.0
483 - * @version 3.3.3
484 - */
485 - public function get_expiration_time() {
486 - $duration = get_post_meta( $this->item_id, '_lp_duration', true );
487 -
488 - if ( ! absint( $duration ) || empty( $this->start_time ) ) {
489 - $expire = null;
490 - } else {
491 - $start = new LP_Datetime( $this->start_time );
492 - $start_time = $start->getTimestamp();
493 - // Convert duration from string to seconds.
494 - if ( ! is_numeric( $duration ) ) {
495 - $duration = strtotime( $duration ) - time();
496 - }
497 -
498 - $expire_time = $start_time + $duration;
499 - $expire = new LP_Datetime( $expire_time );
500 - }
501 -
502 - return apply_filters( 'learnPress/user-item/expiration-time', $expire, $duration, $this );
503 - }
504 -
505 - /**
506 - * Get translate value.
507 - *
508 - * @param string $value
509 - *
510 - * @return string
511 - * @since 4.2.7.8
512 - * @version 1.0.0
513 - */
514 - public function get_string_i18n( string $value ): string {
515 - switch ( $value ) {
516 - case self::STATUS_COMPLETED:
517 - $value = __( 'Completed', 'learnpress' );
518 - break;
519 - case self::STATUS_FINISHED:
520 - $value = __( 'Finished', 'learnpress' );
521 - break;
522 - case self::STATUS_ENROLLED:
523 - $value = __( 'Enrolled', 'learnpress' );
524 - break;
525 - case self::STATUS_CANCEL:
526 - $value = __( 'Cancel', 'learnpress' );
527 - break;
528 - case self::GRADUATION_IN_PROGRESS:
529 - $value = __( 'In Progress', 'learnpress' );
530 - break;
531 - case self::GRADUATION_PASSED:
532 - $value = __( 'Passed', 'learnpress' );
533 - break;
534 - case self::GRADUATION_FAILED:
535 - $value = __( 'Failed', 'learnpress' );
536 - break;
537 - }
538 -
539 - return $value;
540 - }
541 -
542 - /**
543 - * Delete user item.
544 - *
545 - * @throws Exception
546 - * @since 4.2.7.3
547 - * @version 1.0.2
548 - */
549 - public function delete() {
550 - // Delete meta data of user item.
551 - $lp_user_item_meta_db = LP_User_Item_Meta_DB::getInstance();
552 - $filter = new LP_User_Item_Meta_Filter();
553 - $filter->where[] = $lp_user_item_meta_db->wpdb->prepare( 'AND learnpress_user_item_id = %d', $this->get_user_item_id() );
554 - $filter->collection = $lp_user_item_meta_db->tb_lp_user_itemmeta;
555 - $lp_user_item_meta_db->delete_execute( $filter );
556 - $this->meta_data = null;
557 -
558 - // Delete user item relationships.
559 - $lp_user_item_db = LP_User_Items_DB::getInstance();
560 - $filter = new LP_User_Items_Filter();
561 - $filter->where[] = $lp_user_item_db->wpdb->prepare( 'AND parent_id = %d', $this->get_user_item_id() );
562 - $filter->collection = $lp_user_item_db->tb_lp_user_items;
563 - $lp_user_item_db->delete_execute( $filter );
564 -
565 - // Delete user item.
566 - $lp_user_item_db = LP_User_Items_DB::getInstance();
567 - $filter = new LP_User_Items_Filter();
568 - $filter->where[] = $lp_user_item_db->wpdb->prepare( 'AND user_item_id = %d', $this->get_user_item_id() );
569 - $filter->collection = $lp_user_item_db->tb_lp_user_items;
570 - $lp_user_item_db->delete_execute( $filter );
571 -
572 - $this->clean_caches();
573 - }
574 -
575 - /**
576 - * Clean caches.
577 - *
578 - * @return void
579 - */
580 - public function clean_caches() {
581 - // Clear cache user item.
582 - $lp_user_items_cache = new LP_User_Items_Cache();
583 - $lp_user_items_cache->clean_user_item(
584 - [
585 - $this->user_id,
586 - $this->item_id,
587 - $this->item_type,
588 - ]
589 - );
590 -
591 - $key_cache_user_item = "userItemModel/find/{$this->user_id}/{$this->item_id}/{$this->item_type}";
592 - $lp_user_items_cache->clear( $key_cache_user_item );
593 -
594 - $key_cache_user_item_ref = "userItemModel/find/{$this->user_id}/{$this->item_id}/{$this->item_type}/{$this->ref_id}/{$this->ref_type}";
595 - $lp_user_items_cache->clear( $key_cache_user_item_ref );
596 - }
597 -}
1 +<?php
2 +
3 +/**
4 + * Class UserItemModel
5 + * To replace class LP_User_Item
6 + *
7 + * @package LearnPress/Classes
8 + * @version 1.0.3
9 + * @since 4.2.5
10 + */
11 +
12 +namespace LearnPress\Models\UserItems;
13 +
14 +use Exception;
15 +use LearnPress\Filters\UserItemsFilter;
16 +use LearnPress\Models\CoursePostModel;
17 +use LearnPress\Models\PostModel;
18 +use LearnPress\Models\UserItemMeta\UserItemMetaModel;
19 +use LearnPress\Models\UserModel;
20 +use LP_Datetime;
21 +use LP_User_Item_Meta_DB;
22 +use LP_User_Item_Meta_Filter;
23 +use LP_User_Items_Cache;
24 +use LP_User_Items_DB;
25 +use LP_User_Items_Filter;
26 +use stdClass;
27 +use Throwable;
28 +
29 +class UserItemModel {
30 + /**
31 + * Auto increment, Primary key
32 + *
33 + * @var int
34 + */
35 + private $user_item_id = 0;
36 + /**
37 + * @var string User ID, foreign key
38 + */
39 + public $user_id = 0;
40 + /**
41 + * Item id (course, lesson, quiz ...)
42 + *
43 + * @var string foreign key
44 + */
45 + public $item_id = 0;
46 + /**
47 + * @var string Time start item
48 + */
49 + public $start_time = null;
50 + /**
51 + * @var string Time finish item
52 + */
53 + public $end_time = null;
54 + /**
55 + * Item type (course, lesson, quiz ...)
56 + *
57 + * @var string Item type
58 + */
59 + public $item_type = '';
60 + /**
61 + * Item status (completed, enrolled, finished ...)
62 + *
63 + * @var string
64 + */
65 + public $status = '';
66 + /**
67 + * Item graduation
68 + *
69 + * @var string (passed, failed, in-progress...)
70 + */
71 + public $graduation = null;
72 + /**
73 + * Ref id (Order, course ...)
74 + *
75 + * @var int Reference id
76 + */
77 + public $ref_id = 0;
78 + /**
79 + * Ref type (Order, course ...)
80 + *
81 + * @var string
82 + */
83 + public $ref_type = '';
84 + /**
85 + * Parent id
86 + *
87 + * @var int
88 + */
89 + public $parent_id = 0;
90 + /**
91 + * @var null|PostModel|CoursePostModel
92 + */
93 + public $item;
94 + /**
95 + * List UserItemMetaModel
96 + * object {meta_key: {meta_id, learnpress_user_item_id, meta_key, meta_value, extra_value}}
97 + *
98 + * @var {meta_key: UserItemMetaModel}
99 + */
100 + public $meta_data;
101 +
102 + // Constants
103 + const STATUS_COMPLETED = 'completed';
104 + const STATUS_FINISHED = 'finished';
105 + const STATUS_ENROLLED = 'enrolled';
106 + const STATUS_PURCHASED = 'purchased';
107 + const STATUS_CANCEL = 'cancel';
108 + const GRADUATION_IN_PROGRESS = 'in-progress';
109 + const GRADUATION_PASSED = 'passed';
110 + const GRADUATION_FAILED = 'failed';
111 +
112 + /**
113 + * If data get from database, map to object.
114 + * Else create new object to save data to database.
115 + *
116 + * @param array|object|mixed $data
117 + */
118 + public function __construct( $data = null ) {
119 + if ( $data ) {
120 + $this->map_to_object( $data );
121 + $this->get_user_model();
122 + }
123 +
124 + if ( ! $this->meta_data instanceof stdClass ) {
125 + $this->meta_data = new stdClass();
126 + }
127 + }
128 +
129 + /**
130 + * Get start time
131 + *
132 + * @return string
133 + */
134 + public function get_start_time(): string {
135 + return is_null( $this->start_time ) ? '' : $this->start_time;
136 + }
137 +
138 + /**
139 + * Get end time
140 + *
141 + * @return string
142 + */
143 + public function get_end_time(): string {
144 + return is_null( $this->end_time ) ? '' : $this->end_time;
145 + }
146 +
147 + /**
148 + * Get status
149 + *
150 + * @return string
151 + */
152 + public function get_status(): string {
153 + return $this->status;
154 + }
155 +
156 + /**
157 + * Get graduation
158 + *
159 + * @return string
160 + */
161 + public function get_graduation(): string {
162 + return is_null( $this->graduation ) ? '' : $this->graduation;
163 + }
164 +
165 +
166 + /**
167 + * Get user item id
168 + *
169 + * @return int
170 + */
171 + public function get_user_item_id(): int {
172 + return $this->user_item_id;
173 + }
174 +
175 + /**
176 + * Set user item id
177 + *
178 + * @param int $user_item_id
179 + */
180 + private function set_user_item_id( int $user_item_id ) {
181 + $this->user_item_id = $user_item_id;
182 + }
183 +
184 + /**
185 + * Get user model
186 + *
187 + * @return false|UserModel
188 + * @since 4.2.6
189 + * @version 1.0.1
190 + */
191 + public function get_user_model() {
192 + return UserModel::find( $this->user_id, true );
193 + }
194 +
195 + /**
196 + * Map array, object data to UserItemModel.
197 + * Use for data get from database.
198 + *
199 + * @param array|object|mixed $data
200 + *
201 + * @return UserItemModel
202 + */
203 + public function map_to_object( $data ): UserItemModel {
204 + foreach ( $data as $key => $value ) {
205 + if ( property_exists( $this, $key ) ) {
206 + $this->{$key} = $value;
207 + }
208 + }
209 +
210 + return $this;
211 + }
212 +
213 + /**
214 + * Get user item from database by user_id, item_id, item_type.
215 + * If not exists, return false.
216 + * If exists, return UserItemModel.
217 + *
218 + * @param LP_User_Items_Filter|UserItemsFilter $filter
219 + *
220 + * @return UserItemModel|false|static
221 + * @since 4.2.5
222 + * @version 1.0.2
223 + */
224 + public static function get_user_item_model_from_db( $filter ) {
225 + $lp_user_item_db = LP_User_Items_DB::getInstance();
226 + $user_item_model = false;
227 +
228 + try {
229 + // Set order by user_item_id DESC to get the latest user item.
230 + $filter->order = $filter::ORDER_DESC;
231 + $filter->order_by = $filter::COL_USER_ITEM_ID;
232 + if ( empty( $filter->item_type ) ) {
233 + $filter->item_type = ( new static() )->item_type;
234 + }
235 +
236 + $lp_user_item_db->get_query_single_row( $filter );
237 + $query_single_row = $lp_user_item_db->get_user_items( $filter );
238 + $user_item_rs = $lp_user_item_db->wpdb->get_row( $query_single_row );
239 + if ( $user_item_rs instanceof stdClass ) {
240 + $user_item_model = new static( $user_item_rs );
241 + }
242 + } catch ( Throwable $e ) {
243 + error_log( __METHOD__ . ': ' . $e->getMessage() );
244 + }
245 +
246 + return $user_item_model;
247 + }
248 +
249 + /**
250 + * Find User Item by user_id, item_id, item_type.
251 + *
252 + * @param int $user_id
253 + * @param int $item_id
254 + * @param string $item_type
255 + * @param int $ref_id
256 + * @param string $ref_type
257 + * @param bool $check_cache
258 + *
259 + * @return false|UserItemModel|static
260 + * @since 4.2.7.3
261 + * @version 1.0.2
262 + */
263 + public static function find_user_item(
264 + int $user_id,
265 + int $item_id,
266 + string $item_type,
267 + int $ref_id = 0,
268 + string $ref_type = '',
269 + bool $check_cache = false
270 + ) {
271 + $key_cache = "userItemModel/find/{$user_id}/{$item_id}/{$item_type}";
272 + $filter = new LP_User_Items_Filter();
273 + $filter->user_id = $user_id;
274 + $filter->item_id = $item_id;
275 + $filter->item_type = $item_type;
276 + if ( ! empty( $ref_id ) ) {
277 + $filter->ref_id = $ref_id;
278 + $key_cache .= "/{$ref_id}";
279 + }
280 + if ( ! empty( $ref_type ) ) {
281 + $filter->ref_type = $ref_type;
282 + $key_cache .= "/{$ref_type}";
283 + }
284 + $lpUserItemCache = new LP_User_Items_Cache();
285 +
286 + // Check cache
287 + if ( $check_cache ) {
288 + $userItemModel = $lpUserItemCache->get_cache( $key_cache );
289 + if ( $userItemModel instanceof UserItemModel ) {
290 + return new static( $userItemModel );
291 + }
292 + }
293 +
294 + $userItemModel = static::get_user_item_model_from_db( $filter );
295 + // Set cache
296 + if ( $userItemModel instanceof UserItemModel ) {
297 + if ( ! $userItemModel->meta_data instanceof stdClass ) {
298 + $userItemModel->meta_data = new stdClass();
299 + }
300 +
301 + $lpUserItemCache->set_cache( $key_cache, $userItemModel );
302 + }
303 +
304 + return $userItemModel;
305 + }
306 +
307 + /**
308 + * Get user item metadata from object meta_data or database by user_item_id, meta_key.
309 + *
310 + * @param string $key
311 + *
312 + * @return false|UserItemMetaModel
313 + * @since 4.2.5
314 + * @version 1.0.1
315 + */
316 + public function get_meta_model_from_key( string $key ) {
317 + $filter = new LP_User_Item_Meta_Filter();
318 + $filter->meta_key = $key;
319 + $filter->learnpress_user_item_id = $this->get_user_item_id();
320 +
321 + return UserItemMetaModel::get_user_item_meta_model_from_db( $filter );
322 + }
323 +
324 + /**
325 + * Get metadata from key
326 + *
327 + * @param string $key
328 + * @param mixed $default_value
329 + * @param bool $get_extra
330 + *
331 + * @return false|string
332 + * @since 4.2.5
333 + * @version 1.0.3
334 + */
335 + public function get_meta_value_from_key( string $key, $default_value = false, bool $get_extra = false ) {
336 + if ( $this->meta_data instanceof stdClass && isset( $this->meta_data->{$key} ) ) {
337 + return maybe_unserialize( $this->meta_data->{$key} );
338 + }
339 +
340 + $user_item_metadata = $this->get_meta_model_from_key( $key );
341 + if ( $user_item_metadata instanceof UserItemMetaModel ) {
342 + if ( ! $this->meta_data instanceof stdClass ) {
343 + $this->meta_data = new stdClass();
344 + }
345 +
346 + if ( $get_extra ) {
347 + $data = $user_item_metadata->extra_value;
348 + } else {
349 + $data = $user_item_metadata->meta_value;
350 + }
351 +
352 + $this->meta_data->{$key} = maybe_unserialize( $data );
353 + } else {
354 + $data = $default_value;
355 + }
356 +
357 + return $data;
358 + }
359 +
360 + /**
361 + * Update meta value for key.
362 + *
363 + * @param string $key
364 + * @param mixed $value
365 + * @param bool $is_extra
366 + *
367 + * @return void
368 + * @since 4.2.7.4
369 + * @version 1.0.0
370 + */
371 + public function set_meta_value_for_key( string $key, $value, bool $is_extra = false ) {
372 + if ( ! $this->meta_data instanceof stdClass ) {
373 + $this->meta_data = new stdClass();
374 + }
375 +
376 + $this->meta_data->{$key} = $value;
377 + $lp_db = LP_User_Items_DB::getInstance();
378 + if ( $is_extra ) {
379 + if ( is_object( $value ) || is_array( $value ) ) {
380 + $value = json_encode( $value );
381 + }
382 + $lp_db->update_extra_value( $this->get_user_item_id(), $key, $value );
383 + } else {
384 + learn_press_update_user_item_meta( $this->get_user_item_id(), $key, $value );
385 + }
386 +
387 + //$this->clean_caches();
388 + }
389 +
390 + /**
391 + * Delete meta from key.
392 + *
393 + * @param string $key
394 + *
395 + * @return void
396 + * @since 4.2.7.4
397 + * @version 1.0.0
398 + */
399 + public function delete_meta( string $key ) {
400 + $user_item_metadata = $this->get_meta_model_from_key( $key );
401 + if ( $user_item_metadata instanceof UserItemMetaModel ) {
402 + $user_item_metadata->delete();
403 + $this->meta_data->{$key} = null;
404 + $this->clean_caches();
405 + }
406 + }
407 +
408 + /**
409 + * Update data to database.
410 + *
411 + * If user_item_id is empty, insert new data, else update data.
412 + *
413 + * @return UserItemModel
414 + * @throws Exception
415 + * @since 4.2.5
416 + * @version 1.0.3
417 + */
418 + public function save(): UserItemModel {
419 + $lp_user_item_db = LP_User_Items_DB::getInstance();
420 + $user_item_id_new = 0;
421 + $data = get_object_vars( $this );
422 +
423 + if ( ! isset( $data['start_time'] ) ) {
424 + $data['start_time'] = gmdate( 'Y-m-d H:i:s', time() );
425 + $this->start_time = $data['start_time'];
426 + }
427 +
428 + // Check if exists user_item_id.
429 + if ( empty( $this->get_user_item_id() ) ) { // Insert data.
430 + if ( empty( $data['item_id'] ) ) {
431 + throw new Exception( 'Item ID is require.' );
432 + }
433 + if ( empty( $data['item_type'] ) ) {
434 + throw new Exception( 'Item Type is require.' );
435 + }
436 +
437 + // Guest can buy course if enable guest checkout.
438 + if ( empty( $data['user_id'] ) && LP_COURSE_CPT !== $data['item_type'] ) {
439 + throw new Exception( 'User ID is require.' );
440 + }
441 +
442 + $user_item_id_new = $lp_user_item_db->insert_data( $data );
443 + if ( empty( $user_item_id_new ) ) {
444 + throw new Exception( 'Cannot insert data to database.' );
445 + }
446 + } else { // Update data.
447 + $lp_user_item_db->update_data( $data );
448 + }
449 +
450 + if ( $user_item_id_new ) {
451 + $this->set_user_item_id( $user_item_id_new );
452 + }
453 +
454 + // Clear caches before firing the created hook. Webhook and third-party listeners may reload
455 + // this user item from the model/cache layer, so firing earlier can expose stale data.
456 + $this->clean_caches();
457 +
458 + if ( $user_item_id_new ) {
459 + do_action( 'learn-press/user-item/created', $this );
460 + }
461 +
462 + return $this;
463 + }
464 +
465 + /**
466 + * Get total timestamp complete, done item.
467 + *
468 + * @return int
469 + */
470 + public function get_total_timestamp_completed(): int {
471 + $time_interval = 0;
472 +
473 + if ( empty( $this->get_start_time() ) || empty( $this->get_end_time() ) ) {
474 + return $time_interval;
475 + }
476 +
477 + $start = new LP_Datetime( $this->get_start_time() );
478 + $end = new LP_Datetime( $this->get_end_time() );
479 +
480 + return $end->getTimestamp() - $start->getTimestamp();
481 + }
482 +
483 + /**
484 + * Get expiration time.
485 + *
486 + * @return null|LP_Datetime $time
487 + * @since 3.3.0
488 + * @version 3.3.3
489 + */
490 + public function get_expiration_time() {
491 + $duration = get_post_meta( $this->item_id, '_lp_duration', true );
492 +
493 + if ( ! absint( $duration ) || empty( $this->start_time ) ) {
494 + $expire = null;
495 + } else {
496 + $start = new LP_Datetime( $this->start_time );
497 + $start_time = $start->getTimestamp();
498 + // Convert duration from string to seconds.
499 + if ( ! is_numeric( $duration ) ) {
500 + $duration = strtotime( $duration ) - time();
501 + }
502 +
503 + $expire_time = $start_time + $duration;
504 + $expire = new LP_Datetime( $expire_time );
505 + }
506 +
507 + return apply_filters( 'learnPress/user-item/expiration-time', $expire, $duration, $this );
508 + }
509 +
510 + /**
511 + * Get translate value.
512 + *
513 + * @param string $value
514 + *
515 + * @return string
516 + * @since 4.2.7.8
517 + * @version 1.0.0
518 + */
519 + public function get_string_i18n( string $value ): string {
520 + switch ( $value ) {
521 + case self::STATUS_COMPLETED:
522 + $value = __( 'Completed', 'learnpress' );
523 + break;
524 + case self::STATUS_FINISHED:
525 + $value = __( 'Finished', 'learnpress' );
526 + break;
527 + case self::STATUS_ENROLLED:
528 + $value = __( 'Enrolled', 'learnpress' );
529 + break;
530 + case self::STATUS_CANCEL:
531 + $value = __( 'Cancel', 'learnpress' );
532 + break;
533 + case self::GRADUATION_IN_PROGRESS:
534 + $value = __( 'In Progress', 'learnpress' );
535 + break;
536 + case self::GRADUATION_PASSED:
537 + $value = __( 'Passed', 'learnpress' );
538 + break;
539 + case self::GRADUATION_FAILED:
540 + $value = __( 'Failed', 'learnpress' );
541 + break;
542 + }
543 +
544 + return $value;
545 + }
546 +
547 + /**
548 + * Get status label.
549 + *
550 + * @return string
551 + * @since 4.4.2
552 + * @version 1.0.0
553 + */
554 + public function get_status_label(): string {
555 + switch ( $this->get_status() ) {
556 + case self::STATUS_COMPLETED:
557 + $value = __( 'Completed', 'learnpress' );
558 + break;
559 + case self::STATUS_FINISHED:
560 + $value = __( 'Finished', 'learnpress' );
561 + break;
562 + case self::STATUS_ENROLLED:
563 + $value = __( 'Enrolled', 'learnpress' );
564 + break;
565 + case self::STATUS_CANCEL:
566 + $value = __( 'Cancel', 'learnpress' );
567 + break;
568 + default:
569 + $value = $this->get_status();
570 + break;
571 + }
572 +
573 + return (string) $value;
574 + }
575 +
576 + /**
577 + * Get graduation label.
578 + *
579 + * @return string
580 + * @since 4.4.2
581 + * @version 1.0.0
582 + */
583 + public function get_graduation_label(): string {
584 + switch ( $this->get_graduation() ) {
585 + case self::GRADUATION_IN_PROGRESS:
586 + $value = __( 'In Progress', 'learnpress' );
587 + break;
588 + case self::GRADUATION_PASSED:
589 + $value = __( 'Passed', 'learnpress' );
590 + break;
591 + case self::GRADUATION_FAILED:
592 + $value = __( 'Failed', 'learnpress' );
593 + break;
594 + default:
595 + $value = $this->get_graduation();
596 + break;
597 + }
598 +
599 + return (string) $value;
600 + }
601 +
602 + /**
603 + * Delete user item.
604 + *
605 + * @throws Exception
606 + * @since 4.2.7.3
607 + * @version 1.0.2
608 + */
609 + public function delete() {
610 + // Delete meta data of user item.
611 + $lp_user_item_meta_db = LP_User_Item_Meta_DB::getInstance();
612 + $filter = new LP_User_Item_Meta_Filter();
613 + $filter->where[] = $lp_user_item_meta_db->wpdb->prepare( 'AND learnpress_user_item_id = %d', $this->get_user_item_id() );
614 + $filter->collection = $lp_user_item_meta_db->tb_lp_user_itemmeta;
615 + $lp_user_item_meta_db->delete_execute( $filter );
616 + $this->meta_data = null;
617 +
618 + // Delete user item relationships.
619 + $lp_user_item_db = LP_User_Items_DB::getInstance();
620 + $filter = new LP_User_Items_Filter();
621 + $filter->where[] = $lp_user_item_db->wpdb->prepare( 'AND parent_id = %d', $this->get_user_item_id() );
622 + $filter->collection = $lp_user_item_db->tb_lp_user_items;
623 + $lp_user_item_db->delete_execute( $filter );
624 +
625 + // Delete user item.
626 + $lp_user_item_db = LP_User_Items_DB::getInstance();
627 + $filter = new LP_User_Items_Filter();
628 + $filter->where[] = $lp_user_item_db->wpdb->prepare( 'AND user_item_id = %d', $this->get_user_item_id() );
629 + $filter->collection = $lp_user_item_db->tb_lp_user_items;
630 + $lp_user_item_db->delete_execute( $filter );
631 +
632 + $this->clean_caches();
633 + }
634 +
635 + /**
636 + * Clean caches.
637 + *
638 + * @return void
639 + */
640 + public function clean_caches() {
641 + // Clear cache user item.
642 + $lp_user_items_cache = new LP_User_Items_Cache();
643 + $lp_user_items_cache->clean_user_item(
644 + [
645 + $this->user_id,
646 + $this->item_id,
647 + $this->item_type,
648 + ]
649 + );
650 +
651 + $key_cache_user_item = "userItemModel/find/{$this->user_id}/{$this->item_id}/{$this->item_type}";
652 + $lp_user_items_cache->clear( $key_cache_user_item );
653 +
654 + $key_cache_user_item_ref = "userItemModel/find/{$this->user_id}/{$this->item_id}/{$this->item_type}/{$this->ref_id}/{$this->ref_type}";
655 + $lp_user_items_cache->clear( $key_cache_user_item_ref );
656 + }
657 +}