ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilSCORM2004Tracking.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
27{
31 public static function _getInProgress(int $scorm_item_id, int $a_obj_id): void
32 {
33 throw new Exception("Not Implemented: ilSCORM2004Tracking_getInProgress");
34 }
35
39 public static function _getCompleted(int $scorm_item_id, int $a_obj_id): void
40 {
41 throw new Exception("Not Implemented: ilSCORM2004Tracking_getCompleted");
42 }
43
47 public static function _getFailed(int $scorm_item_id, int $a_obj_id): void
48 {
49 throw new Exception("Not Implemented: ilSCORM2004Tracking_getFailed");
50 }
51
57 public static function _getCountCompletedPerUser(array $a_scorm_item_ids, int $a_obj_id, bool $a_omit_failed = false): array
58 {
59 global $DIC;
60
61 $ilDB = $DIC->database();
62 $users = [];
63
64 $in = $ilDB->in('cp_node.cp_node_id', $a_scorm_item_ids, false, 'integer');
65
66 // #8171: success_status vs. completion status
67 $omit_failed = '';
68 if ($a_omit_failed) {
69 $omit_failed = ' AND success_status <> ' . $ilDB->quote('failed', 'text');
70 }
71
72 $res = $ilDB->queryF(
73 '
74 SELECT cmi_node.user_id user_id, COUNT(user_id) completed FROM cp_node, cmi_node
75 WHERE ' . $in . $omit_failed . '
76 AND cp_node.cp_node_id = cmi_node.cp_node_id
77 AND cp_node.slm_id = %s
78 AND completion_status = %s
79 GROUP BY cmi_node.user_id',
80 array('integer', 'text'),
81 array($a_obj_id, 'completed')
82 );
83 while ($row = $ilDB->fetchObject($res)) {
84 $users[$row->user_id] = $row->completed;
85 }
86
87 return $users;
88 }
89
94 public static function _getProgressInfo(int $a_obj_id): array
95 {
96 global $DIC;
97
98 $ilDB = $DIC->database();
99
100 $res = $ilDB->queryF(
101 '
102 SELECT user_id, status, satisfied FROM cmi_gobjective
103 WHERE objective_id = %s
104 AND scope_id = %s',
105 array('text', 'integer'),
106 array('-course_overall_status-', $a_obj_id)
107 );
108
109 $info['completed'] = array();
110 $info['failed'] = array();
111 $info['in_progress'] = array();
112
113 while ($row = $ilDB->fetchAssoc($res)) {
114 if (self::_isCompleted($row["status"], $row["satisfied"])) {
115 $info['completed'][] = (int) $row["user_id"];
116 }
117 if (self::_isInProgress($row["status"], $row["satisfied"])) {
118 $info['in_progress'][] = (int) $row["user_id"];
119 }
120 if (self::_isFailed($row["status"], $row["satisfied"])) {
121 $info['failed'][] = (int) $row["user_id"];
122 }
123 }
124
125 return $info;
126 }
127
131 public static function _getProgressInfoOfUser(int $a_obj_id, int $a_user_id): string
132 {
133 global $DIC;
134
135 $ilDB = $DIC->database();
136
137 $res = $ilDB->queryF(
138 '
139 SELECT status, satisfied FROM cmi_gobjective
140 WHERE objective_id = %s
141 AND scope_id = %s AND user_id = %s',
142 array('text', 'integer', 'integer'),
143 array('-course_overall_status-', $a_obj_id, $a_user_id)
144 );
145
146 $status = "not_attempted";
147 if ($row = $ilDB->fetchAssoc($res)) {
148 if (self::_isInProgress($row["status"], $row["satisfied"])) {
149 $status = "in_progress";
150 }
151 if (self::_isCompleted($row["status"], $row["satisfied"])) {
152 $status = "completed";
153 }
154 if (self::_isFailed($row["status"], $row["satisfied"])) {
155 $status = "failed";
156 }
157 }
158 return $status;
159 }
160
165 public static function _getTrackedUsers(int $a_obj_id): array
166 {
167 global $DIC;
168
169 $ilDB = $DIC->database();
170
171 $res = $ilDB->queryF(
172 '
173 SELECT DISTINCT user_id FROM cmi_gobjective
174 WHERE objective_id = %s
175 AND scope_id = %s',
176 array('text', 'integer'),
177 array('-course_overall_status-', $a_obj_id)
178 );
179
180 $users = array();
181 while ($row = $ilDB->fetchAssoc($res)) {
182 $users[] = (int) $row["user_id"];
183 }
184 return $users;
185 }
186
190 public static function _getItemProgressInfo(array $a_scorm_item_ids, int $a_obj_id, bool $a_omit_failed): array
191 {
192 global $DIC;
193
194 $ilDB = $DIC->database();
195
196 $in = $ilDB->in('cp_node.cp_node_id', $a_scorm_item_ids, false, 'integer');
197
198 $res = $ilDB->queryF(
199 'SELECT cp_node.cp_node_id id,
200 cmi_node.user_id user_id,
201 cmi_node.completion_status completion,
202 cmi_node.success_status success
203 FROM cp_node, cmi_node
204 WHERE ' . $in . '
205 AND cp_node.cp_node_id = cmi_node.cp_node_id
206 AND cp_node.slm_id = %s',
207 array('integer'),
208 array($a_obj_id)
209 );
210
211 $info['completed'] = array();
212 $info['failed'] = array();
213 $info['in_progress'] = array();
214
215 while ($row = $ilDB->fetchAssoc($res)) {
216 // if any data available, set in progress.
217 $info['in_progress'][$row["id"]][] = $row["user_id"];
218 if ($row["completion"] === "completed" || $row["success"] === "passed") {
219 // #8171: success_status vs. completion status
220 if (!$a_omit_failed || $row["success"] !== "failed") {
221 $info['completed'][$row["id"]][] = $row["user_id"];
222 }
223 }
224 if ($row["success"] === "failed") {
225 $info['failed'][$row["id"]][] = $row["user_id"];
226 }
227 }
228 return $info;
229 }
230
231 public static function _getCollectionStatus(array $a_scos, int $a_obj_id, int $a_user_id): string
232 {
233 global $DIC;
234
235 $ilDB = $DIC->database();
236
237 $status = "not_attempted";
238
239 if (is_array($a_scos)) {
240 $in = $ilDB->in('cp_node.cp_node_id', $a_scos, false, 'integer');
241
242 $res = $ilDB->queryF(
243 'SELECT cp_node.cp_node_id id,
244 cmi_node.completion_status completion,
245 cmi_node.success_status success
246 FROM cp_node, cmi_node
247 WHERE ' . $in . '
248 AND cp_node.cp_node_id = cmi_node.cp_node_id
249 AND cp_node.slm_id = %s
250 AND cmi_node.user_id = %s',
251 array('integer', 'integer'),
252 array($a_obj_id, $a_user_id)
253 );
254
255 $started = false;
256 $cntcompleted = 0;
257 $failed = false;
258 while ($rec = $ilDB->fetchAssoc($res)) {
259 if ($rec["completion"] === "completed" || $rec["success"] === "passed") {
260 $cntcompleted++;
261 }
262 if ($rec["success"] === "failed") {
263 $failed = true;
264 }
265 $started = true;
266 }
267 if ($started == true) {
268 $status = "in_progress";
269 }
270 if ($failed == true) {
271 $status = "failed";
272 } elseif ($cntcompleted == count($a_scos)) {
273 $status = "completed";
274 }
275 }
276 return $status;
277 }
278
279 public static function _countCompleted(
280 array $a_scos,
281 int $a_obj_id,
282 int $a_user_id,
283 bool $a_omit_failed
284 ): int {
285 global $DIC;
286
287 $ilDB = $DIC->database();
288 $cnt = 0;
289
290 if (is_array($a_scos)) {
291 $in = $ilDB->in('cp_node.cp_node_id', $a_scos, false, 'integer');
292
293 $res = $ilDB->queryF(
294 'SELECT cp_node.cp_node_id id,
295 cmi_node.completion_status completion,
296 cmi_node.success_status success
297 FROM cp_node, cmi_node
298 WHERE ' . $in . '
299 AND cp_node.cp_node_id = cmi_node.cp_node_id
300 AND cp_node.slm_id = %s
301 AND cmi_node.user_id = %s',
302 array('integer', 'integer'),
303 array($a_obj_id, $a_user_id)
304 );
305
306
307 while ($rec = $ilDB->fetchAssoc($res)) {
308 // #8171: alex, added (!$a_omit_failed || $rec["success"] != "failed")
309 // since completed/failed combination should not be included in
310 // percentage calculation at ilLPStatusSCOM::determinePercentage
311 if (($rec["completion"] === "completed" || $rec["success"] === "passed")
312 && (!$a_omit_failed || $rec["success"] !== "failed")) {
313 $cnt++;
314 }
315 }
316 }
317 return $cnt;
318 }
319
323 public static function _syncReadEvent(int $a_obj_id, int $a_user_id, string $a_type, int $a_ref_id, ?bool $time_from_lms = null): void
324 {
325 global $DIC;
326
327 $ilDB = $DIC->database();
328
329 //get condition to select time
330 $val_set = $ilDB->queryF(
331 'SELECT time_from_lms FROM sahs_lm WHERE id = %s',
332 array('integer'),
333 array($a_obj_id)
334 );
335 $val_rec = $ilDB->fetchAssoc($val_set);
336 $time_from_lms = (ilUtil::yn2tf($val_rec["time_from_lms"]));
337
338 // get attempts and time
339 $val_set = $ilDB->queryF(
340 '
341 SELECT package_attempts, sco_total_time_sec, total_time_sec
342 FROM sahs_user WHERE obj_id = %s AND user_id = %s',
343 array('integer','integer'),
344 array($a_obj_id,$a_user_id)
345 );
346 $val_rec = $ilDB->fetchAssoc($val_set);
347 if ($time_from_lms == false) {
348 $time = $val_rec["sco_total_time_sec"];
349 } else {
350 $time = $val_rec["total_time_sec"];
351 }
352 $attempts = $val_rec["package_attempts"];
353 if ($attempts == null) {
354 $attempts = "";
355 } //??
356
357 if ($attempts != "" && $time == null) { //use old way
358 $time = self::getSumTotalTimeSecondsFromScos($a_obj_id, $a_user_id, true);
359 }
360
361 //workaround if $row->read_count == null TODO ERASE
362 try {
364 $a_type,
365 $a_ref_id,
366 $a_obj_id,
367 $a_user_id,
368 false,
369 $attempts,
370 $time
371 );
372 } catch (\Exception $exception) {
374 $a_type,
375 $a_ref_id,
376 $a_obj_id,
377 $a_user_id,
378 false,
379 null,
380 $time
381 );
382 }
383 }
384
385 public static function _isCompleted(string $a_status, string $a_satisfied): bool
386 {
387 return $a_status === "completed" || $a_satisfied === "satisfied";
388 }
389
390 public static function _isInProgress(string $a_status, string $a_satisfied): bool
391 {
392 return $a_status !== "completed";
393 }
394
395 public static function _isFailed(string $a_status, string $a_satisfied): bool
396 {
397 return $a_status === "completed" && $a_satisfied === "notSatisfied";
398 }
399
403 public static function getSumTotalTimeSecondsFromScos(int $a_obj_id, int $a_user_id, bool $a_write = false): int
404 {
405 global $DIC;
406
407 $ilDB = $DIC->database();
408 $scos = array();
409 $val_set = $ilDB->queryF(
410 'SELECT cp_node_id FROM cp_node
411 WHERE nodename = %s
412 AND cp_node.slm_id = %s',
413 array('text', 'integer'),
414 array('item', $a_obj_id)
415 );
416 while ($val_rec = $ilDB->fetchAssoc($val_set)) {
417 $scos[] = $val_rec['cp_node_id'];
418 }
419 $time = 0;
420 foreach ($scos as $sco) {
421 $sec = 0;
422 $data_set = $ilDB->queryF(
423 '
424 SELECT total_time
425 FROM cmi_node
426 WHERE cp_node_id = %s
427 AND user_id = %s',
428 array('integer','integer'),
429 array($sco, $a_user_id)
430 );
431
432 while ($data_rec = $ilDB->fetchAssoc($data_set)) {
433 $sec = ilObjSCORM2004LearningModule::_ISODurationToCentisec($data_rec["total_time"]) / 100;
434 }
435 $time += (int) $sec;
436 $sec = 0;
437 }
438 if ($a_write && $time > 0) {
439 $ilDB->queryF(
440 'UPDATE sahs_user SET sco_total_time_sec=%s WHERE obj_id = %s AND user_id = %s',
441 array('integer', 'integer', 'integer'),
442 array($time, $a_obj_id, $a_user_id)
443 );
444 }
445 return $time;
446 }
447}
448// END class.ilSCORM2004Tracking
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)
static _ISODurationToCentisec(string $str)
convert ISO 8601 Timeperiods to centiseconds
Class ilSCORM2004Tracking.
static _getCompleted(int $scorm_item_id, int $a_obj_id)
static _syncReadEvent(int $a_obj_id, int $a_user_id, string $a_type, int $a_ref_id, ?bool $time_from_lms=null)
Synch read event table.
static _getCollectionStatus(array $a_scos, int $a_obj_id, int $a_user_id)
static _getTrackedUsers(int $a_obj_id)
Get all tracked users.
static getSumTotalTimeSecondsFromScos(int $a_obj_id, int $a_user_id, bool $a_write=false)
should be avoided; store value to increase performance for further requests
static _getProgressInfoOfUser(int $a_obj_id, int $a_user_id)
Get overall scorm status.
static _getFailed(int $scorm_item_id, int $a_obj_id)
static _isFailed(string $a_status, string $a_satisfied)
static _isCompleted(string $a_status, string $a_satisfied)
static _getProgressInfo(int $a_obj_id)
Get overall scorm status.
static _getCountCompletedPerUser(array $a_scorm_item_ids, int $a_obj_id, bool $a_omit_failed=false)
Get progress of selected scos.
static _isInProgress(string $a_status, string $a_satisfied)
static _countCompleted(array $a_scos, int $a_obj_id, int $a_user_id, bool $a_omit_failed)
static _getInProgress(int $scorm_item_id, int $a_obj_id)
static _getItemProgressInfo(array $a_scorm_item_ids, int $a_obj_id, bool $a_omit_failed)
static yn2tf(string $a_yn)
$info
Definition: entry_point.php:21
$res
Definition: ltiservices.php:69
global $DIC
Definition: shib_login.php:26
$time_from_lms