19 declare(strict_types=1);
31 $obj_id = $DIC->http()->wrapper()->query()->retrieve(
'package_id', $DIC->refinery()->kindlyTo()->int());
32 $refId = $DIC->http()->wrapper()->query()->retrieve(
'ref_id', $DIC->refinery()->kindlyTo()->int());
33 $in = file_get_contents(
"php://input");
34 $data = json_decode($in);
37 header(
'Content-Type: text/plain; charset=UTF-8');
39 $rval = self::storeJsApiCmi($user_id, $obj_id,
$data);
41 print(
"storeJsApiCmi failed");
43 $rval = self::syncGlobalStatus($user_id, $obj_id,
$refId,
$data,
$data->now_global_status);
45 print(
"syncGlobalStatus failed");
57 $ilDB = $DIC->database();
59 $b_updateStatus =
false;
69 foreach ($data->cmi as $value) {
70 $aa_data[] = array(
"sco_id" => (
int) $value[0],
78 $ilLog->write(
"ScormAicc: storeJsApi: Error: No valid obj_id given.");
80 foreach ($aa_data as $a_data) {
83 SELECT rvalue FROM scorm_tracking 88 array(
'integer',
'integer',
'text',
'integer'),
89 array($user_id, $a_data[
"sco_id"], $a_data[
"left"], $obj_id)
91 if ($rec =
$ilDB->fetchAssoc($set)) {
92 if ($a_data[
"left"] ===
'cmi.core.lesson_status' && $a_data[
"right"] != $rec[
"rvalue"]) {
93 $b_updateStatus =
true;
98 'rvalue' => array(
'clob', $a_data[
"right"]),
102 'user_id' => array(
'integer', $user_id),
103 'sco_id' => array(
'integer', $a_data[
"sco_id"]),
104 'lvalue' => array(
'text', $a_data[
"left"]),
105 'obj_id' => array(
'integer', $obj_id)
108 $ilLog->debug(
"ScormAicc: storeJsApi Updated - L:" . $a_data[
"left"] .
",R:" .
109 $a_data[
"right"] .
" for obj_id:" . $obj_id .
",sco_id:" . $a_data[
"sco_id"] .
",user_id:" . $user_id);
111 if ($a_data[
"left"] ===
'cmi.core.lesson_status') {
112 $b_updateStatus =
true;
114 $ilDB->insert(
'scorm_tracking', array(
115 'obj_id' => array(
'integer', $obj_id),
116 'user_id' => array(
'integer', $user_id),
117 'sco_id' => array(
'integer', $a_data[
"sco_id"]),
118 'lvalue' => array(
'text', $a_data[
"left"]),
119 'rvalue' => array(
'clob', $a_data[
"right"]),
122 $ilLog->debug(
"ScormAicc: storeJsApi Inserted - L:" . $a_data[
"left"] .
",R:" .
123 $a_data[
"right"] .
" for obj_id:" . $obj_id .
",sco_id:" . $a_data[
"sco_id"] .
",user_id:" . $user_id);
125 if ($a_data[
"left"] ===
'cmi.core.score.max') {
126 $i_score_max = $a_data[
"right"];
128 if ($a_data[
"left"] ===
'cmi.core.score.raw') {
129 $i_score_raw = $a_data[
"right"];
133 if ($i_score_max > 0 && $i_score_raw > 0) {
138 ($i_score_raw / $i_score_max) * 100
156 $ilDB = $DIC->database();
158 $saved_global_status = $data->saved_global_status;
159 $ilLog->write(
"saved_global_status=" . $saved_global_status);
162 if (!isset($data->packageAttempts)) {
163 $val_set =
$ilDB->queryF(
164 'SELECT package_attempts FROM sahs_user WHERE obj_id = %s AND user_id = %s',
165 array(
'integer',
'integer'),
166 array($packageId, $userId)
168 $val_rec =
$ilDB->fetchAssoc($val_set);
169 $attempts = $val_rec[
"package_attempts"];
171 $attempts = $data->packageAttempts;
173 if ($attempts == null) {
178 $totalTime = (
int) $data->totalTimeCentisec;
179 $totalTime = round($totalTime / 100);
181 'UPDATE sahs_user SET last_visited=%s, last_access = %s, sco_total_time_sec=%s, status=%s, percentage_completed=%s, package_attempts=%s WHERE obj_id = %s AND user_id = %s',
182 array(
'text',
'timestamp',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),
183 array($data->last_visited,
187 $data->percentageCompleted,
196 $ilObjDataCache = $DIC[
'ilObjDataCache'];
223 if ($new_global_status != null) {
231 public static function _insertTrackData(
int $a_sahs_id,
string $a_lval,
string $a_rval,
int $a_obj_id): void
234 $ilDB = $DIC->database();
237 $ilDB->insert(
'scorm_tracking', array(
238 'obj_id' => array(
'integer', $a_obj_id),
239 'user_id' => array(
'integer',
$ilUser->getId()),
240 'sco_id' => array(
'integer', $a_sahs_id),
241 'lvalue' => array(
'text', $a_lval),
242 'rvalue' => array(
'clob', $a_rval),
246 if ($a_lval ===
"cmi.core.lesson_status") {
256 public static function _getCompleted(
object $scorm_item_id,
int $a_obj_id): array
259 $ilDB = $DIC->database();
263 if (is_array($scorm_item_id)) {
264 $in =
$ilDB->in(
'sco_id', $scorm_item_id,
false,
'integer');
267 'SELECT DISTINCT(user_id) FROM scorm_tracking 271 AND (' .
$ilDB->like(
'rvalue',
'clob',
'completed') .
' OR ' .
$ilDB->like(
276 array(
'integer',
'text'),
277 array($a_obj_id,
'cmi.core.lesson_status')
281 'SELECT DISTINCT(user_id) FROM scorm_tracking 285 AND (' .
$ilDB->like(
'rvalue',
'clob',
'completed') .
' OR ' .
$ilDB->like(
290 array(
'integer',
'integer',
'text'),
291 array($scorm_item_id, $a_obj_id,
'cmi.core.lesson_status')
295 while ($row =
$ilDB->fetchObject(
$res)) {
296 $user_ids[] = $row->user_id;
304 $ilDB = $DIC->database();
306 $status =
"not_attempted";
308 if (is_array($a_scos)) {
309 $in =
$ilDB->in(
'sco_id', $a_scos,
false,
'integer');
312 'SELECT sco_id, rvalue FROM scorm_tracking 317 array(
'integer',
'text',
'integer'),
318 array($a_obj_id,
'cmi.core.lesson_status', $a_user_id)
325 if ($rec[
"rvalue"] ===
"failed") {
328 if ($rec[
"rvalue"] !==
"completed" && $rec[
"rvalue"] !==
"passed") {
334 $status =
"in_progress";
336 if ($completed && $cnt == count($a_scos)) {
337 $status =
"completed";
349 $ilDB = $DIC->database();
352 if (is_array($a_scos)) {
353 $in =
$ilDB->in(
'sco_id', $a_scos,
false,
'integer');
356 'SELECT sco_id, rvalue FROM scorm_tracking 361 array(
'integer',
'text',
'integer'),
362 array($a_obj_id,
'cmi.core.lesson_status', $a_user_id)
366 if ($rec[
"rvalue"] ===
"completed" || $rec[
"rvalue"] ===
"passed") {
381 $ilDB = $DIC->database();
384 $query =
'SELECT user_id, MAX(c_timestamp) tst ' .
385 'FROM scorm_tracking ' .
386 'WHERE obj_id = ' .
$ilDB->quote($a_obj_id,
'integer') .
' ' .
391 $users[$row->user_id] = $row->tst;
403 $ilDB = $DIC->database();
407 'SELECT DISTINCT user_id FROM scorm_tracking 410 array(
'integer',
'text'),
411 array($a_obj_id,
'cmi.core.lesson_status')
416 $users[] = $row[
"user_id"];
425 public static function _getFailed(
object $scorm_item_id,
int $a_obj_id): array
428 $ilDB = $DIC->database();
431 if (is_array($scorm_item_id)) {
432 $in =
$ilDB->in(
'sco_id', $scorm_item_id,
false,
'integer');
436 SELECT DISTINCT(user_id) FROM scorm_tracking 440 AND ' .
$ilDB->like(
'rvalue',
'clob',
'failed') .
' ',
441 array(
'integer',
'text'),
442 array($a_obj_id,
'cmi.core.lesson_status')
447 SELECT DISTINCT(user_id) FROM scorm_tracking 451 AND ' .
$ilDB->like(
'rvalue',
'clob',
'failed') .
' ',
452 array(
'integer',
'integer',
'text'),
453 array($scorm_item_id, $a_obj_id,
'cmi.core.lesson_status')
457 while ($row =
$ilDB->fetchObject(
$res)) {
458 $user_ids[] = $row->user_id;
470 $ilDB = $DIC->database();
473 $in =
$ilDB->in(
'sco_id', $a_scorm_item_ids,
false,
'integer');
479 SELECT user_id, COUNT(user_id) completed FROM scorm_tracking 483 AND (' .
$ilDB->like(
'rvalue',
'clob',
'completed') .
' OR ' .
$ilDB->like(
'rvalue',
'clob',
'passed') .
') 485 array(
'integer',
'text'),
486 array($a_obj_id,
'cmi.core.lesson_status')
488 while ($row =
$ilDB->fetchObject(
$res)) {
489 $users[$row->user_id] = $row->completed;
501 $ilDB = $DIC->database();
503 $in =
$ilDB->in(
'sco_id', $sco_item_ids,
false,
'integer');
507 SELECT * FROM scorm_tracking 511 array(
'integer',
'text'),
512 array($a_obj_id,
'cmi.core.lesson_status')
515 $info[
'completed'] = array();
516 $info[
'failed'] = array();
519 while ($row =
$ilDB->fetchObject(
$res)) {
520 switch ($row->rvalue) {
523 $info[
'completed'][$row->sco_id][] = $row->user_id;
524 $user_ids[$row->sco_id][] = $row->user_id;
528 $info[
'failed'][$row->sco_id][] = $row->user_id;
529 $user_ids[$row->sco_id][] = $row->user_id;
542 public static function _getInProgress($scorm_item_id,
int $a_obj_id, ?array $a_blocked_user_ids = null): array
545 $ilDB = $DIC->database();
547 if (is_array($scorm_item_id)) {
548 $in =
$ilDB->in(
'sco_id', $scorm_item_id,
false,
'integer');
551 'SELECT user_id,sco_id FROM scorm_tracking 554 GROUP BY user_id, sco_id',
560 'SELECT user_id,sco_id FROM scorm_tracking 563 array(
'integer',
'integer'),
564 array($scorm_item_id, $a_obj_id)
568 $in_progress = array();
570 while ($row =
$ilDB->fetchObject(
$res)) {
572 if (!($a_blocked_user_ids &&
573 isset($a_blocked_user_ids[$row->sco_id]) &&
574 is_array($a_blocked_user_ids[$row->sco_id]) &&
575 in_array($row->user_id, $a_blocked_user_ids[$row->sco_id]))) {
576 $in_progress[$row->sco_id][] = $row->user_id;
585 $ilDB = $DIC->database();
586 $user_id = $DIC->http()->wrapper()->query()->retrieve(
'p', $DIC->refinery()->kindlyTo()->int());
587 $ref_id = $DIC->http()->wrapper()->query()->retrieve(
'ref_id', $DIC->refinery()->kindlyTo()->int());
588 $obj_id = $DIC->http()->wrapper()->query()->retrieve(
'package_id', $DIC->refinery()->kindlyTo()->int());
590 $GLOBALS[
'DIC'][
'ilLog']->write(__METHOD__ .
' no valid obj_id');
593 if ($DIC->http()->wrapper()->query()->has(
'last_visited')) {
594 $last_visited = $DIC->http()->wrapper()->query()->retrieve(
'last_visited', $DIC->refinery()->kindlyTo()->string());
599 mktime((
int) date(
'H'), (
int) date(
'i') + 5, (
int) date(
's'), (
int) date(
'm'), (
int) date(
'd'), (
int) date(
'Y'))
603 SET last_visited = %s, hash_end =%s, last_access = %s 604 WHERE obj_id = %s AND user_id = %s',
605 array(
'text',
'timestamp',
'timestamp',
'integer',
'integer'),
606 array($last_visited, $endDate, date(
'Y-m-d H:i:s'), $obj_id, $user_id)
612 header(
'Content-Type: text/plain; charset=UTF-8');
619 $ilDB = $DIC->database();
621 'select hash from sahs_user where obj_id=%s AND user_id=%s AND hash_end>%s',
622 array(
'integer',
'integer',
'timestamp'),
623 array($packageId, $userId, date(
'Y-m-d H:i:s'))
626 if (! ($rowtmp && $rowtmp[
'hash'] == $hash)) {
632 public static function _syncReadEvent(
int $a_obj_id,
int $a_user_id,
string $a_type,
int $a_ref_id): void
635 $ilDB = $DIC->database();
637 $val_set =
$ilDB->queryF(
638 'SELECT package_attempts, total_time_sec, sco_total_time_sec, time_from_lms FROM sahs_user, sahs_lm ' 639 .
'WHERE sahs_user.obj_id = %s AND sahs_user.user_id = %s AND sahs_user.obj_id = sahs_lm.id',
640 array(
'integer',
'integer'),
641 array($a_obj_id, $a_user_id)
644 $val_rec =
$ilDB->fetchAssoc($val_set);
646 if ($val_rec[
"package_attempts"] == null) {
647 $val_rec[
"package_attempts"] =
"";
649 $attempts = $val_rec[
"package_attempts"];
651 $time = (
int) $val_rec[
"sco_total_time_sec"];
655 $sco_set =
$ilDB->queryF(
657 SELECT sco_id, rvalue FROM scorm_tracking 662 array(
'integer',
'integer',
'text',
'integer'),
663 array($a_obj_id, $a_user_id,
'cmi.core.total_time', 0)
666 while ($sco_rec =
$ilDB->fetchAssoc($sco_set)) {
667 $tarr = explode(
":", $sco_rec[
"rvalue"]);
668 $sec = (
int) $tarr[2] + (
int) $tarr[1] * 60 +
669 (
int) substr($tarr[0], strlen($tarr[0]) - 3) * 60 * 60;
static storeJsApiCmi(int $user_id, int $obj_id, object $data)
static getLogger(string $a_component_id)
Get component logger.
static _lookupPresentableItems(int $a_slm_id)
Count number of presentable SCOs/Assets of SCORM learning module.
static _getCollectionStatus(?array $a_scos, int $a_obj_id, int $a_user_id)
static _getFailed(object $scorm_item_id, int $a_obj_id)
like necessary because of Oracle
Class ilObjSCORMTracking.
static _getProgressInfo(array $sco_item_ids, int $a_obj_id)
Get info about.
static lookupLastAccessTimes(int $a_obj_id)
Lookup last acccess time for all users of a scorm module.
static now()
Return current timestamp in Y-m-d H:i:s format.
static _insertTrackData(int $a_sahs_id, string $a_lval, string $a_rval, int $a_obj_id)
static _getInProgress($scorm_item_id, int $a_obj_id, ?array $a_blocked_user_ids=null)
static _recordReadEvent(string $a_type, int $a_ref_id, int $obj_id, int $usr_id, bool $isCatchupWriteEvents=true, $a_ext_rc=null, $a_ext_time=null)
if(!defined('PATH_SEPARATOR')) $GLOBALS['_PEAR_default_error_mode']
static _getTrackedUsers(int $a_obj_id)
Get all tracked users.
static syncGlobalStatus(int $userId, int $packageId, int $refId, object $data, ?int $new_global_status)
static handleOutcomeWithoutLP(int $a_obj_id, int $a_usr_id, ?float $a_percentage)
static _countCompleted(?array $a_scos, int $a_obj_id, int $a_user_id)
static _getCountCompletedPerUser(array $a_scorm_item_ids, int $a_obj_id)
Get users who have status completed or passed.
static checkIfAllowed(int $packageId, int $userId, int $hash)
static scorm12PlayerUnload()
static writeStatus(int $a_obj_id, int $a_user_id, int $a_status, int $a_percentage=0, bool $a_force_per=false, ?int &$a_old_status=self::LP_STATUS_NOT_ATTEMPTED_NUM)
Write status for user and object.
static _getCompleted(object $scorm_item_id, int $a_obj_id)
like necessary because of Oracle
static _syncReadEvent(int $a_obj_id, int $a_user_id, string $a_type, int $a_ref_id)
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)