19declare(strict_types=1);
159 public function __construct(
int $a_id = 0,
bool $a_reference =
true)
164 $this->lrsTypeId = 0;
169 $this->activityId =
'';
171 $this->publisherId =
'';
173 $this->instructions =
'';
175 $this->launchUrl =
'';
176 $this->launchParameters =
'';
178 $this->entitlementKey =
'';
180 $this->authFetchUrlEnabled =
false;
185 $this->switchToReviewEnabled =
true;
188 $this->keepLpStatusEnabled =
true;
192 $this->userPrivacyComment =
'';
194 $this->currentCmixUser =
null;
196 $this->statementsReportEnabled =
false;
198 $this->xmlManifest =
'';
201 $this->bypassProxyEnabled =
false;
209 return new self($a_id, $a_reference);
214 $this->type =
"cmix";
359 return $olp->getCurrentMode();
421 return ucfirst($this->launchMode);
456 return $this->masteryScore * 100;
461 $this->masteryScore = $masteryScorePercent / 100;
709 protected function load(): void
711 $query =
"SELECT * FROM " . self::DB_TABLE_NAME .
" WHERE obj_id = %s";
715 if ($row[
'lrs_type_id']) {
729 $this->
setMoveOn((
string) $row[
'moveon']);
791 $DIC->database()->replace(self::DB_TABLE_NAME, [
792 'obj_id' => [
'integer', $this->
getId()]
802 'moveon' => [
'text', $this->
getMoveOn()],
815 'version' => [
'integer', $this->
getVersion()],
825 'achieved' => [
'integer', (
int) $this->
getAchieved()],
826 'answered' => [
'integer', (
int) $this->
getAnswered()],
827 'completed' => [
'integer', (
int) $this->
getCompleted()],
828 'failed' => [
'integer', (
int) $this->
getFailed()],
830 'passed' => [
'integer', (
int) $this->
getPassed()],
832 'satisfied' => [
'integer', (
int) $this->
getSatisfied()],
834 'hide_data' => [
'integer', (
int) $this->
getHideData()],
835 'c_timestamp' => [
'integer', (
int) $this->
getTimestamp()],
836 'duration' => [
'integer', (
int) $this->
getDuration()],
849 switch ($activation[
"timing_type"]) {
852 if (!is_null($activation[
"timing_start"])) {
853 $activation[
"timing_start"] = (
int) $activation[
"timing_start"];
856 if (!is_null($activation[
"timing_end"])) {
857 $activation[
"timing_end"] = (
int) $activation[
"timing_end"];
885 $item->update($this->ref_id);
897 SET privacy_ident = %s,
912 no_substatements = %s,
915 WHERE lrs_type_id = %s
918 $DIC->database()->manipulateF(
971 SET bypass_proxy = %s
972 WHERE lrs_type_id = %s
975 $DIC->database()->manipulateF(
977 [
'integer',
'integer'],
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
995 $res =
$DIC->database()->queryF($query, array(
'integer'), array(1));
999 while ($row =
$DIC->database()->fetchAssoc(
$res)) {
1000 $objects[] = (
int) $row[
'obj_id'];
1036 $this->_highscore_enabled = $a_enabled;
1053 $this->_highscore_achieved_ts = $a_achieved_ts;
1070 $this->_highscore_percentage = $a_percentage;
1087 $this->_highscore_wtime = $a_wtime;
1105 $this->_highscore_own_table = $a_own_table;
1122 $this->_highscore_top_table = $a_top_table;
1141 $this->_highscore_top_num = $a_top_num;
1152 $retval = $a_retval;
1153 if ($this->_highscore_top_num != 0) {
1208 'obj_id' => $this->
getId(),
1277 $new_obj->setMoveOn($this->
getMoveOn());
1303 $new_obj->setFailed($this->
getFailed());
1305 $new_obj->setPassed($this->
getPassed());
1319 $dirUtil->ensureCreatedObjectDirectory();
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());
1337 if (is_dir($thisDir)) {
1345 $query =
"DELETE FROM " . self::DB_RESULTS_TABLE_NAME .
1346 " WHERE obj_id = " . $this->
database->quote($this->
getId(),
'integer');
1347 $this->
database->manipulate($query);
1376 $data ??= random_bytes(16);
1377 assert(strlen(
$data) == 16);
1385 return vsprintf(
'%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex(
$data), 4));
1391 if (
null === $this->currentCmixUser) {
1392 $this->currentCmixUser =
new ilCmiXapiUser($this->
getId(), $DIC->user()->getId(), $this->getPrivacyIdent());
1402 if (
null === $cmixUser) {
1414 if (
null === $cmixUser) {
1419 if (!$moveOn ||
$moveOn ==
'') {
1424 if ($launchMode == self::LAUNCH_MODE_NORMAL) {
1425 if ($cmixUser->getSatisfied() && $this->isSwitchToReviewEnabled()) {
1432 "launchMethod" =>
"OwnWindow",
1436 if ($lmsLaunchMethod ===
"ownWin") {
1441 $ctxTemplate[
'returnURL'] = $href;
1443 $ctxTemplate[
'returnURL'] = ILIAS_HTTP_PATH .
"/xapiexit.php?text=" . rawurlencode($exitText);
1452 $ctxTemplate[
'entitlementKey'] = array(
"courseStructure" => $this->
getEntitlementKey());
1454 return $ctxTemplate;
1462 if (
null === $cmixUser) {
1467 if ($launchMode == self::LAUNCH_MODE_NORMAL) {
1468 if ($cmixUser->getSatisfied() && $this->isSwitchToReviewEnabled()) {
1473 $extensions[
'https://w3id.org/xapi/cmi5/context/extensions/launchmode'] =
$launchMode;
1475 $extensions[
'https://w3id.org/xapi/cmi5/context/extensions/moveon'] = $this->
getLMSMoveOn();
1478 $extensions[
'https://w3id.org/xapi/cmi5/context/extensions/launchparameters'] = $this->
getLaunchParameters();
1481 $extensions[
'https://w3id.org/xapi/cmi5/context/extensions/masteryscore'] = $this->
getMasteryScore();
1485 "extensions" => $extensions
1496 if (
null === $cmixUser) {
1503 $registration = $cmixUser->getRegistration();
1515 'extensions' => $extensions,
1516 'registration' => $registration,
1517 'contextActivities' => $contextActivities
1530 if (
null === $cmixUser) {
1536 $this->
log()->error(
'error: no name in cmixuser');
1537 $name =
'UNDEFINED';
1539 $homePage = ($this->anonymousHomePage ==
true) ? self::ANONYMOUS_HOMEPAGE : self::iliasUrl();
1542 'objectType' =>
'Agent',
1544 'homePage' => $homePage,
1545 'name' => $cmixUser->getUsrIdent()
1549 $actor[
'name'] = $name;
1553 'objectType' =>
'Agent',
1554 'mbox' =>
'mailto:' . $cmixUser->getUsrIdent()
1557 $actor[
'name'] = $name;
1570 if (
null === $cmixUser) {
1574 'https://w3id.org/xapi/cmi5/context/extensions/sessionid' => $this->
getSessionId($cmixUser),
1575 'https://ilias.de/cmi5/activityid' => $this->
getActivityId()
1593 "objectType" =>
"Activity",
1594 "id" =>
"{$publisherId}",
1611 "id" =>
"https://w3id.org/xapi/cmi5/context/categories/cmi5",
1612 "objectType" =>
"Activity"
1647 if (
null === $cmixUser) {
1652 if ($launchMode == self::LAUNCH_MODE_NORMAL) {
1653 if ($cmixUser->getSatisfied() && $this->isSwitchToReviewEnabled()) {
1658 $statement = $this->
getStatement(
'launched', $cmixUser);
1659 $statement[
'context'][
'extensions'][
'https://w3id.org/xapi/cmi5/context/extensions/launchmode'] =
$launchMode;
1661 $statement[
'context'][
'extensions'][
'https://w3id.org/xapi/cmi5/context/extensions/moveon'] = $this->
getLMSMoveOn();
1664 $statement[
'context'][
'extensions'][
'https://w3id.org/xapi/cmi5/context/extensions/launchparameters'] = $this->
getLaunchParameters();
1667 $statement[
'context'][
'extensions'][
'https://w3id.org/xapi/cmi5/context/extensions/masteryscore'] = $this->
getMasteryScore();
1678 if (
null === $cmixUser) {
1681 $statement = $this->
getStatement(
'abandoned', $cmixUser);
1683 $statement[
'context'][
'extensions'][
'https://w3id.org/xapi/cmi5/context/extensions/sessionid'] = $sessionId;
1684 $statement[
'result'] = array(
1696 if (
null === $cmixUser) {
1699 $statement = $this->
getStatement(
'satisfied', $cmixUser);
1702 $type =
"https://w3id.org/xapi/cmi5/activitytype/course";
1703 $statement[
'object'][
'definition'][
'type'] =
$type;
1704 $statement[
'context'][
'contextActivities'][
'grouping'][0][
'definition'][
'type'] =
$type;
1722 'X-Experience-API-Version' =>
'1.0.3',
1723 'Authorization' => $defaultBasicAuth,
1724 'Cache-Control' =>
'no-cache, no-store, must-revalidate'
1728 $defaultLastStatementUrl = $defaultLrs .
"?pipeline=" . urlencode($pipeline);
1731 foreach ($defaultHeaders as $key => $value) {
1732 $headers[] =
"$key: $value";
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,
1745 $body = curl_exec($ch);
1746 $error = curl_error($ch);
1747 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1751 $this->
log()->error(
"cURL error: " .
$error);
1755 if ($httpCode < 200 || $httpCode >= 300) {
1756 $this->
log()->error(
"Unexpected HTTP status: {$httpCode}");
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());
1775 $pipeline = array();
1779 $match[
'statement.object.objectType'] =
'Activity';
1780 $match[
'statement.actor.objectType'] =
'Agent';
1786 $activityId[
'statement.context.extensions.https://ilias&46;de/cmi5/activityid'] = $this->
getActivityId();
1791 $activityId[
'$or'] = [];
1792 $activityId[
'$or'][] = [
'statement.object.id' => $activityQuery];
1793 $activityId[
'$or'][] = [
'statement.context.contextActivities.parent.id' => $activityQuery];
1796 $sessionId = array();
1797 $sessionId[
'statement.context.extensions.https://w3id&46;org/xapi/cmi5/context/extensions/sessionid'] = $sess;
1798 $match[
'$and'] = array();
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);
1814 $regex =
'/^(https?:\/\/[^\/]+).*/';
1815 preg_match($regex, (
string)
$DIC->http()->request()->getUri(), $request_parts);
1816 return $request_parts[1];
1821 return \ilLoggerFactory::getLogger(
'cmix');
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
static getCmi5SessionByUsrIdAndObjIdAndRefId(int $usrId, int $objId, ?int $refId=null)
const MOVEON_COMPLETED_OR_PASSED
const MOVEON_NOT_APPLICABLE
getLrsEndpointStatementsAggregationLink()
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_COMPLETED_OR_PASSED
const LP_MODE_CMIX_COMPL_WITH_FAILED
const LP_MODE_CMIX_PASSED
const LP_MODE_CMIX_COMPL_OR_PASSED_WITH_FAILED
const LP_MODE_DEACTIVATED
const LP_MODE_CMIX_COMPLETED
const LP_MODE_CMIX_PASSED_WITH_FAILED
static _getStaticLink(?int $a_ref_id, string $a_type='', bool $a_fallback_goto=true, string $append="")
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)
bool $_highscore_top_table
setOnlyMoveon(bool $only_moveon)
bool $activationVisibility
getHighscoreWTime()
Gets if the column with the workingtime should be shown.
setHideData(bool $hide_data)
const DB_RESULTS_TABLE_NAME
bool $_highscore_own_table
getHighscoreTopNum(?int $a_retval=10)
Gets the number of entries which are to be shown in the top-rankings table.
getActivationStartingTime()
const PRIVACY_NAME_FULLNAME
setPrivacyName(int $userName)
setContentType(string $contentType)
getActivationEndingTime()
const LAUNCH_METHOD_NEW_WIN
getLPMode()
only for internal LMS usage
const PRIVACY_NAME_FIRSTNAME
setNoSubstatements(bool $no_substatements)
ilCmiXapiUser $currentCmixUser
getSessionId(?ilCmiXapiUser $cmixUser=null)
getActivationVisibility()
static getObjectsHavingBypassProxyEnabledAndRegisteredUsers()
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)
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)
getSwitchToReviewEnabled()
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
const DB_USERS_TABLE_NAME
loadRepositoryActivationSettings()
doCloneObject(ilObject2 $new_obj, int $a_target_id, ?int $a_copy_id=null)
saveRepositoryActivationSettings()
bool $activationLimited
repository object activation settings (handled by ilObject)
setAnswered(bool $answered)
int $activationStartingTime
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)
bool $keepLpStatusEnabled
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
bool $statementsReportEnabled
setMasteryScorePercent(float $masteryScorePercent)
const PRIVACY_IDENT_IL_UUID_SHA256
setProgressed(bool $progressed)
string $userPrivacyComment
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
bool $_highscore_percentage
bool $_highscore_achieved_ts
const PRIVACY_NAME_LASTNAME
getStatementContextActivities()
Minimal statementActivities.
isStatementsReportEnabled()
setInitialized(bool $initialized)
getHighscoreOwnTable()
Gets if the own rankings table should be shown.
bool $authFetchUrlEnabled
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.
bool $switchToReviewEnabled
setActivationLimited(bool $activationLimited)
getHighscoreEnabled()
Gets the setting which determines if the highscore feature is enabled.
setActivationStartingTime(?int $activationStartingTime=null)
setLaunchUrl(string $launchUrl)
setLrsType(\ilCmiXapiLrsType $lrsType)
setEnrichData(bool $enrichData)
setUserPrivacyComment(string $userPrivacyComment)
setEntitlementKey(string $entitlementKey)
const LAUNCH_METHOD_IFRAME
setHighscoreEnabled(bool $a_enabled)
Sets if the highscore feature should be enabled.
static updatePrivacySettingsFromLrsType(ilCmiXapiLrsType $lrsType)
static updateByPassProxyFromLrsType(ilCmiXapiLrsType $lrsType)
isSwitchToReviewEnabled()
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)
int $activationEndingTime
getAbandonedStatement(?string $sessionId, ?string $duration, ?ilCmiXapiUser $cmixUser=null)
setActivityId(string $activityId)
getLastStatementPipline(string $sess)
getStatementActor(?ilCmiXapiUser $cmixUser=null)
statement actor
setPrivacyIdent(int $userIdent)
const LAUNCH_METHOD_OWN_WIN
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.
const TIMINGS_DEACTIVATED
static getItem(int $ref_id)
static getInstance(int $obj_id)
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc