ILIAS  release_8 Revision v8.24
class.ilObjCmiXapi.php
Go to the documentation of this file.
1<?php
2
3declare(strict_types=1);
4
31{
32 public const PLUGIN = false;
33
34 public const DB_TABLE_NAME = 'cmix_settings';
35 public const DB_USERS_TABLE_NAME = 'cmix_users';
36 public const DB_RESULTS_TABLE_NAME = 'cmix_results';
37
41 protected ?bool $activationLimited = null;
42 protected ?int $activationStartingTime = null;
43 protected ?int $activationEndingTime = null;
44 protected ?bool $activationVisibility = null;
45
46 protected ?int $lrsTypeId;
47
49
50 protected string $contentType;
51 public const CONT_TYPE_GENERIC = 'generic';
52 public const CONT_TYPE_CMI5 = 'cmi5';
53
54 protected string $sourceType;
55 public const SRC_TYPE_REMOTE = 'remoteSource';
56 public const SRC_TYPE_LOCAL = 'localSource';
57 public const SRC_TYPE_EXTERNAL = 'externalSource';
58
59 protected string $activityId;
60
61 protected string $publisherId;
62
63 protected string $instructions;
64
65 protected string $launchUrl;
66
67 protected string $launchParameters;
68
69 protected string $moveOn;
70
71 protected string $entitlementKey;
72
73 protected bool $authFetchUrlEnabled = false;
74
75 protected bool $anonymousHomePage = false;
76 public const ANONYMOUS_HOMEPAGE = 'https://example.org';
77
78 protected string $launchMethod;
79 public const LAUNCH_METHOD_OWN_WIN = 'ownWin';
80 public const LAUNCH_METHOD_NEW_WIN = 'newWin';
81 public const LAUNCH_METHOD_IFRAME = 'iframe';
82
83 protected string $launchMode;
84 public const LAUNCH_MODE_NORMAL = 'Normal';
85 public const LAUNCH_MODE_BROWSE = 'Browse';
86 public const LAUNCH_MODE_REVIEW = 'Review';
87
88 protected bool $switchToReviewEnabled = false;
89
90 protected float $masteryScore;
91 public const LMS_MASTERY_SCORE = 0.7;
92
93 protected bool $keepLpStatusEnabled = false;
94
95 protected int $userIdent;
99 public const PRIVACY_IDENT_REAL_EMAIL = 3;
103
104 protected int $userName;
105 public const PRIVACY_NAME_NONE = 0;
106 public const PRIVACY_NAME_FIRSTNAME = 1;
107 public const PRIVACY_NAME_LASTNAME = 2;
108 public const PRIVACY_NAME_FULLNAME = 3;
109
110 protected string $userPrivacyComment = "";
111
112 protected bool $statementsReportEnabled = false;
113
114 protected string $xmlManifest = "";
115
116 protected int $version;
117
118 protected bool $bypassProxyEnabled = false;
119
120 protected bool $only_moveon = false;
121
122 protected bool $achieved = true;
123
124 protected bool $answered = true;
125
126 protected bool $completed = true;
127
128 protected bool $failed = true;
129
130 protected bool $initialized = true;
131
132 protected bool $passed = true;
133
134 protected bool $progressed = true;
135
136 protected bool $satisfied = true;
137
138 protected bool $terminated = true;
139
140 protected bool $hide_data = false;
141
142 protected bool $timestamp = false;
143
144 protected bool $duration = true;
145
146 protected bool $no_substatements = false;
147
149
151
155 public function __construct(int $a_id = 0, bool $a_reference = true)
156 {
157 global $DIC;
158 $this->database = $DIC->database();
159
160 $this->lrsTypeId = 0;
161
162 $this->contentType = self::CONT_TYPE_GENERIC;
163 $this->sourceType = self::SRC_TYPE_REMOTE;
164
165 $this->activityId = '';
166
167 $this->publisherId = '';
168
169 $this->instructions = '';
170
171 $this->launchUrl = '';
172 $this->launchParameters = '';
173 $this->moveOn = '';
174 $this->entitlementKey = '';
175
176 $this->authFetchUrlEnabled = false;
177
178 $this->launchMethod = self::LAUNCH_METHOD_NEW_WIN;
179 $this->launchMode = self::LAUNCH_MODE_NORMAL;
180
181 $this->switchToReviewEnabled = true;
182
183 $this->masteryScore = self::LMS_MASTERY_SCORE;
184 $this->keepLpStatusEnabled = true;
185
186 $this->userIdent = self::PRIVACY_IDENT_IL_UUID_USER_ID;
187 $this->userName = self::PRIVACY_NAME_NONE;
188 $this->userPrivacyComment = '';
189
190 $this->currentCmixUser = null;
191
192 $this->statementsReportEnabled = false;
193
194 $this->xmlManifest = '';
195 $this->version = 0;
196
197 $this->bypassProxyEnabled = false;
198
199 parent::__construct($a_id, $a_reference);
200 }
201
202
203 public static function getInstance(int $a_id = 0, bool $a_reference = true): \ilObjCmiXapi
204 {
205 return new self($a_id, $a_reference);
206 }
207
208 protected function initType(): void
209 {
210 $this->type = "cmix";
211 }
212
213 public function getLrsTypeId(): ?int
214 {
215 return $this->lrsTypeId;
216 }
217
218 public function setLrsTypeId(int $lrsTypeId): void
219 {
220 $this->lrsTypeId = $lrsTypeId;
221 }
222
223 public function getLrsType(): \ilCmiXapiLrsType
224 {
225 return $this->lrsType;
226 }
227
228 public function setLrsType(\ilCmiXapiLrsType $lrsType): void
229 {
230 $this->lrsType = $lrsType;
231 }
232
233 public function initLrsType(): void
234 {
235 $this->setLrsType(new ilCmiXapiLrsType($this->getLrsTypeId()));
236 }
237
238 public function getContentType(): string
239 {
240 return $this->contentType;
241 }
242
243 public function setContentType(string $contentType): void
244 {
245 //bug before 21-07-24
246 if ($contentType == "learning") {
248 }
249 $this->contentType = $contentType;
250 }
251
252 public function isMixedContentType(): bool
253 {
254 // after 21-07-24 and before cmi5 refactoring
255 // launched before cmi5 refactoring ident in: statement.actor.mbox
256 // launched after cmi5 refactoring ident in: statement.actor.account.name
257 return (($this->getContentType() == self::CONT_TYPE_CMI5) && empty($this->getPublisherId()));
258 }
259
260 public function getSourceType(): string
261 {
262 return $this->sourceType;
263 }
264
265 public function isSourceTypeRemote(): bool
266 {
267 return $this->sourceType == self::SRC_TYPE_REMOTE;
268 }
269
270 public function isSourceTypeExternal(): bool
271 {
272 return $this->sourceType == self::SRC_TYPE_EXTERNAL;
273 }
274
275 public function setSourceType(string $sourceType): void
276 {
277 $this->sourceType = $sourceType;
278 }
279
280 public function getActivityId(): string
281 {
282 return $this->activityId;
283 }
284
285 public function setActivityId(string $activityId): void
286 {
287 $this->activityId = $activityId;
288 }
289
290 public function getPublisherId(): string
291 {
292 return $this->publisherId;
293 }
294
295 public function setPublisherId(string $publisherId): void
296 {
297 $this->publisherId = $publisherId;
298 }
299
300 public function getInstructions(): string
301 {
302 return $this->instructions;
303 }
304
305 public function setInstructions(string $instructions): void
306 {
307 $this->instructions = $instructions;
308 }
309
310 public function getLaunchUrl(): string
311 {
312 return $this->launchUrl;
313 }
314
315 public function setLaunchUrl(string $launchUrl): void
316 {
317 $this->launchUrl = $launchUrl;
318 }
319
320 public function getLaunchParameters(): string
321 {
323 }
324
325 public function setLaunchParameters(string $launchParameters): void
326 {
327 $this->launchParameters = $launchParameters;
328 }
329
334 public function getMoveOn(): string
335 {
336 return $this->moveOn;
337 }
338
343 public function setMoveOn(string $moveOn): void
344 {
345 $this->moveOn = $moveOn;
346 }
347
352 public function getLPMode(): int
353 {
354 $olp = ilObjectLP::getInstance($this->getId());
355 return $olp->getCurrentMode();
356 }
357
362 public function getLMSMoveOn(): string
363 {
365 switch ($this->getLPMode()) {
368 break;
372 break;
376 break;
380 break;
381 }
382 return $moveOn;
383 }
384
385 public function getEntitlementKey(): string
386 {
388 }
389
390 public function setEntitlementKey(string $entitlementKey): void
391 {
392 $this->entitlementKey = $entitlementKey;
393 }
394
395 public function isAuthFetchUrlEnabled(): bool
396 {
398 }
399
401 {
402 $this->authFetchUrlEnabled = $authFetchUrlEnabled;
403 }
404
405 public function getLaunchMethod(): string
406 {
407 return $this->launchMethod;
408 }
409
410 public function setLaunchMethod(string $launchMethod): void
411 {
412 $this->launchMethod = $launchMethod;
413 }
414
415 public function getLaunchMode(): string
416 {
417 return ucfirst($this->launchMode);
418 }
419
420 public function setLaunchMode(string $launchMode): void
421 {
422 $this->launchMode = ucfirst($launchMode);
423 }
424
425 public function isSwitchToReviewEnabled(): bool
426 {
428 }
429
430 public function getSwitchToReviewEnabled(): bool
431 {
433 }
434
436 {
437 $this->switchToReviewEnabled = $switchToReviewEnabled;
438 }
439
440 public function getMasteryScore(): float
441 {
442 return $this->masteryScore;
443 }
444
445 public function setMasteryScore(float $masteryScore): void
446 {
447 $this->masteryScore = $masteryScore;
448 }
449
450 public function getMasteryScorePercent(): float
451 {
452 return $this->masteryScore * 100;
453 }
454
455 public function setMasteryScorePercent(float $masteryScorePercent): void
456 {
457 $this->masteryScore = $masteryScorePercent / 100;
458 }
459
460 public function isKeepLpStatusEnabled(): bool
461 {
463 }
464
466 {
467 $this->keepLpStatusEnabled = $keepLpStatusEnabled;
468 }
469
470 public function getPrivacyIdent(): int
471 {
472 return $this->userIdent;
473 }
474
475 public function setPrivacyIdent(int $userIdent): void
476 {
477 $this->userIdent = $userIdent;
478 }
479
480 public function getPrivacyName(): int
481 {
482 return $this->userName;
483 }
484
485 public function setPrivacyName(int $userName): void
486 {
487 $this->userName = $userName;
488 }
489
490 public function getOnlyMoveon(): bool
491 {
492 return $this->only_moveon;
493 }
494
495 public function setOnlyMoveon(bool $only_moveon): void
496 {
497 $this->only_moveon = $only_moveon;
498 }
499
500 public function getAchieved(): bool
501 {
502 return $this->achieved;
503 }
504
505 public function setAchieved(bool $achieved): void
506 {
507 $this->achieved = $achieved;
508 }
509
510 public function getAnswered(): bool
511 {
512 return $this->answered;
513 }
514
515 public function setAnswered(bool $answered): void
516 {
517 $this->answered = $answered;
518 }
519
520 public function getCompleted(): bool
521 {
522 return $this->completed;
523 }
524
525 public function setCompleted(bool $completed): void
526 {
527 $this->completed = $completed;
528 }
529
530 public function getFailed(): bool
531 {
532 return $this->failed;
533 }
534
535 public function setFailed(bool $failed): void
536 {
537 $this->failed = $failed;
538 }
539
540 public function getInitialized(): bool
541 {
542 return $this->initialized;
543 }
544
545 public function setInitialized(bool $initialized): void
546 {
547 $this->initialized = $initialized;
548 }
549
550 public function getPassed(): bool
551 {
552 return $this->passed;
553 }
554
555 public function setPassed(bool $passed): void
556 {
557 $this->passed = $passed;
558 }
559
560 public function getProgressed(): bool
561 {
562 return $this->progressed;
563 }
564
565 public function setProgressed(bool $progressed): void
566 {
567 $this->progressed = $progressed;
568 }
569
570 public function getSatisfied(): bool
571 {
572 return $this->satisfied;
573 }
574
575 public function setSatisfied(bool $satisfied): void
576 {
577 $this->satisfied = $satisfied;
578 }
579
580 public function getTerminated(): bool
581 {
582 return $this->terminated;
583 }
584
585 public function setTerminated(bool $terminated): void
586 {
587 $this->terminated = $terminated;
588 }
589
590 public function getHideData(): bool
591 {
592 return $this->hide_data;
593 }
594
595 public function setHideData(bool $hide_data): void
596 {
597 $this->hide_data = $hide_data;
598 }
599
600 public function getTimestamp(): bool
601 {
602 return $this->timestamp;
603 }
604
605 public function setTimestamp(bool $timestamp): void
606 {
607 $this->timestamp = $timestamp;
608 }
609
610 public function getDuration(): bool
611 {
612 return $this->duration;
613 }
614
615 public function setDuration(bool $duration): void
616 {
617 $this->duration = $duration;
618 }
619
620 public function getNoSubstatements(): bool
621 {
623 }
624
625 public function setNoSubstatements(bool $no_substatements): void
626 {
627 $this->no_substatements = $no_substatements;
628 }
629
630 public function getUserPrivacyComment(): string
631 {
633 }
634
635 public function setUserPrivacyComment(string $userPrivacyComment): void
636 {
637 $this->userPrivacyComment = $userPrivacyComment;
638 }
639
640 public function isStatementsReportEnabled(): bool
641 {
643 }
644
646 {
647 $this->statementsReportEnabled = $statementsReportEnabled;
648 }
649
650 public function getXmlManifest(): string
651 {
652 return $this->xmlManifest;
653 }
654
655 public function setXmlManifest(string $xmlManifest): void
656 {
657 $this->xmlManifest = $xmlManifest;
658 }
659
660 public function getVersion(): int
661 {
662 return $this->version;
663 }
664
665 public function setVersion(int $version): void
666 {
667 $this->version = $version;
668 }
669
670 public function isBypassProxyEnabled(): bool
671 {
673 }
674
675 public function setBypassProxyEnabled(bool $bypassProxyEnabled): void
676 {
677 $this->bypassProxyEnabled = $bypassProxyEnabled;
678 }
679
680 //todo?
681 protected function doRead(): void
682 {
683 $this->load();
684 }
685
686 protected function load(): void
687 {
688 $query = "SELECT * FROM " . self::DB_TABLE_NAME . " WHERE obj_id = %s";
689 $res = $this->database->queryF($query, ['integer'], [$this->getId()]);
690
691 while ($row = $this->database->fetchAssoc($res)) {
692 if ($row['lrs_type_id']) {
693 $this->setLrsTypeId((int) $row['lrs_type_id']);
694 $this->initLrsType();
695 }
696
697 $this->setContentType((string) $row['content_type']);
698 $this->setSourceType((string) $row['source_type']);
699
700 $this->setActivityId((string) $row['activity_id']);
701 $this->setPublisherId((string) $row['publisher_id']);
702 $this->setInstructions((string) $row['instructions']);
703
704 $this->setLaunchUrl((string) $row['launch_url']);
705 $this->setLaunchParameters((string) $row['launch_parameters']);
706 $this->setMoveOn((string) $row['moveon']);
707 $this->setEntitlementKey((string) $row['entitlement_key']);
708 $this->setAuthFetchUrlEnabled((bool) $row['auth_fetch_url']);
709
710 $this->setLaunchMethod((string) $row['launch_method']);
711
712 $this->setLaunchMode((string) $row['launch_mode']);
713 $this->setSwitchToReviewEnabled((bool) $row['switch_to_review']);
714 $this->setMasteryScore((float) $row['mastery_score']);
715 $this->setKeepLpStatusEnabled((bool) $row['keep_lp']);
716
717 $this->setPrivacyIdent((int) $row['privacy_ident']);
718 $this->setPrivacyName((int) $row['privacy_name']);
719
720 $this->setOnlyMoveon((bool) $row['only_moveon']);
721 $this->setAchieved((bool) $row['achieved']);
722 $this->setAnswered((bool) $row['answered']);
723 $this->setCompleted((bool) $row['completed']);
724 $this->setFailed((bool) $row['failed']);
725 $this->setInitialized((bool) $row['initialized']);
726 $this->setPassed((bool) $row['passed']);
727 $this->setProgressed((bool) $row['progressed']);
728 $this->setSatisfied((bool) $row['satisfied']);
729 $this->setTerminated((bool) $row['c_terminated']);
730 $this->setHideData((bool) $row['hide_data']);
731 $this->setTimestamp((bool) $row['c_timestamp']);
732 $this->setDuration((bool) $row['duration']);
733 $this->setNoSubstatements((bool) $row['no_substatements']);
734
735 $this->setUserPrivacyComment((string) $row['usr_privacy_comment']);
736
737 $this->setStatementsReportEnabled((bool) $row['show_statements']);
738
739 $this->setXmlManifest((string) $row['xml_manifest']);
740 $this->setVersion((int) $row['version']);
741
742 $this->setBypassProxyEnabled((bool) $row['bypass_proxy']);
743
744 $this->setHighscoreEnabled((bool) $row['highscore_enabled']);
745 $this->setHighscoreAchievedTS((bool) $row['highscore_achieved_ts']);
746 $this->setHighscorePercentage((bool) $row['highscore_percentage']);
747 $this->setHighscoreWTime((bool) $row['highscore_wtime']);
748 $this->setHighscoreOwnTable((bool) $row['highscore_own_table']);
749 $this->setHighscoreTopTable((bool) $row['highscore_top_table']);
750 $this->setHighscoreTopNum((int) $row['highscore_top_num']);
751 }
752
754 }
755
756 //todo?
757 protected function doUpdate(): void
758 {
759 $this->save();
760 }
761
762 public function save(): void
763 {
764 global $DIC; /* @var \ILIAS\DI\Container $DIC */
765 // not possible: Move Global Access to Constructor
766 $DIC->database()->replace(self::DB_TABLE_NAME, [
767 'obj_id' => ['integer', $this->getId()]
768 ], [
769 'lrs_type_id' => ['integer', $this->getLrsTypeId()],
770 'content_type' => ['text', $this->getContentType()],
771 'source_type' => ['text', $this->getSourceType()],
772 'activity_id' => ['text', $this->getActivityId()],
773 'publisher_id' => ['text', $this->getPublisherId()],
774 'instructions' => ['text', $this->getInstructions()],
775 'launch_url' => ['text', $this->getLaunchUrl()],
776 'launch_parameters' => ['text', $this->getLaunchParameters()],
777 'moveon' => ['text', $this->getMoveOn()],
778 'entitlement_key' => ['text', $this->getEntitlementKey()],
779 'auth_fetch_url' => ['integer', (int) $this->isAuthFetchUrlEnabled()],
780 'launch_method' => ['text', $this->getLaunchMethod()],
781 'launch_mode' => ['text', $this->getLaunchMode()],
782 'switch_to_review' => ['integer', (int) $this->isSwitchToReviewEnabled()],
783 'mastery_score' => ['float', $this->getMasteryScore()],
784 'keep_lp' => ['integer', (int) $this->isKeepLpStatusEnabled()],
785 'privacy_ident' => ['integer', $this->getPrivacyIdent()],
786 'privacy_name' => ['integer', $this->getPrivacyName()],
787 'usr_privacy_comment' => ['text', $this->getUserPrivacyComment()],
788 'show_statements' => ['integer', (int) $this->isStatementsReportEnabled()],
789 'xml_manifest' => ['text', $this->getXmlManifest()],
790 'version' => ['integer', $this->getVersion()],
791 'bypass_proxy' => ['integer', (int) $this->isBypassProxyEnabled()],
792 'highscore_enabled' => ['integer', (int) $this->getHighscoreEnabled()],
793 'highscore_achieved_ts' => ['integer', (int) $this->getHighscoreAchievedTS()],
794 'highscore_percentage' => ['integer', (int) $this->getHighscorePercentage()],
795 'highscore_wtime' => ['integer', (int) $this->getHighscoreWTime()],
796 'highscore_own_table' => ['integer', (int) $this->getHighscoreOwnTable()],
797 'highscore_top_table' => ['integer', (int) $this->getHighscoreTopTable()],
798 'highscore_top_num' => ['integer', $this->getHighscoreTopNum()],
799 'only_moveon' => ['integer', (int) $this->getOnlyMoveon()],
800 'achieved' => ['integer', (int) $this->getAchieved()],
801 'answered' => ['integer', (int) $this->getAnswered()],
802 'completed' => ['integer', (int) $this->getCompleted()],
803 'failed' => ['integer', (int) $this->getFailed()],
804 'initialized' => ['integer', (int) $this->getInitialized()],
805 'passed' => ['integer', (int) $this->getPassed()],
806 'progressed' => ['integer', (int) $this->getProgressed()],
807 'satisfied' => ['integer', (int) $this->getSatisfied()],
808 'c_terminated' => ['integer', (int) $this->getTerminated()],
809 'hide_data' => ['integer', (int) $this->getHideData()],
810 'c_timestamp' => ['integer', (int) $this->getTimestamp()],
811 'duration' => ['integer', (int) $this->getDuration()],
812 'no_substatements' => ['integer', (int) $this->getNoSubstatements()]
813 ]);
814
816 }
817
818 protected function loadRepositoryActivationSettings(): void
819 {
820 if ($this->ref_id) {
821 $activation = ilObjectActivation::getItem($this->ref_id);
822 switch ($activation["timing_type"]) {
824 $this->setActivationLimited(true);
825 if (!is_null($activation["timing_start"])) {
826 $activation["timing_start"] = (int) $activation["timing_start"];
827 }
828 $this->setActivationStartingTime($activation["timing_start"]);
829 if (!is_null($activation["timing_end"])) {
830 $activation["timing_end"] = (int) $activation["timing_end"];
831 }
832 $this->setActivationEndingTime($activation["timing_end"]);
833 $this->setActivationVisibility((bool) $activation["visible"]);
834 break;
835
836 default:
837 $this->setActivationLimited(false);
838 break;
839 }
840 }
841 }
842
843 protected function saveRepositoryActivationSettings(): void
844 {
845 if ($this->ref_id) {
846 ilObjectActivation::getItem($this->ref_id);
847
848 $item = new ilObjectActivation();
849 if (!$this->isActivationLimited()) {
850 $item->setTimingType(ilObjectActivation::TIMINGS_DEACTIVATED);
851 } else {
852 $item->setTimingType(ilObjectActivation::TIMINGS_ACTIVATION);
853 $item->setTimingStart($this->getActivationStartingTime());
854 $item->setTimingEnd($this->getActivationEndingTime());
855 $item->toggleVisible($this->getActivationVisibility());
856 }
857
858 $item->update($this->ref_id);
859 }
860 }
861
863 {
864 global $DIC; /* @var \ILIAS\DI\Container $DIC */
865 //not possible: Move Global Access to Constructor
866 $tableName = self::DB_TABLE_NAME;
867
868 $query = "
869 UPDATE {$tableName}
870 SET privacy_ident = %s,
871 privacy_name = %s,
872 only_moveon = %s,
873 achieved = %s,
874 answered = %s,
875 completed = %s,
876 failed = %s,
877 initialized = %s,
878 passed = %s,
879 progressed = %s,
880 satisfied = %s,
881 c_terminated = %s,
882 hide_data = %s,
883 c_timestamp = %s,
884 duration = %s,
885 no_substatements = %s
886 WHERE lrs_type_id = %s
887 ";
888
889 $DIC->database()->manipulateF(
890 $query,
891 ['integer',
892 'integer',
893 'integer',
894 'integer',
895 'integer',
896 'integer',
897 'integer',
898 'integer',
899 'integer',
900 'integer',
901 'integer',
902 'integer',
903 'integer',
904 'integer',
905 'integer',
906 'integer',
907 'integer'
908 ],
926 ]
927 );
928 }
929
931 {
932 global $DIC; /* @var \ILIAS\DI\Container $DIC */
933 // not possible: Move Global Access to Constructor
934 $tableName = self::DB_TABLE_NAME;
935
936 $query = "
937 UPDATE {$tableName}
938 SET bypass_proxy = %s
939 WHERE lrs_type_id = %s
940 ";
941
942 $DIC->database()->manipulateF(
943 $query,
944 ['integer', 'integer'],
946 );
947 }
948
953 {
954 global $DIC; /* @var \ILIAS\DI\Container $DIC */
955 // not possible: Move Global Access to Constructor
956 $query = "
957 SELECT DISTINCT s.obj_id FROM " . self::DB_TABLE_NAME . " s
958 INNER JOIN " . self::DB_USERS_TABLE_NAME . " u ON u.obj_id = s.obj_id
959 WHERE bypass_proxy = %s
960 ";
961
962 $res = $DIC->database()->queryF($query, array('integer'), array(1));
963
964 $objects = array();
965
966 while ($row = $DIC->database()->fetchAssoc($res)) {
967 $objects[] = (int) $row['obj_id'];
968 }
969
970 return $objects;
971 }
972
973
974
977
978 protected bool $_highscore_enabled = false;
979
980 protected int $anonymity = 0;
981
982 protected bool $_highscore_achieved_ts = true;
983
984 protected bool $_highscore_percentage = true;
985
986 protected bool $_highscore_wtime = true;
987
988 protected bool $_highscore_own_table = true;
989
990 protected bool $_highscore_top_table = true;
991
992 protected int $_highscore_top_num = 10;
993
995 public const HIGHSCORE_SHOW_TOP_TABLE = 2;
996 public const HIGHSCORE_SHOW_OWN_TABLE = 3;
997
1001 public function setHighscoreEnabled(bool $a_enabled): void
1002 {
1003 $this->_highscore_enabled = $a_enabled;
1004 }
1005
1010 public function getHighscoreEnabled(): bool
1011 {
1013 }
1014
1018 public function setHighscoreAchievedTS(bool $a_achieved_ts): void
1019 {
1020 $this->_highscore_achieved_ts = $a_achieved_ts;
1021 }
1022
1027 public function getHighscoreAchievedTS(): bool
1028 {
1030 }
1031
1035 public function setHighscorePercentage(bool $a_percentage): void
1036 {
1037 $this->_highscore_percentage = $a_percentage;
1038 }
1039
1044 public function getHighscorePercentage(): bool
1045 {
1047 }
1048
1052 public function setHighscoreWTime(bool $a_wtime): void
1053 {
1054 $this->_highscore_wtime = $a_wtime;
1055 }
1056
1061 public function getHighscoreWTime(): bool
1062 {
1064 }
1065
1070 public function setHighscoreOwnTable(bool $a_own_table): void
1071 {
1072 $this->_highscore_own_table = $a_own_table;
1073 }
1074
1079 public function getHighscoreOwnTable(): bool
1080 {
1082 }
1083
1087 public function setHighscoreTopTable(bool $a_top_table): void
1088 {
1089 $this->_highscore_top_table = $a_top_table;
1090 }
1091
1096 public function getHighscoreTopTable(): bool
1097 {
1099 }
1100
1106 public function setHighscoreTopNum(int $a_top_num): void
1107 {
1108 $this->_highscore_top_num = $a_top_num;
1109 }
1110
1117 public function getHighscoreTopNum(?int $a_retval = 10): ?int
1118 {
1119 $retval = $a_retval;
1120 if ($this->_highscore_top_num != 0) {
1121 $retval = $this->_highscore_top_num;
1122 }
1123
1124 return $retval;
1125 }
1126
1127 public function getHighscoreMode(): int
1128 {
1129 switch (true) {
1130 case $this->getHighscoreOwnTable() && $this->getHighscoreTopTable():
1132
1133 case $this->getHighscoreTopTable():
1135
1136 case $this->getHighscoreOwnTable():
1137 default:
1139 }
1140 }
1141
1142
1143 public function setHighscoreMode(int $mode): void
1144 {
1145 switch ($mode) {
1147 $this->setHighscoreTopTable(true);
1148 $this->setHighscoreOwnTable(true);
1149 break;
1150
1152 $this->setHighscoreTopTable(true);
1153 $this->setHighscoreOwnTable(false);
1154 break;
1155
1157 default:
1158 $this->setHighscoreTopTable(false);
1159 $this->setHighscoreOwnTable(true);
1160 break;
1161 }
1162 }
1163
1164 /* End GET/SET for highscore feature */
1165
1169 public function getDataSetMapping(): array
1170 {
1171 if (null === ($lrsTypeId = $this->getLrsTypeId())) {
1172 $this->doRead();
1173 }
1174 return [
1175 'obj_id' => $this->getId(),
1176 'lrs_type_id' => $this->getLrsTypeId(),
1177 'content_type' => $this->getContentType(),
1178 'source_type' => $this->getSourceType(),
1179 'activity_id' => $this->getActivityId(),
1180 'publisher_id' => $this->getPublisherId(),
1181 'instructions' => $this->getInstructions(),
1182 'launch_url' => $this->getLaunchUrl(),
1183 'launch_parameters' => $this->getLaunchParameters(),
1184 'moveon' => $this->getMoveOn(),
1185 'entitlement_key' => $this->getEntitlementKey(),
1186 'auth_fetch_url' => (int) $this->isAuthFetchUrlEnabled(),
1187 'launch_method' => $this->getLaunchMethod(),
1188 'launch_mode' => $this->getLaunchMode(),
1189 'switch_to_review' => (int) $this->isSwitchToReviewEnabled(),
1190 'mastery_score' => $this->getMasteryScore(),
1191 'keep_lp' => (int) $this->isKeepLpStatusEnabled(),
1192 'privacy_ident' => $this->getPrivacyIdent(),
1193 'privacy_name' => $this->getPrivacyName(),
1194 'usr_privacy_comment' => $this->getUserPrivacyComment(),
1195 'show_statements' => (int) $this->isStatementsReportEnabled(),
1196 'xml_manifest' => $this->getXmlManifest(),
1197 'version' => $this->getVersion(),
1198 'highscore_enabled' => (int) $this->getHighscoreEnabled(),
1199 'highscore_achieved_ts' => (int) $this->getHighscoreAchievedTS(),
1200 'highscore_percentage' => (int) $this->getHighscorePercentage(),
1201 'highscore_wtime' => (int) $this->getHighscoreWTime(),
1202 'highscore_own_table' => (int) $this->getHighscoreOwnTable(),
1203 'highscore_top_table' => (int) $this->getHighscoreTopTable(),
1204 'highscore_top_num' => $this->getHighscoreTopNum(),
1205 'only_moveon' => (int) $this->getOnlyMoveon(),
1206 'achieved' => (int) $this->getAchieved(),
1207 'answered' => (int) $this->getAnswered(),
1208 'completed' => (int) $this->getCompleted(),
1209 'failed' => (int) $this->getFailed(),
1210 'initialized' => (int) $this->getInitialized(),
1211 'passed' => (int) $this->getPassed(),
1212 'progressed' => (int) $this->getProgressed(),
1213 'satisfied' => (int) $this->getSatisfied(),
1214 'c_terminated' => (int) $this->getTerminated(),
1215 'hide_data' => (int) $this->getHideData(),
1216 'c_timestamp' => (int) $this->getTimestamp(),
1217 'duration' => (int) $this->getDuration(),
1218 'no_substatements' => (int) $this->getNoSubstatements()
1219 //'bypass_proxy' => (int) $this->isBypassProxyEnabled()
1220 ];
1221 }
1222
1228 protected function doCloneObject(ilObject2 $new_obj, int $a_target_id, ?int $a_copy_id = null): void
1229 {
1230 assert($new_obj instanceof ilObjCmiXapi);
1231
1232 $this->cloneMetaData($new_obj);
1233
1234 $new_obj->setLrsTypeId($this->getLrsTypeId());
1235 $new_obj->setContentType($this->getContentType());
1236 $new_obj->setSourceType($this->getSourceType());
1237 $new_obj->setActivityId($this->getActivityId());
1238 $new_obj->setPublisherId($this->getPublisherId());
1239 $new_obj->setInstructions($this->getInstructions());
1240 $new_obj->setLaunchUrl($this->getLaunchUrl());
1241 $new_obj->setLaunchParameters($this->getLaunchParameters());
1242 $new_obj->setMoveOn($this->getMoveOn());
1243 $new_obj->setEntitlementKey($this->getEntitlementKey());
1244 $new_obj->setAuthFetchUrlEnabled($this->isAuthFetchUrlEnabled());
1245 $new_obj->setLaunchMethod($this->getLaunchMethod());
1246 $new_obj->setLaunchMode($this->getLaunchMode());
1247 $new_obj->setSwitchToReviewEnabled($this->isSwitchToReviewEnabled());
1248 $new_obj->setMasteryScore($this->getMasteryScore());
1249 $new_obj->setKeepLpStatusEnabled($this->isKeepLpStatusEnabled());
1250 $new_obj->setPrivacyIdent($this->getPrivacyIdent());
1251 $new_obj->setPrivacyName($this->getPrivacyName());
1252 $new_obj->setUserPrivacyComment($this->getUserPrivacyComment());
1253 $new_obj->setStatementsReportEnabled($this->isStatementsReportEnabled());
1254 $new_obj->setXmlManifest($this->getXmlManifest());
1255 $new_obj->setVersion($this->getVersion());
1256 $new_obj->setHighscoreEnabled($this->getHighscoreEnabled());
1257 $new_obj->setHighscoreAchievedTS($this->getHighscoreAchievedTS());
1258 $new_obj->setHighscorePercentage($this->getHighscorePercentage());
1259 $new_obj->setHighscoreWTime($this->getHighscoreWTime());
1260 $new_obj->setHighscoreOwnTable($this->getHighscoreOwnTable());
1261 $new_obj->setHighscoreTopTable($this->getHighscoreTopTable());
1262 $new_obj->setHighscoreTopNum($this->getHighscoreTopNum());
1263 $new_obj->setBypassProxyEnabled($this->isBypassProxyEnabled());
1264 $new_obj->setOnlyMoveon($this->getOnlyMoveon());
1265 $new_obj->setAchieved($this->getAchieved());
1266 $new_obj->setAnswered($this->getAnswered());
1267 $new_obj->setCompleted($this->getCompleted());
1268 $new_obj->setFailed($this->getFailed());
1269 $new_obj->setInitialized($this->getInitialized());
1270 $new_obj->setPassed($this->getPassed());
1271 $new_obj->setProgressed($this->getProgressed());
1272 $new_obj->setSatisfied($this->getSatisfied());
1273 $new_obj->setTerminated($this->getTerminated());
1274 $new_obj->setHideData($this->getHideData());
1275 $new_obj->setTimestamp($this->getTimestamp());
1276 $new_obj->setDuration($this->getDuration());
1277 $new_obj->setNoSubstatements($this->getNoSubstatements());
1278 $new_obj->update();
1279
1280 if ($this->getSourceType() == self::SRC_TYPE_LOCAL) {
1281 $dirUtil = new ilCmiXapiContentUploadImporter($new_obj);
1282 $dirUtil->ensureCreatedObjectDirectory();
1283 $newDir = implode(DIRECTORY_SEPARATOR, [ilFileUtils::getWebspaceDir(), $dirUtil->getWebDataDirRelativeObjectDirectory()]);
1284 $dirUtil = new ilCmiXapiContentUploadImporter($this);
1285 $thisDir = implode(DIRECTORY_SEPARATOR, [ilFileUtils::getWebspaceDir(), $dirUtil->getWebDataDirRelativeObjectDirectory()]);
1286 ilFileUtils::rCopy($thisDir, $newDir);
1287 }
1288 }
1289
1290 protected function doDelete(): void
1291 {
1292 // delete file data entry
1293 $query = "DELETE FROM " . self::DB_TABLE_NAME . " WHERE obj_id = " . $this->database->quote($this->getId(), 'integer');
1294 $this->database->manipulate($query);
1296
1297 // delete entire directory and its content
1298 $dirUtil = new ilCmiXapiContentUploadImporter($this);
1299 $thisDir = implode(DIRECTORY_SEPARATOR, [ilFileUtils::getWebspaceDir(), $dirUtil->getWebDataDirRelativeObjectDirectory()]);
1300 if (is_dir($thisDir)) {
1301 ilFileUtils::delDir($thisDir);
1302 }
1303
1304 // delete meta data
1305 $this->deleteMetaData();
1306
1307 //delete results
1308 $query = "DELETE FROM " . self::DB_RESULTS_TABLE_NAME .
1309 " WHERE obj_id = " . $this->database->quote($this->getId(), 'integer');
1310 $this->database->manipulate($query);
1311
1312 // TODO check xapidel
1313 }
1314
1315 // /**
1316 // * @return string[]
1317 // */
1318 // public function getRegistrations() : array
1319 // {
1320 // global $DIC;
1321 // $res = $DIC->database()->queryF(
1322 // "SELECT DISTINCT registration FROM " . self::DB_USERS_TABLE_NAME . " WHERE obj_id = %s",
1323 // array('text'),
1324 // array($this->getId())
1325 // );
1326 // $ret = [];
1327 // while ($row = $DIC->database()->fetchAssoc($res)) {
1328 // $ret[] = (string) $row['registration'];
1329 // }
1330 // return $ret;
1331 // }
1332
1336 public static function guidv4(?string $data = null): string
1337 {
1338 // Generate 16 bytes (128 bits) of random data or use the data passed into the function.
1339 $data ??= random_bytes(16);
1340 assert(strlen($data) == 16);
1341
1342 // Set version to 0100
1343 $data[6] = chr(ord($data[6]) & 0x0f | 0x40);
1344 // Set bits 6-7 to 10
1345 $data[8] = chr(ord($data[8]) & 0x3f | 0x80);
1346
1347 // Output the 36 character UUID.
1348 return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
1349 }
1350
1352 {
1353 global $DIC;
1354 if (null === $this->currentCmixUser) {
1355 $this->currentCmixUser = new ilCmiXapiUser($this->getId(), $DIC->user()->getId(), $this->getPrivacyIdent());
1356 }
1358 }
1359
1363 public function getSessionId(?ilCmiXapiUser $cmixUser = null): string
1364 {
1365 if (null === $cmixUser) {
1366 $cmixUser = $this->getCurrentCmixUser();
1367 }
1368 return ilCmiXapiAuthToken::getCmi5SessionByUsrIdAndObjIdAndRefId($cmixUser->getUsrId(), $this->getId(), $this->getRefId());
1369 }
1370
1375 public function getLaunchData(?ilCmiXapiUser $cmixUser = null, string $lang = 'en', ?int $launchedByRefId = null): array
1376 {
1377 global $DIC;
1378 if (null === $cmixUser) {
1379 $cmixUser = $this->getCurrentCmixUser();
1380 }
1381 // ToDo
1382 $moveOn = $this->getLMSMoveOn();
1383 if (!$moveOn || $moveOn == '') {
1384 $moveOn = 'Completed';
1385 }
1386 $launchMode = $this->getLaunchMode();
1387 // only check switch if self::LAUNCH_MODE_NORMAL
1388 if ($launchMode == self::LAUNCH_MODE_NORMAL) {
1389 if ($cmixUser->getSatisfied() && $this->isSwitchToReviewEnabled()) {
1391 }
1392 }
1393 $ctxTemplate = [
1394 "contextTemplate" => $this->getLaunchedContextTemplate($cmixUser),
1395 "launchMode" => ucfirst($launchMode),
1396 "launchMethod" => "OwnWindow",
1397 "moveOn" => $moveOn
1398 ];
1399 $lmsLaunchMethod = $this->getLaunchMethod();
1400 if ($lmsLaunchMethod === "ownWin") {
1401 if (is_int($launchedByRefId)) {
1402 $href = ilLink::_getStaticLink(
1403 $launchedByRefId,
1405 );
1406 } else {
1407 $href = ilLink::_getStaticLink(
1408 $this->getRefId(),
1409 $this->getType()
1410 );
1411 }
1412 $ctxTemplate['returnURL'] = $href;
1413 } else {
1414 $ctxTemplate['returnURL'] = ILIAS_HTTP_PATH . "/Modules/CmiXapi/xapiexit.php?lang={$lang}";
1415 }
1416 if (!empty($this->getMasteryScore())) {
1417 $ctxTemplate['masteryScore'] = $this->getMasteryScore();
1418 }
1419 if (!empty($this->getLaunchParameters())) {
1420 $ctxTemplate['launchParameters'] = $this->getLaunchParameters();
1421 }
1422 if (!empty($this->getEntitlementKey())) {
1423 $ctxTemplate['entitlementKey'] = array("courseStructure" => $this->getEntitlementKey());
1424 }
1425 return $ctxTemplate;
1426 }
1427
1431 public function getLaunchedContextTemplate(?ilCmiXapiUser $cmixUser = null): array
1432 {
1433 if (null === $cmixUser) {
1434 $cmixUser = $this->getCurrentCmixUser();
1435 }
1436 $launchMode = $this->getLaunchMode();
1437 // only check switch if self::LAUNCH_MODE_NORMAL
1438 if ($launchMode == self::LAUNCH_MODE_NORMAL) {
1439 if ($cmixUser->getSatisfied() && $this->isSwitchToReviewEnabled()) {
1441 }
1442 }
1443 $extensions = $this->getStatementExtensions($cmixUser);
1444 $extensions['https://w3id.org/xapi/cmi5/context/extensions/launchmode'] = $launchMode;
1445 if (!empty($this->getLMSMoveOn())) {
1446 $extensions['https://w3id.org/xapi/cmi5/context/extensions/moveon'] = $this->getLMSMoveOn();
1447 }
1448 if (!empty($this->getLaunchParameters())) {
1449 $extensions['https://w3id.org/xapi/cmi5/context/extensions/launchparameters'] = $this->getLaunchParameters();
1450 }
1451 if (!empty($this->getMasteryScore())) {
1452 $extensions['https://w3id.org/xapi/cmi5/context/extensions/masteryscore'] = $this->getMasteryScore();
1453 }
1454 return array(
1455 "contextActivities" => $this->getStatementContextActivities(),
1456 "extensions" => $extensions
1457 );
1458 }
1459
1465 public function getStatement(string $verb, ?ilCmiXapiUser $cmixUser = null): array
1466 {
1467 if (null === $cmixUser) {
1468 $cmixUser = $this->getCurrentCmixUser();
1469 }
1470 $id = self::guidv4();
1471 $actor = $this->getStatementActor($cmixUser);
1472 $verbUri = ilCmiXapiVerbList::getInstance()->getVerbUri($verb);
1473 $extensions = $this->getStatementExtensions($cmixUser);
1474 $registration = $cmixUser->getRegistration();
1475 $contextActivities = $this->getStatementContextActivities();
1476 $object = $this->getStatementObject();
1477 return array(
1478 'id' => $id,
1479 'actor' => $actor,
1480 'verb' =>
1481 array(
1482 'id' => $verbUri
1483 ),
1484 'context' =>
1485 array(
1486 'extensions' => $extensions,
1487 'registration' => $registration,
1488 'contextActivities' => $contextActivities
1489 ),
1490 'object' => $object
1491 );
1492 }
1493
1498 public function getStatementActor(?ilCmiXapiUser $cmixUser = null): array
1499 {
1500 global $DIC;
1501 if (null === $cmixUser) {
1502 $cmixUser = $this->getCurrentCmixUser();
1503 }
1504 $user = new ilObjUser($cmixUser->getUsrId()); // ToDo: Caching Names
1506 if ($name == '') {
1507 $this->log()->error('error: no name in cmixuser');
1508 $name = 'UNDEFINED';
1509 }
1510 $homePage = ($this->anonymousHomePage == true) ? self::ANONYMOUS_HOMEPAGE : self::iliasUrl();
1511 if ($this->getContentType() == self::CONT_TYPE_CMI5) {
1512 $actor = [
1513 'objectType' => 'Agent',
1514 'account' => [
1515 'homePage' => $homePage,
1516 'name' => $cmixUser->getUsrIdent()
1517 ]
1518 ];
1519 if ($name !== '') {
1520 $actor['name'] = $name;
1521 }
1522 } else {
1523 $actor = [
1524 'objectType' => 'Agent',
1525 'mbox' => 'mailto:' . $cmixUser->getUsrIdent()
1526 ];
1527 if ($name !== '') {
1528 $actor['name'] = $name;
1529 }
1530 }
1531 return $actor;
1532 }
1533
1539 public function getStatementExtensions(?ilCmiXapiUser $cmixUser = null): array
1540 {
1541 if (null === $cmixUser) {
1542 $cmixUser = $this->getCurrentCmixUser();
1543 }
1544 return array(
1545 'https://w3id.org/xapi/cmi5/context/extensions/sessionid' => $this->getSessionId($cmixUser),
1546 'https://ilias.de/cmi5/activityid' => $this->getActivityId()
1547 );
1548 }
1549
1554 public function getStatementContextActivities(): array
1555 {
1556 $publisherId = $this->getPublisherId();
1557 $activityId = $this->getActivityId();
1558 if (empty($publisherId)) {
1560 }
1561 return array(
1562 "grouping" => [
1563 [
1564 "objectType" => "Activity",
1565 "id" => "{$publisherId}",
1566 'definition' =>
1567 array(
1568 'name' =>
1569 array(
1570 'de-DE' => $this->getTitle(),
1571 'en-US' => $this->getTitle()
1572 ),
1573 'description' =>
1574 array(
1575 'de-DE' => $this->getDescription(),
1576 'en-US' => $this->getDescription()
1577 )
1578 )]
1579 ],
1580 "category" => [
1581 [
1582 "id" => "https://w3id.org/xapi/cmi5/context/categories/cmi5",
1583 "objectType" => "Activity"
1584 ]
1585 ]
1586 );
1587 }
1588
1592 public function getStatementObject(): array
1593 {
1594 return array(
1595 'id' => $this->getActivityId(),
1596 'definition' =>
1597 array(
1598 'name' =>
1599 array(
1600 'de-DE' => $this->getTitle(),
1601 'en-US' => $this->getTitle()
1602 ),
1603 'description' =>
1604 array(
1605 'de-DE' => $this->getDescription(),
1606 'en-US' => $this->getDescription()
1607 )
1608 )
1609 );
1610 }
1611
1616 public function getLaunchedStatement(?ilCmiXapiUser $cmixUser = null): array
1617 {
1618 if (null === $cmixUser) {
1619 $cmixUser = $this->getCurrentCmixUser();
1620 }
1621 $launchMode = $this->getLaunchMode();
1622 // only check switch if self::LAUNCH_MODE_NORMAL
1623 if ($launchMode == self::LAUNCH_MODE_NORMAL) {
1624 if ($cmixUser->getSatisfied() && $this->isSwitchToReviewEnabled()) {
1626 }
1627 }
1628
1629 $statement = $this->getStatement('launched', $cmixUser);
1630 $statement['context']['extensions']['https://w3id.org/xapi/cmi5/context/extensions/launchmode'] = $launchMode;
1631 if (!empty($this->getLMSMoveOn())) {
1632 $statement['context']['extensions']['https://w3id.org/xapi/cmi5/context/extensions/moveon'] = $this->getLMSMoveOn();
1633 }
1634 if (!empty($this->getLaunchParameters())) {
1635 $statement['context']['extensions']['https://w3id.org/xapi/cmi5/context/extensions/launchparameters'] = $this->getLaunchParameters();
1636 }
1637 if (!empty($this->getMasteryScore())) {
1638 $statement['context']['extensions']['https://w3id.org/xapi/cmi5/context/extensions/masteryscore'] = $this->getMasteryScore();
1639 }
1640 return $statement;
1641 }
1642
1647 public function getAbandonedStatement(?string $sessionId, ?string $duration, ?ilCmiXapiUser $cmixUser = null): array
1648 {
1649 if (null === $cmixUser) {
1650 $cmixUser = $this->getCurrentCmixUser();
1651 }
1652 $statement = $this->getStatement('abandoned', $cmixUser);
1653 // overwrite session with abandoned oldSession
1654 $statement['context']['extensions']['https://w3id.org/xapi/cmi5/context/extensions/sessionid'] = $sessionId;
1655 $statement['result'] = array(
1656 'duration' => $duration
1657 );
1658 return $statement;
1659 }
1660
1665 public function getSatisfiedStatement(?ilCmiXapiUser $cmixUser = null): array
1666 {
1667 if (null === $cmixUser) {
1668 $cmixUser = $this->getCurrentCmixUser();
1669 }
1670 $statement = $this->getStatement('satisfied', $cmixUser);
1671 // add type, see https://aicc.github.io/CMI-5_Spec_Current/samples/scenarios/16-not_applicable-no_launch/#satisfied-statement
1672 // see also: https://github.com/AICC/CMI-5_Spec_Current/blob/quartz/cmi5_spec.md#verbs_satisfied
1673 $type = "https://w3id.org/xapi/cmi5/activitytype/course";
1674 $statement['object']['definition']['type'] = $type;
1675 $statement['context']['contextActivities']['grouping'][0]['definition']['type'] = $type;
1676 return $statement;
1677 }
1678
1683 public function getLastStatement(string $sess)
1684 {
1685 global $DIC;
1686 $lrsType = $this->getLrsType();
1687
1688 //$this->getLrsEndpoint())) . '/api/' . self::ENDPOINT_AGGREGATE_SUFFIX;
1690 //$fallbackLrs = $lrsType->getLrsFallbackEndpoint();
1691 $defaultBasicAuth = $lrsType->getBasicAuth();
1692 //$fallbackBasicAuth = $lrsType->getFallbackBasicAuth();
1693 $defaultHeaders = [
1694 'X-Experience-API-Version' => '1.0.3',
1695 'Authorization' => $defaultBasicAuth,
1696 'Cache-Control' => 'no-cache, no-store, must-revalidate'
1697 ];
1698 /*
1699 $fallbackHeaders = [
1700 'X-Experience-API-Version' => '1.0.3',
1701 'Authorization' => $fallbackBasicAuth,
1702 'Content-Type' => 'application/json;charset=utf-8',
1703 'Cache-Control' => 'no-cache, no-store, must-revalidate'
1704 ];
1705 */
1706 $pipeline = json_encode($this->getLastStatementPipline($sess));
1707 $defaultLastStatementUrl = $defaultLrs . "?pipeline=" . urlencode($pipeline);
1708 $client = new GuzzleHttp\Client();
1709 $req_opts = array(
1710 GuzzleHttp\RequestOptions::VERIFY => true,
1711 GuzzleHttp\RequestOptions::CONNECT_TIMEOUT => 10,
1712 GuzzleHttp\RequestOptions::HTTP_ERRORS => false
1713 );
1714 $defaultLastStatementRequest = new GuzzleHttp\Psr7\Request(
1715 'GET',
1716 $defaultLastStatementUrl,
1717 $defaultHeaders
1718 );
1719 $promises = array();
1720 $promises['defaultLastStatement'] = $client->sendAsync($defaultLastStatementRequest, $req_opts);
1721 try {
1722 $responses = GuzzleHttp\Promise\Utils::settle($promises)->wait();
1723 $body = '';
1724 ilCmiXapiAbstractRequest::checkResponse($responses['defaultLastStatement'], $body, [200]);
1725 return json_decode($body, (bool) JSON_OBJECT_AS_ARRAY);
1726 } catch (Exception $e) {
1727 $this->log()->error('error:' . $e->getMessage());
1728 return null;
1729 }
1730 }
1731
1735 public function getLastStatementPipline(string $sess): array
1736 {
1737 global $DIC;
1738 $pipeline = array();
1739
1740 // filter activityId
1741 $match = array();
1742 $match['statement.object.objectType'] = 'Activity';
1743 $match['statement.actor.objectType'] = 'Agent';
1744
1745 $activityId = array();
1746
1747 if ($this->getContentType() == ilObjCmiXapi::CONT_TYPE_CMI5 && !$this->isMixedContentType()) {
1748 // https://github.com/AICC/CMI-5_Spec_Current/blob/quartz/cmi5_spec.md#963-extensions
1749 $activityId['statement.context.extensions.https://ilias&46;de/cmi5/activityid'] = $this->getActivityId();
1750 } else {
1751 $activityQuery = [
1752 '$regex' => '^' . preg_quote($this->getActivityId()) . ''
1753 ];
1754 $activityId['$or'] = [];
1755 $activityId['$or'][] = ['statement.object.id' => $activityQuery];
1756 $activityId['$or'][] = ['statement.context.contextActivities.parent.id' => $activityQuery];
1757 }
1758
1759 $sessionId = array();
1760 $sessionId['statement.context.extensions.https://w3id&46;org/xapi/cmi5/context/extensions/sessionid'] = $sess;
1761 $match['$and'] = array();
1762 $match['$and'][] = $activityId;
1763 $match['$and'][] = $sessionId;
1764 $sort = array('statement.timestamp' => -1);
1765 $project = array('statement.timestamp' => 1, 'statement.verb.id' => 1);
1766 $pipeline[] = array('$match' => $match);
1767 $pipeline[] = array('$sort' => $sort);
1768 $pipeline[] = array('$limit' => 1);
1769 $pipeline[] = array('$project' => $project);
1770
1771 return $pipeline;
1772 }
1773
1774 public static function iliasUrl(): string
1775 {
1776 global $DIC;
1777 $regex = '/^(https?:\/\/[^\/]+).*/';
1778 preg_match($regex, (string) $DIC->http()->request()->getUri(), $request_parts);
1779 return $request_parts[1];
1780 }
1781
1782 public static function log(): ilLogger
1783 {
1784 if (self::PLUGIN) {
1785 global $log;
1786 return $log;
1787 } else {
1788 return \ilLoggerFactory::getLogger('cmix');
1789 }
1790 }
1791
1792
1793 public function isActivationLimited(): ?bool
1794 {
1796 }
1797
1798
1799 public function setActivationLimited(bool $activationLimited): void
1800 {
1801 $this->activationLimited = $activationLimited;
1802 }
1803
1804 public function getActivationStartingTime(): ?int
1805 {
1807 }
1808
1809 public function setActivationStartingTime(?int $activationStartingTime = null): void
1810 {
1811 $this->activationStartingTime = $activationStartingTime;
1812 }
1813
1814 public function getActivationEndingTime(): ?int
1815 {
1817 }
1818
1819 public function setActivationEndingTime(?int $activationEndingTime = null): void
1820 {
1821 $this->activationEndingTime = $activationEndingTime;
1822 }
1823
1824 public function getActivationVisibility(): ?bool
1825 {
1827 }
1828
1830 {
1831 $this->activationVisibility = $activationVisibility;
1832 }
1833}
static checkResponse(array $response, &$body, array $allowedStatus=[200, 204])
static getCmi5SessionByUsrIdAndObjIdAndRefId(int $usrId, int $objId, ?int $refId=null)
const MOVEON_COMPLETED_OR_PASSED
const MOVEON_NOT_APPLICABLE
static getName(int $userNameMode, ilObjUser $user)
static getWebspaceDir(string $mode="filesystem")
get webspace directory
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static rCopy(string $a_sdir, string $a_tdir, bool $preserveTimeAttributes=false)
Copies content of a directory $a_sdir recursively to a directory $a_tdir.
static _removeEntriesForObject(int $a_obj_id)
remove all history entries for an object
const LP_MODE_CMIX_COMPL_OR_PASSED_WITH_FAILED
Component logger with individual log levels by component id.
getStatement(string $verb, ?ilCmiXapiUser $cmixUser=null)
blueprint statement
setActivationEndingTime(?int $activationEndingTime=null)
setDuration(bool $duration)
setBypassProxyEnabled(bool $bypassProxyEnabled)
setHighscoreMode(int $mode)
setOnlyMoveon(bool $only_moveon)
getHighscoreWTime()
Gets if the column with the workingtime should be shown.
setHideData(bool $hide_data)
getHighscoreTopNum(?int $a_retval=10)
Gets the number of entries which are to be shown in the top-rankings table.
setPrivacyName(int $userName)
setContentType(string $contentType)
getLPMode()
only for internal LMS usage
setNoSubstatements(bool $no_substatements)
ilCmiXapiUser $currentCmixUser
getSessionId(?ilCmiXapiUser $cmixUser=null)
static getObjectsHavingBypassProxyEnabledAndRegisteredUsers()
ilDBInterface $database
setActivationVisibility(bool $activationVisibility)
setHighscoreWTime(bool $a_wtime)
Sets if the workingtime of the scores should be shown.
const PRIVACY_IDENT_IL_UUID_USER_ID
setLaunchMethod(string $launchMethod)
getLaunchData(?ilCmiXapiUser $cmixUser=null, string $lang='en', ?int $launchedByRefId=null)
LMS.LaunchData.
setPublisherId(string $publisherId)
const HIGHSCORE_SHOW_ALL_TABLES
setHighscoreTopNum(int $a_top_num)
Sets the number of entries which are to be shown in the top-rankings table.
getHighscorePercentage()
Gets if the percentage column should be shown.
setSwitchToReviewEnabled(bool $switchToReviewEnabled)
setLaunchParameters(string $launchParameters)
const HIGHSCORE_SHOW_TOP_TABLE
setSatisfied(bool $satisfied)
setTimestamp(bool $timestamp)
getHighscoreAchievedTS()
Returns if date and time of the scores achievement should be displayed.
setTerminated(bool $terminated)
const PRIVACY_IDENT_IL_UUID_RANDOM
doCloneObject(ilObject2 $new_obj, int $a_target_id, ?int $a_copy_id=null)
bool $activationLimited
repository object activation settings (handled by ilObject)
setAnswered(bool $answered)
getLaunchedContextTemplate(?ilCmiXapiUser $cmixUser=null)
getHighscoreTopTable()
Gets, if the top-rankings table should be shown.
setSourceType(string $sourceType)
setStatementsReportEnabled(bool $statementsReportEnabled)
bool $_highscore_enabled
HIGHSCORE.
setHighscoreOwnTable(bool $a_own_table)
Sets if the table with the own ranking should be shown.
getStatementExtensions(?ilCmiXapiUser $cmixUser=null)
Minimal extensions.
getSatisfiedStatement(?ilCmiXapiUser $cmixUser=null)
static guidv4(?string $data=null)
setLrsTypeId(int $lrsTypeId)
const PRIVACY_IDENT_IL_UUID_LOGIN
setAchieved(bool $achieved)
getLaunchedStatement(?ilCmiXapiUser $cmixUser=null)
setMoveOn(string $moveOn)
Attention: this is the original moveOn from course import should only be set on import!
setLaunchMode(string $launchMode)
getMoveOn()
Attention: this is the original imported moveOn for using in LaunchData and LaunchStatement use getLM...
const PRIVACY_IDENT_REAL_EMAIL
setMasteryScorePercent(float $masteryScorePercent)
const PRIVACY_IDENT_IL_UUID_SHA256
setProgressed(bool $progressed)
getLMSMoveOn()
for CMI5 statements | state moveOn values
setInstructions(string $instructions)
setXmlManifest(string $xmlManifest)
const PRIVACY_IDENT_IL_UUID_EXT_ACCOUNT
setHighscoreTopTable(bool $a_top_table)
Sets if the top-rankings table should be shown.
ilCmiXapiLrsType $lrsType
getStatementContextActivities()
Minimal statementActivities.
setInitialized(bool $initialized)
getHighscoreOwnTable()
Gets if the own rankings table should be shown.
getLastStatement(string $sess)
get latest statement from session
setCompleted(bool $completed)
__construct(int $a_id=0, bool $a_reference=true)
ilObjCmiXapi constructor.
const HIGHSCORE_SHOW_OWN_TABLE
const PRIVACY_IDENT_IL_UUID_SHA256URL
setMasteryScore(float $masteryScore)
setHighscoreAchievedTS(bool $a_achieved_ts)
Sets if the date and time of the scores achievement should be displayed.
setActivationLimited(bool $activationLimited)
setPassed(bool $passed)
getHighscoreEnabled()
Gets the setting which determines if the highscore feature is enabled.
setActivationStartingTime(?int $activationStartingTime=null)
setVersion(int $version)
setLaunchUrl(string $launchUrl)
setLrsType(\ilCmiXapiLrsType $lrsType)
setUserPrivacyComment(string $userPrivacyComment)
setEntitlementKey(string $entitlementKey)
setHighscoreEnabled(bool $a_enabled)
Sets if the highscore feature should be enabled.
static updatePrivacySettingsFromLrsType(ilCmiXapiLrsType $lrsType)
static updateByPassProxyFromLrsType(ilCmiXapiLrsType $lrsType)
setFailed(bool $failed)
setKeepLpStatusEnabled(bool $keepLpStatusEnabled)
setAuthFetchUrlEnabled(bool $authFetchUrlEnabled)
setHighscorePercentage(bool $a_percentage)
Sets if the percentages of the scores pass should be shown.
static getInstance(int $a_id=0, bool $a_reference=true)
getAbandonedStatement(?string $sessionId, ?string $duration, ?ilCmiXapiUser $cmixUser=null)
setActivityId(string $activityId)
getLastStatementPipline(string $sess)
getStatementActor(?ilCmiXapiUser $cmixUser=null)
statement actor
setPrivacyIdent(int $userIdent)
User class.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
cloneMetaData(ilObject $target_obj)
Copy meta data.
Class ilObjectActivation.
static getItem(int $ref_id)
static getInstance(int $obj_id)
static _lookupType(int $id, bool $reference=false)
ilLogger $log
ilObjUser $user
string $type
static _lookupObjId(int $ref_id)
$client
global $DIC
Definition: feed.php:28
Interface ilDBInterface.
$res
Definition: ltiservices.php:69
if($format !==null) $name
Definition: metadata.php:247
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
$query
$lang
Definition: xapiexit.php:26