3 declare(strict_types=1);
155 public function __construct(
int $a_id = 0,
bool $a_reference =
true)
158 $this->database = $DIC->database();
160 $this->lrsTypeId = 0;
162 $this->contentType = self::CONT_TYPE_GENERIC;
163 $this->sourceType = self::SRC_TYPE_REMOTE;
165 $this->activityId =
'';
167 $this->publisherId =
'';
169 $this->instructions =
'';
171 $this->launchUrl =
'';
172 $this->launchParameters =
'';
174 $this->entitlementKey =
'';
176 $this->authFetchUrlEnabled =
false;
178 $this->launchMethod = self::LAUNCH_METHOD_NEW_WIN;
179 $this->launchMode = self::LAUNCH_MODE_NORMAL;
181 $this->switchToReviewEnabled =
true;
183 $this->masteryScore = self::LMS_MASTERY_SCORE;
184 $this->keepLpStatusEnabled =
true;
186 $this->userIdent = self::PRIVACY_IDENT_IL_UUID_USER_ID;
187 $this->userName = self::PRIVACY_NAME_NONE;
188 $this->userPrivacyComment =
'';
190 $this->currentCmixUser = null;
192 $this->statementsReportEnabled =
false;
194 $this->xmlManifest =
'';
197 $this->bypassProxyEnabled =
false;
205 return new self($a_id, $a_reference);
210 $this->type =
"cmix";
246 if ($contentType ==
"learning") {
247 $contentType = self::CONT_TYPE_GENERIC;
267 return $this->sourceType == self::SRC_TYPE_REMOTE;
272 return $this->sourceType == self::SRC_TYPE_EXTERNAL;
355 return $olp->getCurrentMode();
417 return ucfirst($this->launchMode);
422 $this->launchMode = ucfirst($launchMode);
452 return $this->masteryScore * 100;
457 $this->masteryScore = $masteryScorePercent / 100;
686 protected function load(): void
688 $query =
"SELECT * FROM " . self::DB_TABLE_NAME .
" WHERE obj_id = %s";
691 while ($row = $this->database->fetchAssoc(
$res)) {
692 if ($row[
'lrs_type_id']) {
706 $this->
setMoveOn((
string) $row[
'moveon']);
766 $DIC->database()->replace(self::DB_TABLE_NAME, [
767 'obj_id' => [
'integer', $this->
getId()]
777 'moveon' => [
'text', $this->
getMoveOn()],
790 'version' => [
'integer', $this->
getVersion()],
800 'achieved' => [
'integer', (
int) $this->
getAchieved()],
801 'answered' => [
'integer', (
int) $this->
getAnswered()],
802 'completed' => [
'integer', (
int) $this->
getCompleted()],
803 'failed' => [
'integer', (
int) $this->
getFailed()],
805 'passed' => [
'integer', (
int) $this->
getPassed()],
807 'satisfied' => [
'integer', (
int) $this->
getSatisfied()],
809 'hide_data' => [
'integer', (
int) $this->
getHideData()],
810 'c_timestamp' => [
'integer', (
int) $this->
getTimestamp()],
811 'duration' => [
'integer', (
int) $this->
getDuration()],
822 switch ($activation[
"timing_type"]) {
825 if (!is_null($activation[
"timing_start"])) {
826 $activation[
"timing_start"] = (
int) $activation[
"timing_start"];
829 if (!is_null($activation[
"timing_end"])) {
830 $activation[
"timing_end"] = (
int) $activation[
"timing_end"];
858 $item->update($this->ref_id);
866 $tableName = self::DB_TABLE_NAME;
870 SET privacy_ident = %s, 885 no_substatements = %s 886 WHERE lrs_type_id = %s 889 $DIC->database()->manipulateF(
934 $tableName = self::DB_TABLE_NAME;
938 SET bypass_proxy = %s 939 WHERE lrs_type_id = %s 942 $DIC->database()->manipulateF(
944 [
'integer',
'integer'],
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 962 $res = $DIC->database()->queryF(
$query, array(
'integer'), array(1));
966 while ($row = $DIC->database()->fetchAssoc(
$res)) {
967 $objects[] = (
int) $row[
'obj_id'];
1003 $this->_highscore_enabled = $a_enabled;
1020 $this->_highscore_achieved_ts = $a_achieved_ts;
1037 $this->_highscore_percentage = $a_percentage;
1054 $this->_highscore_wtime = $a_wtime;
1072 $this->_highscore_own_table = $a_own_table;
1089 $this->_highscore_top_table = $a_top_table;
1108 $this->_highscore_top_num = $a_top_num;
1119 $retval = $a_retval;
1120 if ($this->_highscore_top_num != 0) {
1131 return self::HIGHSCORE_SHOW_ALL_TABLES;
1134 return self::HIGHSCORE_SHOW_TOP_TABLE;
1138 return self::HIGHSCORE_SHOW_OWN_TABLE;
1146 case self::HIGHSCORE_SHOW_ALL_TABLES:
1151 case self::HIGHSCORE_SHOW_TOP_TABLE:
1156 case self::HIGHSCORE_SHOW_OWN_TABLE:
1175 'obj_id' => $this->
getId(),
1242 $new_obj->setMoveOn($this->
getMoveOn());
1268 $new_obj->setFailed($this->
getFailed());
1270 $new_obj->setPassed($this->
getPassed());
1282 $dirUtil->ensureCreatedObjectDirectory();
1293 $query =
"DELETE FROM " . self::DB_TABLE_NAME .
" WHERE obj_id = " . $this->database->quote($this->
getId(),
'integer');
1294 $this->database->manipulate(
$query);
1300 if (is_dir($thisDir)) {
1308 $query =
"DELETE FROM " . self::DB_RESULTS_TABLE_NAME .
1309 " WHERE obj_id = " . $this->database->quote($this->
getId(),
'integer');
1310 $this->database->manipulate(
$query);
1339 $data ??= random_bytes(16);
1340 assert(strlen(
$data) == 16);
1348 return vsprintf(
'%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex(
$data), 4));
1354 if (null === $this->currentCmixUser) {
1365 if (null === $cmixUser) {
1378 if (null === $cmixUser) {
1383 if (!$moveOn || $moveOn ==
'') {
1384 $moveOn =
'Completed';
1388 if ($launchMode == self::LAUNCH_MODE_NORMAL) {
1390 $launchMode = self::LAUNCH_MODE_REVIEW;
1395 "launchMode" => ucfirst($launchMode),
1396 "launchMethod" =>
"OwnWindow",
1400 if ($lmsLaunchMethod ===
"ownWin") {
1401 if (is_int($launchedByRefId)) {
1412 $ctxTemplate[
'returnURL'] = $href;
1414 $ctxTemplate[
'returnURL'] = ILIAS_HTTP_PATH .
"/Modules/CmiXapi/xapiexit.php?lang={$lang}";
1423 $ctxTemplate[
'entitlementKey'] = array(
"courseStructure" => $this->
getEntitlementKey());
1425 return $ctxTemplate;
1433 if (null === $cmixUser) {
1438 if ($launchMode == self::LAUNCH_MODE_NORMAL) {
1440 $launchMode = self::LAUNCH_MODE_REVIEW;
1444 $extensions[
'https://w3id.org/xapi/cmi5/context/extensions/launchmode'] =
$launchMode;
1446 $extensions[
'https://w3id.org/xapi/cmi5/context/extensions/moveon'] = $this->
getLMSMoveOn();
1449 $extensions[
'https://w3id.org/xapi/cmi5/context/extensions/launchparameters'] = $this->
getLaunchParameters();
1452 $extensions[
'https://w3id.org/xapi/cmi5/context/extensions/masteryscore'] = $this->
getMasteryScore();
1456 "extensions" => $extensions
1467 if (null === $cmixUser) {
1470 $id = self::guidv4();
1474 $registration = $cmixUser->getRegistration();
1486 'extensions' => $extensions,
1487 'registration' => $registration,
1488 'contextActivities' => $contextActivities
1501 if (null === $cmixUser) {
1507 $this->
log()->error(
'error: no name in cmixuser');
1508 $name =
'UNDEFINED';
1510 $homePage = ($this->anonymousHomePage ==
true) ? self::ANONYMOUS_HOMEPAGE : self::iliasUrl();
1513 'objectType' =>
'Agent',
1515 'homePage' => $homePage,
1516 'name' => $cmixUser->getUsrIdent()
1520 $actor[
'name'] =
$name;
1524 'objectType' =>
'Agent',
1525 'mbox' =>
'mailto:' . $cmixUser->getUsrIdent()
1528 $actor[
'name'] =
$name;
1541 if (null === $cmixUser) {
1545 'https://w3id.org/xapi/cmi5/context/extensions/sessionid' => $this->
getSessionId($cmixUser),
1546 'https://ilias.de/cmi5/activityid' => $this->
getActivityId()
1558 if (empty($publisherId)) {
1564 "objectType" =>
"Activity",
1565 "id" =>
"{$publisherId}",
1582 "id" =>
"https://w3id.org/xapi/cmi5/context/categories/cmi5",
1583 "objectType" =>
"Activity" 1618 if (null === $cmixUser) {
1623 if ($launchMode == self::LAUNCH_MODE_NORMAL) {
1625 $launchMode = self::LAUNCH_MODE_REVIEW;
1629 $statement = $this->
getStatement(
'launched', $cmixUser);
1630 $statement[
'context'][
'extensions'][
'https://w3id.org/xapi/cmi5/context/extensions/launchmode'] =
$launchMode;
1632 $statement[
'context'][
'extensions'][
'https://w3id.org/xapi/cmi5/context/extensions/moveon'] = $this->
getLMSMoveOn();
1635 $statement[
'context'][
'extensions'][
'https://w3id.org/xapi/cmi5/context/extensions/launchparameters'] = $this->
getLaunchParameters();
1638 $statement[
'context'][
'extensions'][
'https://w3id.org/xapi/cmi5/context/extensions/masteryscore'] = $this->
getMasteryScore();
1649 if (null === $cmixUser) {
1652 $statement = $this->
getStatement(
'abandoned', $cmixUser);
1654 $statement[
'context'][
'extensions'][
'https://w3id.org/xapi/cmi5/context/extensions/sessionid'] = $sessionId;
1655 $statement[
'result'] = array(
1656 'duration' => $duration
1667 if (null === $cmixUser) {
1670 $statement = $this->
getStatement(
'satisfied', $cmixUser);
1673 $type =
"https://w3id.org/xapi/cmi5/activitytype/course";
1674 $statement[
'object'][
'definition'][
'type'] =
$type;
1675 $statement[
'context'][
'contextActivities'][
'grouping'][0][
'definition'][
'type'] =
$type;
1694 'X-Experience-API-Version' =>
'1.0.3',
1695 'Authorization' => $defaultBasicAuth,
1696 'Cache-Control' =>
'no-cache, no-store, must-revalidate' 1707 $defaultLastStatementUrl = $defaultLrs .
"?pipeline=" . urlencode($pipeline);
1710 GuzzleHttp\RequestOptions::VERIFY =>
true,
1711 GuzzleHttp\RequestOptions::CONNECT_TIMEOUT => 10,
1712 GuzzleHttp\RequestOptions::HTTP_ERRORS =>
false 1716 $defaultLastStatementUrl,
1719 $promises = array();
1720 $promises[
'defaultLastStatement'] =
$client->sendAsync($defaultLastStatementRequest, $req_opts);
1722 $responses = GuzzleHttp\Promise\Utils::settle($promises)->wait();
1725 return json_decode($body, (
bool) JSON_OBJECT_AS_ARRAY);
1727 $this->
log()->error(
'error:' . $e->getMessage());
1738 $pipeline = array();
1742 $match[
'statement.object.objectType'] =
'Activity';
1743 $match[
'statement.actor.objectType'] =
'Agent';
1745 $activityId = array();
1749 $activityId[
'statement.context.extensions.https://ilias&46;de/cmi5/activityid'] = $this->
getActivityId();
1754 $activityId[
'$or'] = [];
1755 $activityId[
'$or'][] = [
'statement.object.id' => $activityQuery];
1756 $activityId[
'$or'][] = [
'statement.context.contextActivities.parent.id' => $activityQuery];
1759 $sessionId = array();
1760 $sessionId[
'statement.context.extensions.https://w3id&46;org/xapi/cmi5/context/extensions/sessionid'] = $sess;
1761 $match[
'$and'] = array();
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);
1777 $regex =
'/^(https?:\/\/[^\/]+).*/';
1778 preg_match($regex, (
string) $DIC->http()->request()->getUri(), $request_parts);
1779 return $request_parts[1];
1788 return \ilLoggerFactory::getLogger(
'cmix');
getAbandonedStatement(?string $sessionId, ?string $duration, ?ilCmiXapiUser $cmixUser=null)
static getWebspaceDir(string $mode="filesystem")
get webspace directory
setDuration(bool $duration)
const LP_MODE_CMIX_COMPLETED
setPublisherId(string $publisherId)
const DB_RESULTS_TABLE_NAME
doCloneObject(ilObject2 $new_obj, int $a_target_id, ?int $a_copy_id=null)
setPrivacyIdent(int $userIdent)
setContentType(string $contentType)
int $activationEndingTime
const LP_MODE_CMIX_COMPLETED_OR_PASSED
const PRIVACY_IDENT_IL_UUID_SHA256URL
bool $_highscore_top_table
bool $switchToReviewEnabled
string $userPrivacyComment
setXmlManifest(string $xmlManifest)
getSatisfiedStatement(?ilCmiXapiUser $cmixUser=null)
static getObjectsHavingBypassProxyEnabledAndRegisteredUsers()
getLaunchedContextTemplate(?ilCmiXapiUser $cmixUser=null)
getHighscoreTopTable()
Gets, if the top-rankings table should be shown.
bool $activationLimited
repository object activation settings (handled by ilObject)
const HIGHSCORE_SHOW_OWN_TABLE
const LP_MODE_CMIX_PASSED_WITH_FAILED
bool $_highscore_own_table
cloneMetaData(ilObject $target_obj)
bool $keepLpStatusEnabled
getStatementExtensions(?ilCmiXapiUser $cmixUser=null)
Minimal extensions.
setEntitlementKey(string $entitlementKey)
const LAUNCH_METHOD_NEW_WIN
getHighscoreWTime()
Gets if the column with the workingtime should be shown.
static getCmi5SessionByUsrIdAndObjIdAndRefId(int $usrId, int $objId, ?int $refId=null)
const MOVEON_NOT_APPLICABLE
setActivationStartingTime(?int $activationStartingTime=null)
setNoSubstatements(bool $no_substatements)
setOnlyMoveon(bool $only_moveon)
setAchieved(bool $achieved)
setSourceType(string $sourceType)
const LP_MODE_CMIX_PASSED
setHighscoreWTime(bool $a_wtime)
Sets if the workingtime of the scores should be shown.
int $activationStartingTime
setAuthFetchUrlEnabled(bool $authFetchUrlEnabled)
getSessionId(?ilCmiXapiUser $cmixUser=null)
setHighscoreOwnTable(bool $a_own_table)
Sets if the table with the own ranking should be shown.
static getInstance(int $a_id=0, bool $a_reference=true)
const TIMINGS_DEACTIVATED
bool $authFetchUrlEnabled
getLrsEndpointStatementsAggregationLink()
static rCopy(string $a_sdir, string $a_tdir, bool $preserveTimeAttributes=false)
Copies content of a directory $a_sdir recursively to a directory $a_tdir.
bool $_highscore_achieved_ts
getLastStatement(string $sess)
get latest statement from session
setKeepLpStatusEnabled(bool $keepLpStatusEnabled)
setLaunchMode(string $launchMode)
const PRIVACY_IDENT_IL_UUID_RANDOM
static updatePrivacySettingsFromLrsType(ilCmiXapiLrsType $lrsType)
getActivationStartingTime()
bool $_highscore_enabled
HIGHSCORE.
getHighscoreTopNum(?int $a_retval=10)
Gets the number of entries which are to be shown in the top-rankings table.
const PRIVACY_IDENT_IL_UUID_EXT_ACCOUNT
setSwitchToReviewEnabled(bool $switchToReviewEnabled)
getHighscoreOwnTable()
Gets if the own rankings table should be shown.
const LP_MODE_CMIX_COMPL_WITH_FAILED
static _lookupObjId(int $ref_id)
getMoveOn()
Attention: this is the original imported moveOn for using in LaunchData and LaunchStatement use getLM...
const PRIVACY_IDENT_REAL_EMAIL
setBypassProxyEnabled(bool $bypassProxyEnabled)
getActivationEndingTime()
setLaunchMethod(string $launchMethod)
const LAUNCH_METHOD_IFRAME
ilCmiXapiLrsType $lrsType
setTerminated(bool $terminated)
const PRIVACY_IDENT_IL_UUID_SHA256
static _removeEntriesForObject(int $a_obj_id)
remove all history entries for an object
setActivityId(string $activityId)
getLPMode()
only for internal LMS usage
setMasteryScore(float $masteryScore)
setHighscoreMode(int $mode)
getHighscoreEnabled()
Gets the setting which determines if the highscore feature is enabled.
getStatementActor(?ilCmiXapiUser $cmixUser=null)
statement actor
setCompleted(bool $completed)
const PRIVACY_NAME_FIRSTNAME
setHighscorePercentage(bool $a_percentage)
Sets if the percentages of the scores pass should be shown.
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static _getStaticLink(?int $a_ref_id, string $a_type='', bool $a_fallback_goto=true, string $append="")
Get static link.
const LAUNCH_METHOD_OWN_WIN
getLastStatementPipline(string $sess)
setMoveOn(string $moveOn)
Attention: this is the original moveOn from course import should only be set on import! ...
bool $activationVisibility
const DB_USERS_TABLE_NAME
setStatementsReportEnabled(bool $statementsReportEnabled)
getActivationVisibility()
getLaunchData(?ilCmiXapiUser $cmixUser=null, string $lang='en', ?int $launchedByRefId=null)
LMS.LaunchData.
__construct(int $a_id=0, bool $a_reference=true)
ilObjCmiXapi constructor.
getLaunchedStatement(?ilCmiXapiUser $cmixUser=null)
const PRIVACY_IDENT_IL_UUID_LOGIN
setInitialized(bool $initialized)
const PRIVACY_IDENT_IL_UUID_USER_ID
setProgressed(bool $progressed)
static guidv4(?string $data=null)
const HIGHSCORE_SHOW_ALL_TABLES
setUserPrivacyComment(string $userPrivacyComment)
setSatisfied(bool $satisfied)
setActivationLimited(bool $activationLimited)
const LP_MODE_DEACTIVATED
static getItem(int $ref_id)
setPrivacyName(int $userName)
setLaunchParameters(string $launchParameters)
getStatement(string $verb, ?ilCmiXapiUser $cmixUser=null)
blueprint statement
const PRIVACY_NAME_LASTNAME
__construct(Container $dic, ilPlugin $plugin)
getLMSMoveOn()
for CMI5 statements | state moveOn values
setTimestamp(bool $timestamp)
const LP_MODE_CMIX_COMPL_OR_PASSED_WITH_FAILED
getSwitchToReviewEnabled()
setAnswered(bool $answered)
getStatementContextActivities()
Minimal statementActivities.
getHighscorePercentage()
Gets if the percentage column should be shown.
setLaunchUrl(string $launchUrl)
loadRepositoryActivationSettings()
setMasteryScorePercent(float $masteryScorePercent)
const PRIVACY_NAME_FULLNAME
setLrsType(\ilCmiXapiLrsType $lrsType)
setHideData(bool $hide_data)
static updateByPassProxyFromLrsType(ilCmiXapiLrsType $lrsType)
setHighscoreAchievedTS(bool $a_achieved_ts)
Sets if the date and time of the scores achievement should be displayed.
isSwitchToReviewEnabled()
static _lookupType(int $id, bool $reference=false)
bool $statementsReportEnabled
const HIGHSCORE_SHOW_TOP_TABLE
setActivationEndingTime(?int $activationEndingTime=null)
bool $_highscore_percentage
static getInstance(int $obj_id)
const MOVEON_COMPLETED_OR_PASSED
Class ilObjectActivation.
setInstructions(string $instructions)
setHighscoreTopTable(bool $a_top_table)
Sets if the top-rankings table should be shown.
static checkResponse(array $response, &$body, array $allowedStatus=[200, 204])
setLrsTypeId(int $lrsTypeId)
isStatementsReportEnabled()
setActivationVisibility(bool $activationVisibility)
getHighscoreAchievedTS()
Returns if date and time of the scores achievement should be displayed.
static getName(int $userNameMode, ilObjUser $user)
ilCmiXapiUser $currentCmixUser
saveRepositoryActivationSettings()
setHighscoreEnabled(bool $a_enabled)
Sets if the highscore feature should be enabled.
setHighscoreTopNum(int $a_top_num)
Sets the number of entries which are to be shown in the top-rankings table.