ILIAS  trunk Revision v12.0_alpha-377-g3641b37b9db
class.ilObjCmiXapi.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
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
148 protected int $deleteData = 0;
149
150 protected bool $enrichData = false;
151
153
155
159 public function __construct(int $a_id = 0, bool $a_reference = true)
160 {
161 global $DIC;
162 $this->database = $DIC->database();
163
164 $this->lrsTypeId = 0;
165
166 $this->contentType = self::CONT_TYPE_GENERIC;
167 $this->sourceType = self::SRC_TYPE_REMOTE;
168
169 $this->activityId = '';
170
171 $this->publisherId = '';
172
173 $this->instructions = '';
174
175 $this->launchUrl = '';
176 $this->launchParameters = '';
177 $this->moveOn = '';
178 $this->entitlementKey = '';
179
180 $this->authFetchUrlEnabled = false;
181
182 $this->launchMethod = self::LAUNCH_METHOD_NEW_WIN;
183 $this->launchMode = self::LAUNCH_MODE_NORMAL;
184
185 $this->switchToReviewEnabled = true;
186
187 $this->masteryScore = self::LMS_MASTERY_SCORE;
188 $this->keepLpStatusEnabled = true;
189
190 $this->userIdent = self::PRIVACY_IDENT_IL_UUID_USER_ID;
191 $this->userName = self::PRIVACY_NAME_NONE;
192 $this->userPrivacyComment = '';
193
194 $this->currentCmixUser = null;
195
196 $this->statementsReportEnabled = false;
197
198 $this->xmlManifest = '';
199 $this->version = 0;
200
201 $this->bypassProxyEnabled = false;
202
203 parent::__construct($a_id, $a_reference);
204 }
205
206
207 public static function getInstance(int $a_id = 0, bool $a_reference = true): \ilObjCmiXapi
208 {
209 return new self($a_id, $a_reference);
210 }
211
212 protected function initType(): void
213 {
214 $this->type = "cmix";
215 }
216
217 public function getLrsTypeId(): ?int
218 {
219 return $this->lrsTypeId;
220 }
221
222 public function setLrsTypeId(int $lrsTypeId): void
223 {
224 $this->lrsTypeId = $lrsTypeId;
225 }
226
227 public function getLrsType(): \ilCmiXapiLrsType
228 {
229 return $this->lrsType;
230 }
231
232 public function setLrsType(\ilCmiXapiLrsType $lrsType): void
233 {
234 $this->lrsType = $lrsType;
235 }
236
237 public function initLrsType(): void
238 {
239 $this->setLrsType(new ilCmiXapiLrsType($this->getLrsTypeId()));
240 }
241
242 public function getContentType(): string
243 {
244 return $this->contentType;
245 }
246
247 public function setContentType(string $contentType): void
248 {
249 //bug before 21-07-24
250 if ($contentType == "learning") {
252 }
253 $this->contentType = $contentType;
254 }
255
256 public function isMixedContentType(): bool
257 {
258 // after 21-07-24 and before cmi5 refactoring
259 // launched before cmi5 refactoring ident in: statement.actor.mbox
260 // launched after cmi5 refactoring ident in: statement.actor.account.name
261 return (($this->getContentType() == self::CONT_TYPE_CMI5) && empty($this->getPublisherId()));
262 }
263
264 public function getSourceType(): string
265 {
266 return $this->sourceType;
267 }
268
269 public function isSourceTypeRemote(): bool
270 {
271 return $this->sourceType == self::SRC_TYPE_REMOTE;
272 }
273
274 public function isSourceTypeExternal(): bool
275 {
276 return $this->sourceType == self::SRC_TYPE_EXTERNAL;
277 }
278
279 public function setSourceType(string $sourceType): void
280 {
281 $this->sourceType = $sourceType;
282 }
283
284 public function getActivityId(): string
285 {
286 return $this->activityId;
287 }
288
289 public function setActivityId(string $activityId): void
290 {
291 $this->activityId = $activityId;
292 }
293
294 public function getPublisherId(): string
295 {
296 return $this->publisherId;
297 }
298
299 public function setPublisherId(string $publisherId): void
300 {
301 $this->publisherId = $publisherId;
302 }
303
304 public function getInstructions(): string
305 {
306 return $this->instructions;
307 }
308
309 public function setInstructions(string $instructions): void
310 {
311 $this->instructions = $instructions;
312 }
313
314 public function getLaunchUrl(): string
315 {
316 return $this->launchUrl;
317 }
318
319 public function setLaunchUrl(string $launchUrl): void
320 {
321 $this->launchUrl = $launchUrl;
322 }
323
324 public function getLaunchParameters(): string
325 {
327 }
328
329 public function setLaunchParameters(string $launchParameters): void
330 {
331 $this->launchParameters = $launchParameters;
332 }
333
338 public function getMoveOn(): string
339 {
340 return $this->moveOn;
341 }
342
347 public function setMoveOn(string $moveOn): void
348 {
349 $this->moveOn = $moveOn;
350 }
351
356 public function getLPMode(): int
357 {
358 $olp = ilObjectLP::getInstance($this->getId());
359 return $olp->getCurrentMode();
360 }
361
366 public function getLMSMoveOn(): string
367 {
369 switch ($this->getLPMode()) {
372 break;
376 break;
380 break;
384 break;
385 }
386 return $moveOn;
387 }
388
389 public function getEntitlementKey(): string
390 {
392 }
393
394 public function setEntitlementKey(string $entitlementKey): void
395 {
396 $this->entitlementKey = $entitlementKey;
397 }
398
399 public function isAuthFetchUrlEnabled(): bool
400 {
402 }
403
405 {
406 $this->authFetchUrlEnabled = $authFetchUrlEnabled;
407 }
408
409 public function getLaunchMethod(): string
410 {
411 return $this->launchMethod;
412 }
413
414 public function setLaunchMethod(string $launchMethod): void
415 {
416 $this->launchMethod = $launchMethod;
417 }
418
419 public function getLaunchMode(): string
420 {
421 return ucfirst($this->launchMode);
422 }
423
424 public function setLaunchMode(string $launchMode): void
425 {
426 $this->launchMode = ucfirst($launchMode);
427 }
428
429 public function isSwitchToReviewEnabled(): bool
430 {
432 }
433
434 public function getSwitchToReviewEnabled(): bool
435 {
437 }
438
440 {
441 $this->switchToReviewEnabled = $switchToReviewEnabled;
442 }
443
444 public function getMasteryScore(): float
445 {
446 return $this->masteryScore;
447 }
448
449 public function setMasteryScore(float $masteryScore): void
450 {
451 $this->masteryScore = $masteryScore;
452 }
453
454 public function getMasteryScorePercent(): float
455 {
456 return $this->masteryScore * 100;
457 }
458
459 public function setMasteryScorePercent(float $masteryScorePercent): void
460 {
461 $this->masteryScore = $masteryScorePercent / 100;
462 }
463
464 public function isKeepLpStatusEnabled(): bool
465 {
467 }
468
470 {
471 $this->keepLpStatusEnabled = $keepLpStatusEnabled;
472 }
473
474 public function getPrivacyIdent(): int
475 {
476 return $this->userIdent;
477 }
478
479 public function setPrivacyIdent(int $userIdent): void
480 {
481 $this->userIdent = $userIdent;
482 }
483
484 public function getPrivacyName(): int
485 {
486 return $this->userName;
487 }
488
489 public function setPrivacyName(int $userName): void
490 {
491 $this->userName = $userName;
492 }
493
494 public function getOnlyMoveon(): bool
495 {
496 return $this->only_moveon;
497 }
498
499 public function setOnlyMoveon(bool $only_moveon): void
500 {
501 $this->only_moveon = $only_moveon;
502 }
503
504 public function getAchieved(): bool
505 {
506 return $this->achieved;
507 }
508
509 public function setAchieved(bool $achieved): void
510 {
511 $this->achieved = $achieved;
512 }
513
514 public function getAnswered(): bool
515 {
516 return $this->answered;
517 }
518
519 public function setAnswered(bool $answered): void
520 {
521 $this->answered = $answered;
522 }
523
524 public function getCompleted(): bool
525 {
526 return $this->completed;
527 }
528
529 public function setCompleted(bool $completed): void
530 {
531 $this->completed = $completed;
532 }
533
534 public function getFailed(): bool
535 {
536 return $this->failed;
537 }
538
539 public function setFailed(bool $failed): void
540 {
541 $this->failed = $failed;
542 }
543
544 public function getInitialized(): bool
545 {
546 return $this->initialized;
547 }
548
549 public function setInitialized(bool $initialized): void
550 {
551 $this->initialized = $initialized;
552 }
553
554 public function getPassed(): bool
555 {
556 return $this->passed;
557 }
558
559 public function setPassed(bool $passed): void
560 {
561 $this->passed = $passed;
562 }
563
564 public function getProgressed(): bool
565 {
566 return $this->progressed;
567 }
568
569 public function setProgressed(bool $progressed): void
570 {
571 $this->progressed = $progressed;
572 }
573
574 public function getSatisfied(): bool
575 {
576 return $this->satisfied;
577 }
578
579 public function setSatisfied(bool $satisfied): void
580 {
581 $this->satisfied = $satisfied;
582 }
583
584 public function getTerminated(): bool
585 {
586 return $this->terminated;
587 }
588
589 public function setTerminated(bool $terminated): void
590 {
591 $this->terminated = $terminated;
592 }
593
594 public function getHideData(): bool
595 {
596 return $this->hide_data;
597 }
598
599 public function setHideData(bool $hide_data): void
600 {
601 $this->hide_data = $hide_data;
602 }
603
604 public function getTimestamp(): bool
605 {
606 return $this->timestamp;
607 }
608
609 public function setTimestamp(bool $timestamp): void
610 {
611 $this->timestamp = $timestamp;
612 }
613
614 public function getDuration(): bool
615 {
616 return $this->duration;
617 }
618
619 public function setDuration(bool $duration): void
620 {
621 $this->duration = $duration;
622 }
623
624 public function getNoSubstatements(): bool
625 {
627 }
628
629 public function setNoSubstatements(bool $no_substatements): void
630 {
631 $this->no_substatements = $no_substatements;
632 }
633
634 public function getDeleteData(): int
635 {
636 return $this->deleteData;
637 }
638
639 public function setDeleteData(int $deleteData): void
640 {
641 $this->deleteData = $deleteData;
642 }
643
644 public function getUserPrivacyComment(): string
645 {
647 }
648
649 public function setUserPrivacyComment(string $userPrivacyComment): void
650 {
651 $this->userPrivacyComment = $userPrivacyComment;
652 }
653
654 public function isStatementsReportEnabled(): bool
655 {
657 }
658
660 {
661 $this->statementsReportEnabled = $statementsReportEnabled;
662 }
663
664 public function getXmlManifest(): string
665 {
666 return $this->xmlManifest;
667 }
668
669 public function setXmlManifest(string $xmlManifest): void
670 {
671 $this->xmlManifest = $xmlManifest;
672 }
673
674 public function getVersion(): int
675 {
676 return $this->version;
677 }
678
679 public function setVersion(int $version): void
680 {
681 $this->version = $version;
682 }
683
684 public function isBypassProxyEnabled(): bool
685 {
687 }
688
689 public function setBypassProxyEnabled(bool $bypassProxyEnabled): void
690 {
691 $this->bypassProxyEnabled = $bypassProxyEnabled;
692 }
693
694 public function getEnrichData(): bool
695 {
696 return $this->enrichData;
697 }
698
699 public function setEnrichData(bool $enrichData): void
700 {
701 $this->enrichData = $enrichData;
702 }
703
704 protected function doRead(): void
705 {
706 $this->load();
707 }
708
709 protected function load(): void
710 {
711 $query = "SELECT * FROM " . self::DB_TABLE_NAME . " WHERE obj_id = %s";
712 $res = $this->database->queryF($query, ['integer'], [$this->getId()]);
713
714 while ($row = $this->database->fetchAssoc($res)) {
715 if ($row['lrs_type_id']) {
716 $this->setLrsTypeId((int) $row['lrs_type_id']);
717 $this->initLrsType();
718 }
719
720 $this->setContentType((string) $row['content_type']);
721 $this->setSourceType((string) $row['source_type']);
722
723 $this->setActivityId((string) $row['activity_id']);
724 $this->setPublisherId((string) $row['publisher_id']);
725 $this->setInstructions((string) $row['instructions']);
726
727 $this->setLaunchUrl((string) $row['launch_url']);
728 $this->setLaunchParameters((string) $row['launch_parameters']);
729 $this->setMoveOn((string) $row['moveon']);
730 $this->setEntitlementKey((string) $row['entitlement_key']);
731 $this->setAuthFetchUrlEnabled((bool) $row['auth_fetch_url']);
732
733 $this->setLaunchMethod((string) $row['launch_method']);
734
735 $this->setLaunchMode((string) $row['launch_mode']);
736 $this->setSwitchToReviewEnabled((bool) $row['switch_to_review']);
737 $this->setMasteryScore((float) $row['mastery_score']);
738 $this->setKeepLpStatusEnabled((bool) $row['keep_lp']);
739
740 $this->setPrivacyIdent((int) $row['privacy_ident']);
741 $this->setPrivacyName((int) $row['privacy_name']);
742
743 $this->setOnlyMoveon((bool) $row['only_moveon']);
744 $this->setAchieved((bool) $row['achieved']);
745 $this->setAnswered((bool) $row['answered']);
746 $this->setCompleted((bool) $row['completed']);
747 $this->setFailed((bool) $row['failed']);
748 $this->setInitialized((bool) $row['initialized']);
749 $this->setPassed((bool) $row['passed']);
750 $this->setProgressed((bool) $row['progressed']);
751 $this->setSatisfied((bool) $row['satisfied']);
752 $this->setTerminated((bool) $row['c_terminated']);
753 $this->setHideData((bool) $row['hide_data']);
754 $this->setTimestamp((bool) $row['c_timestamp']);
755 $this->setDuration((bool) $row['duration']);
756 $this->setNoSubstatements((bool) $row['no_substatements']);
757 $this->setEnrichData((bool) $row['enrich_data']);
758 $this->setDeleteData((int) $row['delete_data']);
759
760 $this->setUserPrivacyComment((string) $row['usr_privacy_comment']);
761
762 $this->setStatementsReportEnabled((bool) $row['show_statements']);
763
764 $this->setXmlManifest((string) $row['xml_manifest']);
765 $this->setVersion((int) $row['version']);
766
767 $this->setBypassProxyEnabled((bool) $row['bypass_proxy']);
768
769 $this->setHighscoreEnabled((bool) $row['highscore_enabled']);
770 $this->setHighscoreAchievedTS((bool) $row['highscore_achieved_ts']);
771 $this->setHighscorePercentage((bool) $row['highscore_percentage']);
772 $this->setHighscoreWTime((bool) $row['highscore_wtime']);
773 $this->setHighscoreOwnTable((bool) $row['highscore_own_table']);
774 $this->setHighscoreTopTable((bool) $row['highscore_top_table']);
775 $this->setHighscoreTopNum((int) $row['highscore_top_num']);
776 }
777
779 }
780
781 //todo?
782 protected function doUpdate(): void
783 {
784 $this->save();
785 }
786
787 public function save(): void
788 {
789 global $DIC; /* @var \ILIAS\DI\Container $DIC */
790 // not possible: Move Global Access to Constructor
791 $DIC->database()->replace(self::DB_TABLE_NAME, [
792 'obj_id' => ['integer', $this->getId()]
793 ], [
794 'lrs_type_id' => ['integer', $this->getLrsTypeId()],
795 'content_type' => ['text', $this->getContentType()],
796 'source_type' => ['text', $this->getSourceType()],
797 'activity_id' => ['text', $this->getActivityId()],
798 'publisher_id' => ['text', $this->getPublisherId()],
799 'instructions' => ['text', $this->getInstructions()],
800 'launch_url' => ['text', $this->getLaunchUrl()],
801 'launch_parameters' => ['text', $this->getLaunchParameters()],
802 'moveon' => ['text', $this->getMoveOn()],
803 'entitlement_key' => ['text', $this->getEntitlementKey()],
804 'auth_fetch_url' => ['integer', (int) $this->isAuthFetchUrlEnabled()],
805 'launch_method' => ['text', $this->getLaunchMethod()],
806 'launch_mode' => ['text', $this->getLaunchMode()],
807 'switch_to_review' => ['integer', (int) $this->isSwitchToReviewEnabled()],
808 'mastery_score' => ['float', $this->getMasteryScore()],
809 'keep_lp' => ['integer', (int) $this->isKeepLpStatusEnabled()],
810 'privacy_ident' => ['integer', $this->getPrivacyIdent()],
811 'privacy_name' => ['integer', $this->getPrivacyName()],
812 'usr_privacy_comment' => ['text', $this->getUserPrivacyComment()],
813 'show_statements' => ['integer', (int) $this->isStatementsReportEnabled()],
814 'xml_manifest' => ['text', $this->getXmlManifest()],
815 'version' => ['integer', $this->getVersion()],
816 'bypass_proxy' => ['integer', (int) $this->isBypassProxyEnabled()],
817 'highscore_enabled' => ['integer', (int) $this->getHighscoreEnabled()],
818 'highscore_achieved_ts' => ['integer', (int) $this->getHighscoreAchievedTS()],
819 'highscore_percentage' => ['integer', (int) $this->getHighscorePercentage()],
820 'highscore_wtime' => ['integer', (int) $this->getHighscoreWTime()],
821 'highscore_own_table' => ['integer', (int) $this->getHighscoreOwnTable()],
822 'highscore_top_table' => ['integer', (int) $this->getHighscoreTopTable()],
823 'highscore_top_num' => ['integer', $this->getHighscoreTopNum()],
824 'only_moveon' => ['integer', (int) $this->getOnlyMoveon()],
825 'achieved' => ['integer', (int) $this->getAchieved()],
826 'answered' => ['integer', (int) $this->getAnswered()],
827 'completed' => ['integer', (int) $this->getCompleted()],
828 'failed' => ['integer', (int) $this->getFailed()],
829 'initialized' => ['integer', (int) $this->getInitialized()],
830 'passed' => ['integer', (int) $this->getPassed()],
831 'progressed' => ['integer', (int) $this->getProgressed()],
832 'satisfied' => ['integer', (int) $this->getSatisfied()],
833 'c_terminated' => ['integer', (int) $this->getTerminated()],
834 'hide_data' => ['integer', (int) $this->getHideData()],
835 'c_timestamp' => ['integer', (int) $this->getTimestamp()],
836 'duration' => ['integer', (int) $this->getDuration()],
837 'no_substatements' => ['integer', (int) $this->getNoSubstatements()],
838 'delete_data' => ['integer', $this->getDeleteData()],
839 'enrich_data' => ['integer', (int) $this->getEnrichData()]
840 ]);
841
843 }
844
845 protected function loadRepositoryActivationSettings(): void
846 {
847 if ($this->ref_id) {
848 $activation = ilObjectActivation::getItem($this->ref_id);
849 switch ($activation["timing_type"]) {
851 $this->setActivationLimited(true);
852 if (!is_null($activation["timing_start"])) {
853 $activation["timing_start"] = (int) $activation["timing_start"];
854 }
855 $this->setActivationStartingTime($activation["timing_start"]);
856 if (!is_null($activation["timing_end"])) {
857 $activation["timing_end"] = (int) $activation["timing_end"];
858 }
859 $this->setActivationEndingTime($activation["timing_end"]);
860 $this->setActivationVisibility((bool) $activation["visible"]);
861 break;
862
863 default:
864 $this->setActivationLimited(false);
865 break;
866 }
867 }
868 }
869
870 protected function saveRepositoryActivationSettings(): void
871 {
872 if ($this->ref_id) {
873 ilObjectActivation::getItem($this->ref_id);
874
875 $item = new ilObjectActivation();
876 if (!$this->isActivationLimited()) {
877 $item->setTimingType(ilObjectActivation::TIMINGS_DEACTIVATED);
878 } else {
879 $item->setTimingType(ilObjectActivation::TIMINGS_ACTIVATION);
880 $item->setTimingStart($this->getActivationStartingTime());
881 $item->setTimingEnd($this->getActivationEndingTime());
882 $item->toggleVisible($this->getActivationVisibility());
883 }
884
885 $item->update($this->ref_id);
886 }
887 }
888
890 {
891 global $DIC; /* @var \ILIAS\DI\Container $DIC */
892 //not possible: Move Global Access to Constructor
893 $tableName = self::DB_TABLE_NAME;
894
895 $query = "
896 UPDATE {$tableName}
897 SET privacy_ident = %s,
898 privacy_name = %s,
899 only_moveon = %s,
900 achieved = %s,
901 answered = %s,
902 completed = %s,
903 failed = %s,
904 initialized = %s,
905 passed = %s,
906 progressed = %s,
907 satisfied = %s,
908 c_terminated = %s,
909 hide_data = %s,
910 c_timestamp = %s,
911 duration = %s,
912 no_substatements = %s,
913 delete_data = %s,
914 enrich_data = %s
915 WHERE lrs_type_id = %s
916 ";
917
918 $DIC->database()->manipulateF(
919 $query,
920 ['integer',
921 'integer',
922 'integer',
923 'integer',
924 'integer',
925 'integer',
926 'integer',
927 'integer',
928 'integer',
929 'integer',
930 'integer',
931 'integer',
932 'integer',
933 'integer',
934 'integer',
935 'integer',
936 'integer',
937 'integer',
938 'integer'
939 ],
959 ]
960 );
961 }
962
964 {
965 global $DIC; /* @var \ILIAS\DI\Container $DIC */
966 // not possible: Move Global Access to Constructor
967 $tableName = self::DB_TABLE_NAME;
968
969 $query = "
970 UPDATE {$tableName}
971 SET bypass_proxy = %s
972 WHERE lrs_type_id = %s
973 ";
974
975 $DIC->database()->manipulateF(
976 $query,
977 ['integer', 'integer'],
979 );
980 }
981
986 {
987 global $DIC; /* @var \ILIAS\DI\Container $DIC */
988 // not possible: Move Global Access to Constructor
989 $query = "
990 SELECT DISTINCT s.obj_id FROM " . self::DB_TABLE_NAME . " s
991 INNER JOIN " . self::DB_USERS_TABLE_NAME . " u ON u.obj_id = s.obj_id
992 WHERE bypass_proxy = %s
993 ";
994
995 $res = $DIC->database()->queryF($query, array('integer'), array(1));
996
997 $objects = array();
998
999 while ($row = $DIC->database()->fetchAssoc($res)) {
1000 $objects[] = (int) $row['obj_id'];
1001 }
1002
1003 return $objects;
1004 }
1005
1006
1007
1010
1011 protected bool $_highscore_enabled = false;
1012
1013 protected int $anonymity = 0;
1014
1015 protected bool $_highscore_achieved_ts = true;
1016
1017 protected bool $_highscore_percentage = true;
1018
1019 protected bool $_highscore_wtime = true;
1020
1021 protected bool $_highscore_own_table = true;
1022
1023 protected bool $_highscore_top_table = true;
1024
1025 protected int $_highscore_top_num = 10;
1026
1030
1034 public function setHighscoreEnabled(bool $a_enabled): void
1035 {
1036 $this->_highscore_enabled = $a_enabled;
1037 }
1038
1043 public function getHighscoreEnabled(): bool
1044 {
1046 }
1047
1051 public function setHighscoreAchievedTS(bool $a_achieved_ts): void
1052 {
1053 $this->_highscore_achieved_ts = $a_achieved_ts;
1054 }
1055
1060 public function getHighscoreAchievedTS(): bool
1061 {
1063 }
1064
1068 public function setHighscorePercentage(bool $a_percentage): void
1069 {
1070 $this->_highscore_percentage = $a_percentage;
1071 }
1072
1077 public function getHighscorePercentage(): bool
1078 {
1080 }
1081
1085 public function setHighscoreWTime(bool $a_wtime): void
1086 {
1087 $this->_highscore_wtime = $a_wtime;
1088 }
1089
1094 public function getHighscoreWTime(): bool
1095 {
1097 }
1098
1103 public function setHighscoreOwnTable(bool $a_own_table): void
1104 {
1105 $this->_highscore_own_table = $a_own_table;
1106 }
1107
1112 public function getHighscoreOwnTable(): bool
1113 {
1115 }
1116
1120 public function setHighscoreTopTable(bool $a_top_table): void
1121 {
1122 $this->_highscore_top_table = $a_top_table;
1123 }
1124
1129 public function getHighscoreTopTable(): bool
1130 {
1132 }
1133
1139 public function setHighscoreTopNum(int $a_top_num): void
1140 {
1141 $this->_highscore_top_num = $a_top_num;
1142 }
1143
1150 public function getHighscoreTopNum(?int $a_retval = 10): ?int
1151 {
1152 $retval = $a_retval;
1153 if ($this->_highscore_top_num != 0) {
1154 $retval = $this->_highscore_top_num;
1155 }
1156
1157 return $retval;
1158 }
1159
1160 public function getHighscoreMode(): int
1161 {
1162 switch (true) {
1163 case $this->getHighscoreOwnTable() && $this->getHighscoreTopTable():
1165
1166 case $this->getHighscoreTopTable():
1168
1169 case $this->getHighscoreOwnTable():
1170 default:
1172 }
1173 }
1174
1175
1176 public function setHighscoreMode(int $mode): void
1177 {
1178 switch ($mode) {
1180 $this->setHighscoreTopTable(true);
1181 $this->setHighscoreOwnTable(true);
1182 break;
1183
1185 $this->setHighscoreTopTable(true);
1186 $this->setHighscoreOwnTable(false);
1187 break;
1188
1190 default:
1191 $this->setHighscoreTopTable(false);
1192 $this->setHighscoreOwnTable(true);
1193 break;
1194 }
1195 }
1196
1197 /* End GET/SET for highscore feature */
1198
1202 public function getDataSetMapping(): array
1203 {
1204 if (null === ($lrsTypeId = $this->getLrsTypeId())) {
1205 $this->doRead();
1206 }
1207 return [
1208 'obj_id' => $this->getId(),
1209 'lrs_type_id' => $this->getLrsTypeId(),
1210 'content_type' => $this->getContentType(),
1211 'source_type' => $this->getSourceType(),
1212 'activity_id' => $this->getActivityId(),
1213 'publisher_id' => $this->getPublisherId(),
1214 'instructions' => $this->getInstructions(),
1215 'launch_url' => $this->getLaunchUrl(),
1216 'launch_parameters' => $this->getLaunchParameters(),
1217 'moveon' => $this->getMoveOn(),
1218 'entitlement_key' => $this->getEntitlementKey(),
1219 'auth_fetch_url' => (int) $this->isAuthFetchUrlEnabled(),
1220 'launch_method' => $this->getLaunchMethod(),
1221 'launch_mode' => $this->getLaunchMode(),
1222 'switch_to_review' => (int) $this->isSwitchToReviewEnabled(),
1223 'mastery_score' => $this->getMasteryScore(),
1224 'keep_lp' => (int) $this->isKeepLpStatusEnabled(),
1225 'privacy_ident' => $this->getPrivacyIdent(),
1226 'privacy_name' => $this->getPrivacyName(),
1227 'usr_privacy_comment' => $this->getUserPrivacyComment(),
1228 'show_statements' => (int) $this->isStatementsReportEnabled(),
1229 'xml_manifest' => $this->getXmlManifest(),
1230 'version' => $this->getVersion(),
1231 'highscore_enabled' => (int) $this->getHighscoreEnabled(),
1232 'highscore_achieved_ts' => (int) $this->getHighscoreAchievedTS(),
1233 'highscore_percentage' => (int) $this->getHighscorePercentage(),
1234 'highscore_wtime' => (int) $this->getHighscoreWTime(),
1235 'highscore_own_table' => (int) $this->getHighscoreOwnTable(),
1236 'highscore_top_table' => (int) $this->getHighscoreTopTable(),
1237 'highscore_top_num' => $this->getHighscoreTopNum(),
1238 'only_moveon' => (int) $this->getOnlyMoveon(),
1239 'achieved' => (int) $this->getAchieved(),
1240 'answered' => (int) $this->getAnswered(),
1241 'completed' => (int) $this->getCompleted(),
1242 'failed' => (int) $this->getFailed(),
1243 'initialized' => (int) $this->getInitialized(),
1244 'passed' => (int) $this->getPassed(),
1245 'progressed' => (int) $this->getProgressed(),
1246 'satisfied' => (int) $this->getSatisfied(),
1247 'c_terminated' => (int) $this->getTerminated(),
1248 'hide_data' => (int) $this->getHideData(),
1249 'c_timestamp' => (int) $this->getTimestamp(),
1250 'duration' => (int) $this->getDuration(),
1251 'no_substatements' => (int) $this->getNoSubstatements(),
1252 'delete_data' => (int) $this->getDeleteData(),
1253 'enrich_data' => (int) $this->getEnrichData()
1254 //'bypass_proxy' => (int) $this->isBypassProxyEnabled()
1255 ];
1256 }
1257
1263 protected function doCloneObject(ilObject2 $new_obj, int $a_target_id, ?int $a_copy_id = null): void
1264 {
1265 assert($new_obj instanceof ilObjCmiXapi);
1266
1267 $this->cloneMetaData($new_obj);
1268
1269 $new_obj->setLrsTypeId($this->getLrsTypeId());
1270 $new_obj->setContentType($this->getContentType());
1271 $new_obj->setSourceType($this->getSourceType());
1272 $new_obj->setActivityId($this->getActivityId());
1273 $new_obj->setPublisherId($this->getPublisherId());
1274 $new_obj->setInstructions($this->getInstructions());
1275 $new_obj->setLaunchUrl($this->getLaunchUrl());
1276 $new_obj->setLaunchParameters($this->getLaunchParameters());
1277 $new_obj->setMoveOn($this->getMoveOn());
1278 $new_obj->setEntitlementKey($this->getEntitlementKey());
1279 $new_obj->setAuthFetchUrlEnabled($this->isAuthFetchUrlEnabled());
1280 $new_obj->setLaunchMethod($this->getLaunchMethod());
1281 $new_obj->setLaunchMode($this->getLaunchMode());
1282 $new_obj->setSwitchToReviewEnabled($this->isSwitchToReviewEnabled());
1283 $new_obj->setMasteryScore($this->getMasteryScore());
1284 $new_obj->setKeepLpStatusEnabled($this->isKeepLpStatusEnabled());
1285 $new_obj->setPrivacyIdent($this->getPrivacyIdent());
1286 $new_obj->setPrivacyName($this->getPrivacyName());
1287 $new_obj->setUserPrivacyComment($this->getUserPrivacyComment());
1288 $new_obj->setStatementsReportEnabled($this->isStatementsReportEnabled());
1289 $new_obj->setXmlManifest($this->getXmlManifest());
1290 $new_obj->setVersion($this->getVersion());
1291 $new_obj->setHighscoreEnabled($this->getHighscoreEnabled());
1292 $new_obj->setHighscoreAchievedTS($this->getHighscoreAchievedTS());
1293 $new_obj->setHighscorePercentage($this->getHighscorePercentage());
1294 $new_obj->setHighscoreWTime($this->getHighscoreWTime());
1295 $new_obj->setHighscoreOwnTable($this->getHighscoreOwnTable());
1296 $new_obj->setHighscoreTopTable($this->getHighscoreTopTable());
1297 $new_obj->setHighscoreTopNum($this->getHighscoreTopNum());
1298 $new_obj->setBypassProxyEnabled($this->isBypassProxyEnabled());
1299 $new_obj->setOnlyMoveon($this->getOnlyMoveon());
1300 $new_obj->setAchieved($this->getAchieved());
1301 $new_obj->setAnswered($this->getAnswered());
1302 $new_obj->setCompleted($this->getCompleted());
1303 $new_obj->setFailed($this->getFailed());
1304 $new_obj->setInitialized($this->getInitialized());
1305 $new_obj->setPassed($this->getPassed());
1306 $new_obj->setProgressed($this->getProgressed());
1307 $new_obj->setSatisfied($this->getSatisfied());
1308 $new_obj->setTerminated($this->getTerminated());
1309 $new_obj->setHideData($this->getHideData());
1310 $new_obj->setTimestamp($this->getTimestamp());
1311 $new_obj->setDuration($this->getDuration());
1312 $new_obj->setNoSubstatements($this->getNoSubstatements());
1313 $new_obj->setDeleteData($this->getDeleteData());
1314 $new_obj->setEnrichData($this->getEnrichData());
1315 $new_obj->update();
1316
1317 if ($this->getSourceType() == self::SRC_TYPE_LOCAL) {
1318 $dirUtil = new ilCmiXapiContentUploadImporter($new_obj);
1319 $dirUtil->ensureCreatedObjectDirectory();
1320 $newDir = implode(DIRECTORY_SEPARATOR, [ilFileUtils::getWebspaceDir(), $dirUtil->getWebDataDirRelativeObjectDirectory()]);
1321 $dirUtil = new ilCmiXapiContentUploadImporter($this);
1322 $thisDir = implode(DIRECTORY_SEPARATOR, [ilFileUtils::getWebspaceDir(), $dirUtil->getWebDataDirRelativeObjectDirectory()]);
1323 ilFileUtils::rCopy($thisDir, $newDir);
1324 }
1325 }
1326
1327 protected function doDelete(): void
1328 {
1329 // delete file data entry
1330 $query = "DELETE FROM " . self::DB_TABLE_NAME . " WHERE obj_id = " . $this->database->quote($this->getId(), 'integer');
1331 $this->database->manipulate($query);
1332 ilHistory::_removeEntriesForObject($this->getId());
1333
1334 // delete entire directory and its content
1335 $dirUtil = new ilCmiXapiContentUploadImporter($this);
1336 $thisDir = implode(DIRECTORY_SEPARATOR, [ilFileUtils::getWebspaceDir(), $dirUtil->getWebDataDirRelativeObjectDirectory()]);
1337 if (is_dir($thisDir)) {
1338 ilFileUtils::delDir($thisDir);
1339 }
1340
1341 // delete meta data
1342 $this->deleteMetaData();
1343
1344 //delete results
1345 $query = "DELETE FROM " . self::DB_RESULTS_TABLE_NAME .
1346 " WHERE obj_id = " . $this->database->quote($this->getId(), 'integer');
1347 $this->database->manipulate($query);
1348
1349 // TODO check xapidel
1350 }
1351
1352 // /**
1353 // * @return string[]
1354 // */
1355 // public function getRegistrations() : array
1356 // {
1357 // global $DIC;
1358 // $res = $DIC->database()->queryF(
1359 // "SELECT DISTINCT registration FROM " . self::DB_USERS_TABLE_NAME . " WHERE obj_id = %s",
1360 // array('text'),
1361 // array($this->getId())
1362 // );
1363 // $ret = [];
1364 // while ($row = $DIC->database()->fetchAssoc($res)) {
1365 // $ret[] = (string) $row['registration'];
1366 // }
1367 // return $ret;
1368 // }
1369
1373 public static function guidv4(?string $data = null): string
1374 {
1375 // Generate 16 bytes (128 bits) of random data or use the data passed into the function.
1376 $data ??= random_bytes(16);
1377 assert(strlen($data) == 16);
1378
1379 // Set version to 0100
1380 $data[6] = chr(ord($data[6]) & 0x0f | 0x40);
1381 // Set bits 6-7 to 10
1382 $data[8] = chr(ord($data[8]) & 0x3f | 0x80);
1383
1384 // Output the 36 character UUID.
1385 return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
1386 }
1387
1389 {
1390 global $DIC;
1391 if (null === $this->currentCmixUser) {
1392 $this->currentCmixUser = new ilCmiXapiUser($this->getId(), $DIC->user()->getId(), $this->getPrivacyIdent());
1393 }
1395 }
1396
1400 public function getSessionId(?ilCmiXapiUser $cmixUser = null): string
1401 {
1402 if (null === $cmixUser) {
1403 $cmixUser = $this->getCurrentCmixUser();
1404 }
1405 return ilCmiXapiAuthToken::getCmi5SessionByUsrIdAndObjIdAndRefId($cmixUser->getUsrId(), $this->getId(), $this->getRefId());
1406 }
1407
1412 public function getLaunchData(string $exitText, ?ilCmiXapiUser $cmixUser = null): array
1413 {
1414 if (null === $cmixUser) {
1415 $cmixUser = $this->getCurrentCmixUser();
1416 }
1417 // ToDo
1418 $moveOn = $this->getLMSMoveOn();
1419 if (!$moveOn || $moveOn == '') {
1420 $moveOn = 'Completed';
1421 }
1422 $launchMode = $this->getLaunchMode();
1423 // only check switch if self::LAUNCH_MODE_NORMAL
1424 if ($launchMode == self::LAUNCH_MODE_NORMAL) {
1425 if ($cmixUser->getSatisfied() && $this->isSwitchToReviewEnabled()) {
1427 }
1428 }
1429 $ctxTemplate = [
1430 "contextTemplate" => $this->getLaunchedContextTemplate($cmixUser),
1431 "launchMode" => ucfirst($launchMode),
1432 "launchMethod" => "OwnWindow",
1433 "moveOn" => $moveOn
1434 ];
1435 $lmsLaunchMethod = $this->getLaunchMethod();
1436 if ($lmsLaunchMethod === "ownWin") {
1437 $href = ilLink::_getStaticLink(
1438 $this->getRefId(),
1439 $this->getType()
1440 );
1441 $ctxTemplate['returnURL'] = $href;
1442 } else {
1443 $ctxTemplate['returnURL'] = ILIAS_HTTP_PATH . "/xapiexit.php?text=" . rawurlencode($exitText);
1444 }
1445 if (!empty($this->getMasteryScore())) {
1446 $ctxTemplate['masteryScore'] = $this->getMasteryScore();
1447 }
1448 if (!empty($this->getLaunchParameters())) {
1449 $ctxTemplate['launchParameters'] = $this->getLaunchParameters();
1450 }
1451 if (!empty($this->getEntitlementKey())) {
1452 $ctxTemplate['entitlementKey'] = array("courseStructure" => $this->getEntitlementKey());
1453 }
1454 return $ctxTemplate;
1455 }
1456
1460 public function getLaunchedContextTemplate(?ilCmiXapiUser $cmixUser = null): array
1461 {
1462 if (null === $cmixUser) {
1463 $cmixUser = $this->getCurrentCmixUser();
1464 }
1465 $launchMode = $this->getLaunchMode();
1466 // only check switch if self::LAUNCH_MODE_NORMAL
1467 if ($launchMode == self::LAUNCH_MODE_NORMAL) {
1468 if ($cmixUser->getSatisfied() && $this->isSwitchToReviewEnabled()) {
1470 }
1471 }
1472 $extensions = $this->getStatementExtensions($cmixUser);
1473 $extensions['https://w3id.org/xapi/cmi5/context/extensions/launchmode'] = $launchMode;
1474 if (!empty($this->getLMSMoveOn())) {
1475 $extensions['https://w3id.org/xapi/cmi5/context/extensions/moveon'] = $this->getLMSMoveOn();
1476 }
1477 if (!empty($this->getLaunchParameters())) {
1478 $extensions['https://w3id.org/xapi/cmi5/context/extensions/launchparameters'] = $this->getLaunchParameters();
1479 }
1480 if (!empty($this->getMasteryScore())) {
1481 $extensions['https://w3id.org/xapi/cmi5/context/extensions/masteryscore'] = $this->getMasteryScore();
1482 }
1483 return array(
1484 "contextActivities" => $this->getStatementContextActivities(),
1485 "extensions" => $extensions
1486 );
1487 }
1488
1494 public function getStatement(string $verb, ?ilCmiXapiUser $cmixUser = null): array
1495 {
1496 if (null === $cmixUser) {
1497 $cmixUser = $this->getCurrentCmixUser();
1498 }
1499 $id = self::guidv4();
1500 $actor = $this->getStatementActor($cmixUser);
1501 $verbUri = ilCmiXapiVerbList::getInstance()->getVerbUri($verb);
1502 $extensions = $this->getStatementExtensions($cmixUser);
1503 $registration = $cmixUser->getRegistration();
1504 $contextActivities = $this->getStatementContextActivities();
1505 $object = $this->getStatementObject();
1506 return array(
1507 'id' => $id,
1508 'actor' => $actor,
1509 'verb' =>
1510 array(
1511 'id' => $verbUri
1512 ),
1513 'context' =>
1514 array(
1515 'extensions' => $extensions,
1516 'registration' => $registration,
1517 'contextActivities' => $contextActivities
1518 ),
1519 'object' => $object
1520 );
1521 }
1522
1527 public function getStatementActor(?ilCmiXapiUser $cmixUser = null): array
1528 {
1529 global $DIC;
1530 if (null === $cmixUser) {
1531 $cmixUser = $this->getCurrentCmixUser();
1532 }
1533 $user = new ilObjUser($cmixUser->getUsrId()); // ToDo: Caching Names
1534 $name = ilCmiXapiUser::getName($this->getPrivacyName(), $user);
1535 if ($name == '') {
1536 $this->log()->error('error: no name in cmixuser');
1537 $name = 'UNDEFINED';
1538 }
1539 $homePage = ($this->anonymousHomePage == true) ? self::ANONYMOUS_HOMEPAGE : self::iliasUrl();
1540 if ($this->getContentType() == self::CONT_TYPE_CMI5) {
1541 $actor = [
1542 'objectType' => 'Agent',
1543 'account' => [
1544 'homePage' => $homePage,
1545 'name' => $cmixUser->getUsrIdent()
1546 ]
1547 ];
1548 if ($name !== '') {
1549 $actor['name'] = $name;
1550 }
1551 } else {
1552 $actor = [
1553 'objectType' => 'Agent',
1554 'mbox' => 'mailto:' . $cmixUser->getUsrIdent()
1555 ];
1556 if ($name !== '') {
1557 $actor['name'] = $name;
1558 }
1559 }
1560 return $actor;
1561 }
1562
1568 public function getStatementExtensions(?ilCmiXapiUser $cmixUser = null): array
1569 {
1570 if (null === $cmixUser) {
1571 $cmixUser = $this->getCurrentCmixUser();
1572 }
1573 return array(
1574 'https://w3id.org/xapi/cmi5/context/extensions/sessionid' => $this->getSessionId($cmixUser),
1575 'https://ilias.de/cmi5/activityid' => $this->getActivityId()
1576 );
1577 }
1578
1583 public function getStatementContextActivities(): array
1584 {
1585 $publisherId = $this->getPublisherId();
1586 $activityId = $this->getActivityId();
1587 if (empty($publisherId)) {
1589 }
1590 return array(
1591 "grouping" => [
1592 [
1593 "objectType" => "Activity",
1594 "id" => "{$publisherId}",
1595 'definition' =>
1596 array(
1597 'name' =>
1598 array(
1599 'de-DE' => $this->getTitle(),
1600 'en-US' => $this->getTitle()
1601 ),
1602 'description' =>
1603 array(
1604 'de-DE' => $this->getDescription(),
1605 'en-US' => $this->getDescription()
1606 )
1607 )]
1608 ],
1609 "category" => [
1610 [
1611 "id" => "https://w3id.org/xapi/cmi5/context/categories/cmi5",
1612 "objectType" => "Activity"
1613 ]
1614 ]
1615 );
1616 }
1617
1621 public function getStatementObject(): array
1622 {
1623 return array(
1624 'id' => $this->getActivityId(),
1625 'definition' =>
1626 array(
1627 'name' =>
1628 array(
1629 'de-DE' => $this->getTitle(),
1630 'en-US' => $this->getTitle()
1631 ),
1632 'description' =>
1633 array(
1634 'de-DE' => $this->getDescription(),
1635 'en-US' => $this->getDescription()
1636 )
1637 )
1638 );
1639 }
1640
1645 public function getLaunchedStatement(?ilCmiXapiUser $cmixUser = null): array
1646 {
1647 if (null === $cmixUser) {
1648 $cmixUser = $this->getCurrentCmixUser();
1649 }
1650 $launchMode = $this->getLaunchMode();
1651 // only check switch if self::LAUNCH_MODE_NORMAL
1652 if ($launchMode == self::LAUNCH_MODE_NORMAL) {
1653 if ($cmixUser->getSatisfied() && $this->isSwitchToReviewEnabled()) {
1655 }
1656 }
1657
1658 $statement = $this->getStatement('launched', $cmixUser);
1659 $statement['context']['extensions']['https://w3id.org/xapi/cmi5/context/extensions/launchmode'] = $launchMode;
1660 if (!empty($this->getLMSMoveOn())) {
1661 $statement['context']['extensions']['https://w3id.org/xapi/cmi5/context/extensions/moveon'] = $this->getLMSMoveOn();
1662 }
1663 if (!empty($this->getLaunchParameters())) {
1664 $statement['context']['extensions']['https://w3id.org/xapi/cmi5/context/extensions/launchparameters'] = $this->getLaunchParameters();
1665 }
1666 if (!empty($this->getMasteryScore())) {
1667 $statement['context']['extensions']['https://w3id.org/xapi/cmi5/context/extensions/masteryscore'] = $this->getMasteryScore();
1668 }
1669 return $statement;
1670 }
1671
1676 public function getAbandonedStatement(?string $sessionId, ?string $duration, ?ilCmiXapiUser $cmixUser = null): array
1677 {
1678 if (null === $cmixUser) {
1679 $cmixUser = $this->getCurrentCmixUser();
1680 }
1681 $statement = $this->getStatement('abandoned', $cmixUser);
1682 // overwrite session with abandoned oldSession
1683 $statement['context']['extensions']['https://w3id.org/xapi/cmi5/context/extensions/sessionid'] = $sessionId;
1684 $statement['result'] = array(
1685 'duration' => $duration
1686 );
1687 return $statement;
1688 }
1689
1694 public function getSatisfiedStatement(?ilCmiXapiUser $cmixUser = null): array
1695 {
1696 if (null === $cmixUser) {
1697 $cmixUser = $this->getCurrentCmixUser();
1698 }
1699 $statement = $this->getStatement('satisfied', $cmixUser);
1700 // add type, see https://aicc.github.io/CMI-5_Spec_Current/samples/scenarios/16-not_applicable-no_launch/#satisfied-statement
1701 // see also: https://github.com/AICC/CMI-5_Spec_Current/blob/quartz/cmi5_spec.md#verbs_satisfied
1702 $type = "https://w3id.org/xapi/cmi5/activitytype/course";
1703 $statement['object']['definition']['type'] = $type;
1704 $statement['context']['contextActivities']['grouping'][0]['definition']['type'] = $type;
1705 return $statement;
1706 }
1707
1713 public function getLastStatement(string $sess): mixed
1714 {
1715 global $DIC;
1716
1717 $lrsType = $this->getLrsType();
1718
1720 $defaultBasicAuth = $lrsType->getBasicAuth();
1721 $defaultHeaders = [
1722 'X-Experience-API-Version' => '1.0.3',
1723 'Authorization' => $defaultBasicAuth,
1724 'Cache-Control' => 'no-cache, no-store, must-revalidate'
1725 ];
1726
1727 $pipeline = json_encode($this->getLastStatementPipline($sess));
1728 $defaultLastStatementUrl = $defaultLrs . "?pipeline=" . urlencode($pipeline);
1729
1730 $headers = [];
1731 foreach ($defaultHeaders as $key => $value) {
1732 $headers[] = "$key: $value";
1733 }
1734
1735 $ch = curl_init($defaultLastStatementUrl);
1736 curl_setopt_array($ch, [
1737 CURLOPT_RETURNTRANSFER => true,
1738 CURLOPT_HTTPHEADER => $headers,
1739 CURLOPT_CONNECTTIMEOUT => 10,
1740 CURLOPT_TIMEOUT => 30,
1741 CURLOPT_SSL_VERIFYPEER => true,
1742 CURLOPT_FOLLOWLOCATION => true,
1743 ]);
1744
1745 $body = curl_exec($ch);
1746 $error = curl_error($ch);
1747 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1748 curl_close($ch);
1749
1750 if ($error) {
1751 $this->log()->error("cURL error: " . $error);
1752 return null;
1753 }
1754
1755 if ($httpCode < 200 || $httpCode >= 300) {
1756 $this->log()->error("Unexpected HTTP status: {$httpCode}");
1757 return null;
1758 }
1759
1760 $decoded = json_decode($body, true);
1761 if (json_last_error() !== JSON_ERROR_NONE) {
1762 $this->log()->error("JSON decode error: " . json_last_error_msg());
1763 return null;
1764 }
1765
1766 return $decoded;
1767 }
1768
1772 public function getLastStatementPipline(string $sess): array
1773 {
1774 global $DIC;
1775 $pipeline = array();
1776
1777 // filter activityId
1778 $match = array();
1779 $match['statement.object.objectType'] = 'Activity';
1780 $match['statement.actor.objectType'] = 'Agent';
1781
1782 $activityId = array();
1783
1784 if ($this->getContentType() == ilObjCmiXapi::CONT_TYPE_CMI5 && !$this->isMixedContentType()) {
1785 // https://github.com/AICC/CMI-5_Spec_Current/blob/quartz/cmi5_spec.md#963-extensions
1786 $activityId['statement.context.extensions.https://ilias&46;de/cmi5/activityid'] = $this->getActivityId();
1787 } else {
1788 $activityQuery = [
1789 '$regex' => '^' . preg_quote($this->getActivityId()) . ''
1790 ];
1791 $activityId['$or'] = [];
1792 $activityId['$or'][] = ['statement.object.id' => $activityQuery];
1793 $activityId['$or'][] = ['statement.context.contextActivities.parent.id' => $activityQuery];
1794 }
1795
1796 $sessionId = array();
1797 $sessionId['statement.context.extensions.https://w3id&46;org/xapi/cmi5/context/extensions/sessionid'] = $sess;
1798 $match['$and'] = array();
1799 $match['$and'][] = $activityId;
1800 $match['$and'][] = $sessionId;
1801 $sort = array('statement.timestamp' => -1);
1802 $project = array('statement.timestamp' => 1, 'statement.verb.id' => 1);
1803 $pipeline[] = array('$match' => $match);
1804 $pipeline[] = array('$sort' => $sort);
1805 $pipeline[] = array('$limit' => 1);
1806 $pipeline[] = array('$project' => $project);
1807
1808 return $pipeline;
1809 }
1810
1811 public static function iliasUrl(): string
1812 {
1813 global $DIC;
1814 $regex = '/^(https?:\/\/[^\/]+).*/';
1815 preg_match($regex, (string) $DIC->http()->request()->getUri(), $request_parts);
1816 return $request_parts[1];
1817 }
1818
1819 public static function log(): ilLogger
1820 {
1821 return \ilLoggerFactory::getLogger('cmix');
1822 }
1823
1824
1825 public function isActivationLimited(): ?bool
1826 {
1828 }
1829
1830
1831 public function setActivationLimited(bool $activationLimited): void
1832 {
1833 $this->activationLimited = $activationLimited;
1834 }
1835
1836 public function getActivationStartingTime(): ?int
1837 {
1839 }
1840
1841 public function setActivationStartingTime(?int $activationStartingTime = null): void
1842 {
1843 $this->activationStartingTime = $activationStartingTime;
1844 }
1845
1846 public function getActivationEndingTime(): ?int
1847 {
1849 }
1850
1851 public function setActivationEndingTime(?int $activationEndingTime = null): void
1852 {
1853 $this->activationEndingTime = $activationEndingTime;
1854 }
1855
1856 public function getActivationVisibility(): ?bool
1857 {
1859 }
1860
1862 {
1863 $this->activationVisibility = $activationVisibility;
1864 }
1865}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
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.
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)
setPublisherId(string $publisherId)
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)
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
setDeleteData(int $deleteData)
setAchieved(bool $achieved)
getLaunchData(string $exitText, ?ilCmiXapiUser $cmixUser=null)
LMS.LaunchData.
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 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)
setEnrichData(bool $enrichData)
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)
ilErrorHandling $error
ilObjUser $user
string $type
Interface ilDBInterface.
$res
Definition: ltiservices.php:69
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
global $DIC
Definition: shib_login.php:26