ILIAS  release_5-0 Revision 5.0.0-1144-gc4397b1f870
class.ilObjSCORMLearningModule.php
Go to the documentation of this file.
1<?php
2
3/* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
4
5require_once "./Services/Object/classes/class.ilObject.php";
6require_once "./Modules/ScormAicc/classes/class.ilObjSCORMValidator.php";
7require_once "./Modules/ScormAicc/classes/class.ilObjSAHSLearningModule.php";
8
18{
20
27 function ilObjSCORMLearningModule($a_id = 0, $a_call_by_reference = true)
28 {
29 $this->type = "sahs";
30 parent::ilObject($a_id,$a_call_by_reference);
31 }
32
33
40 function validate($directory)
41 {
42 $this->validator = new ilObjSCORMValidator($directory);
43 $returnValue = $this->validator->validate();
44 return $returnValue;
45 }
46
48 {
49 if(is_object($this->validator))
50 {
51 return $this->validator->getSummary();
52 }
53 return "";
54 }
55
57 {
59 }
60
61
66 function _getTrackingItems($a_obj_id)
67 {
68 include_once("./Modules/ScormAicc/classes/SCORM/class.ilSCORMTree.php");
69 $tree = new ilSCORMTree($a_obj_id);
70 $root_id = $tree->readRootId();
71
72 $items = array();
73 $childs = $tree->getSubTree($tree->getNodeData($root_id));
74
75 foreach($childs as $child)
76 {
77 if($child["c_type"] == "sit")
78 {
79 include_once("./Modules/ScormAicc/classes/SCORM/class.ilSCORMItem.php");
80 $sc_item =& new ilSCORMItem($child["obj_id"]);
81 if ($sc_item->getIdentifierRef() != "")
82 {
83 $items[count($items)] =& $sc_item;
84 }
85 }
86 }
87
88 return $items;
89 }
90
95 function readObject()
96 {
97 global $ilErr;
98
99 $needs_convert = false;
100
101 // convert imsmanifest.xml file in iso to utf8 if needed
102
103 $manifest_file = $this->getDataDirectory()."/imsmanifest.xml";
104
105 // check if manifestfile exists and space left on device...
106 $check_for_manifest_file = is_file($manifest_file);
107
108 // if no manifestfile
109 if (!$check_for_manifest_file)
110 {
111 $this->ilias->raiseError($this->lng->txt("Manifestfile $manifest_file not found!"), $this->ilias->error_obj->MESSAGE);
112 return;
113 }
114
115 if ($check_for_manifest_file)
116 {
117 $manifest_file_array = file($manifest_file);
118 foreach($manifest_file_array as $mfa)
119 {
120 // if (seems_not_utf8($mfa))
121 if (@iconv('UTF-8', 'UTF-8', $mfa) != $mfa)
122 {
123 $needs_convert = true;
124 break;
125 }
126 }
127
128 // to copy the file we need some extraspace, counted in bytes *2 ... we need 2 copies....
129 $estimated_manifest_filesize = filesize($manifest_file) * 2;
130
131 // i deactivated this, because it seems to fail on some windows systems (see bug #1795)
132 //$check_disc_free = disk_free_space($this->getDataDirectory()) - $estimated_manifest_filesize;
133 $check_disc_free = 2;
134 }
135
136 // if $manifest_file needs to be converted to UTF8
137 if ($needs_convert)
138 {
139 // if file exists and enough space left on device
140 if ($check_for_manifest_file && ($check_disc_free > 1))
141 {
142
143 // create backup from original
144 if (!copy($manifest_file, $manifest_file.".old"))
145 {
146 echo "Failed to copy $manifest_file...<br>\n";
147 }
148
149 // read backupfile, convert each line to utf8, write line to new file
150 // php < 4.3 style
151 $f_write_handler = fopen($manifest_file.".new", "w");
152 $f_read_handler = fopen($manifest_file.".old", "r");
153 while (!feof($f_read_handler))
154 {
155 $zeile = fgets($f_read_handler);
156 //echo mb_detect_encoding($zeile);
157 fputs($f_write_handler, utf8_encode($zeile));
158 }
159 fclose($f_read_handler);
160 fclose($f_write_handler);
161
162 // copy new utf8-file to imsmanifest.xml
163 if (!copy($manifest_file.".new", $manifest_file))
164 {
165 echo "Failed to copy $manifest_file...<br>\n";
166 }
167
168 if (!@is_file($manifest_file))
169 {
170 $this->ilias->raiseError($this->lng->txt("cont_no_manifest"),
171 $this->ilias->error_obj->WARNING);
172 }
173 }
174 else
175 {
176 // gives out the specific error
177
178 if (!($check_disc_free > 1))
179 $this->ilias->raiseError($this->lng->txt("Not enough space left on device!"),$this->ilias->error_obj->MESSAGE);
180 return;
181 }
182
183 }
184 else
185 {
186 // check whether file starts with BOM (that confuses some sax parsers, see bug #1795)
187 $hmani = fopen($manifest_file, "r");
188 $start = fread($hmani, 3);
189 if (strtolower(bin2hex($start)) == "efbbbf")
190 {
191 $f_write_handler = fopen($manifest_file.".new", "w");
192 while (!feof($hmani))
193 {
194 $n = fread($hmani, 900);
195 fputs($f_write_handler, $n);
196 }
197 fclose($f_write_handler);
198 fclose($hmani);
199
200 // copy new utf8-file to imsmanifest.xml
201 if (!copy($manifest_file.".new", $manifest_file))
202 {
203 echo "Failed to copy $manifest_file...<br>\n";
204 }
205 }
206 else
207 {
208 fclose($hmani);
209 }
210 }
211
212 //validate the XML-Files in the SCORM-Package
213 if ($_POST["validate"] == "y")
214 {
215 if (!$this->validate($this->getDataDirectory()))
216 {
217 $ilErr->raiseError("<b>Validation Error(s):</b><br>".$this->getValidationSummary(),$ilErr->MESSAGE);
218 }
219 }
220
221 // start SCORM package parser
222 include_once ("./Modules/ScormAicc/classes/SCORM/class.ilSCORMPackageParser.php");
223 // todo determine imsmanifest.xml path here...
224 $slmParser = new ilSCORMPackageParser($this, $manifest_file);
225 $slmParser->startParsing();
226 return $slmParser->getPackageTitle();
227 }
228
233 {
234 global $ilSetting;
235 //condition 1
236 $lm_set = new ilSetting("lm");
237 if ($lm_set->get('scorm_lp_auto_activate') != 1) return;
238 //condition 2
239 include_once("./Services/Tracking/classes/class.ilObjUserTracking.php");
240 if (ilObjUserTracking::_enabledLearningProgress() == false) return;
241
242 //set Learning Progress to Automatic by Collection of SCORM Items
243 include_once("./Services/Tracking/classes/class.ilLPObjSettings.php");
244 $lm_set = new ilLPObjSettings($this->getId());
246 $lm_set->insert();
247
248 //select all SCOs as relevant for Learning Progress
249 include_once("Services/Tracking/classes/collection/class.ilLPCollectionOfSCOs.php");
250 $collection = new ilLPCollectionOfSCOs($this->getId(), ilLPObjSettings::LP_MODE_SCORM);
251 $scos = array();
252 foreach($collection->getPossibleItems() as $sco_id => $item)
253 {
254 $scos[] = $sco_id;
255 }
256 $collection->activateEntries($scos);
257 }
262 {
263 global $ilDB, $ilUser;
264
265 $sco_set = $ilDB->queryF('
266 SELECT DISTINCT sco_id FROM scorm_tracking WHERE obj_id = %s',
267 array('integer'),array($this->getId()));
268
269 $items = array();
270 while($sco_rec = $ilDB->fetchAssoc($sco_set))
271 {
272 include_once("./Modules/ScormAicc/classes/SCORM/class.ilSCORMItem.php");
273 $sc_item =& new ilSCORMItem($sco_rec["sco_id"]);
274 if ($sc_item->getIdentifierRef() != "")
275 {
276 $items[count($items)] =& $sc_item;
277 }
278 }
279
280 return $items;
281 }
282
290 public static function _lookupLastAccess($a_obj_id, $a_usr_id)
291 {
292 global $ilDB;
293
294 $result = $ilDB->queryF('
295 SELECT last_access FROM sahs_user
296 WHERE obj_id = %s
297 AND user_id = %s',
298 array('integer','integer'), array($a_obj_id,$a_usr_id));
299
300 if ($ilDB->numRows($result))
301 {
302 $row = $ilDB->fetchAssoc($result);
303 return $row["last_access"];
304 }
305 return "";
306 }
307
308 function getTrackedUsers($a_search)
309 {
310 global $ilDB, $ilUser;
311//TODO: UK last_access is not correct if no Commit or last_visited_sco
312// $query = 'SELECT user_id,MAX(c_timestamp) last_access, lastname, firstname FROM scorm_tracking st ' .
313 $query = 'SELECT user_id, last_access, lastname, firstname FROM sahs_user st ' .
314 'JOIN usr_data ud ON st.user_id = ud.usr_id ' .
315 'WHERE obj_id = ' . $ilDB->quote($this->getId(), 'integer');
316 if($a_search) {
317// $query .= ' AND (' . $ilDB->like('lastname', 'text', '%' . $a_search . '%') . ' OR ' . $ilDB->like('firstname', 'text', '%' . $a_search . '%') .')';
318 $query .= ' AND ' . $ilDB->like('lastname', 'text', '%' . $a_search . '%');
319 }
320 $query .= ' GROUP BY user_id, lastname, firstname, last_access';
321 $sco_set = $ilDB->query($query);
322
323 $items = array();
324 while($sco_rec = $ilDB->fetchAssoc($sco_set))
325 {
326 $items[] = $sco_rec;
327 }
328 return $items;
329 }
330
331
337 public function getAttemptsForUsers()
338 {
339 global $ilDB;
340 $query = 'SELECT user_id, package_attempts FROM sahs_user WHERE obj_id = ' . $ilDB->quote($this->getId(), 'integer') . ' ';
341 $res = $ilDB->query($query);
342
343 $attempts = array();
344 while($row = $res->fetchRow(DB_FETCHMODE_ASSOC))
345 {
346 $attempts[$row['user_id']] = (int) $row['package_attempts'];
347 }
348 return $attempts;
349 }
350
351
355 function getAttemptsForUser($a_user_id){
356 global $ilDB;
357 $val_set = $ilDB->queryF('SELECT package_attempts FROM sahs_user WHERE obj_id = %s AND user_id = %s',
358 array('integer','integer'),
359 array($this->getId(),$a_user_id,0));
360
361 $val_rec = $ilDB->fetchAssoc($val_set);
362
363 if ($val_rec["package_attempts"] == null) {
364 $val_rec["package_attempts"]="";
365 }
366 return $val_rec["package_attempts"];
367 }
368
369
374 public function getModuleVersionForUsers()
375 {
376 global $ilDB;
377 $query = 'SELECT user_id, module_version FROM sahs_user WHERE obj_id = ' . $ilDB->quote($this->getId(), 'integer') . ' ';
378 $res = $ilDB->query($query);
379
380 $versions = array();
381 while($row = $res->fetchRow(DB_FETCHMODE_ASSOC))
382 {
383 $versions[$row['user_id']] = (int) $row['module_version'];
384 }
385 return $versions;
386 }
387
388
392 function getModuleVersionForUser($a_user_id){
393 global $ilDB;
394 $val_set = $ilDB->queryF('SELECT module_version FROM sahs_user WHERE obj_id = %s AND user_id = %s',
395 array('integer','integer'),
396 array($this->getId(),$a_user_id,0));
397
398 $val_rec = $ilDB->fetchAssoc($val_set);
399
400 if ($val_rec["module_version"] == null) {
401 $val_rec["module_version"]="";
402 }
403 return $val_rec["module_version"];
404 }
405
413 function getTrackingDataPerUser($a_sco_id, $a_user_id)
414 {
415 global $ilDB;
416
417 $data_set = $ilDB->queryF('
418 SELECT * FROM scorm_tracking
419 WHERE user_id = %s
420 AND sco_id = %s
421 AND obj_id = %s
422 ORDER BY lvalue',
423 array('integer','integer','integer'),
424 array($a_user_id,$a_sco_id,$this->getId()));
425
426 $data = array();
427 while($data_rec = $ilDB->fetchAssoc($data_set)) {
428 $data[] = $data_rec;
429 }
430
431 return $data;
432 }
433
434 function getTrackingDataAgg($a_user_id)
435 {
436 global $ilDB;
437
438 // get all users with any tracking data
439 $sco_set = $ilDB->queryF('
440 SELECT DISTINCT sco_id FROM scorm_tracking
441 WHERE obj_id = %s
442 AND user_id = %s
443 AND sco_id <> %s',
444 array('integer','integer','integer'),
445 array($this->getId(),$a_user_id,0));
446
447 $data = array();
448 while($sco_rec = $ilDB->fetchAssoc($sco_set))
449 {
450 $data_set = $ilDB->queryF('
451 SELECT * FROM scorm_tracking
452 WHERE obj_id = %s
453 AND sco_id = %s
454 AND user_id = %s
455 AND lvalue <> %s
456 AND (lvalue = %s
457 OR lvalue = %s
458 OR lvalue = %s)',
459 array('integer','integer','integer','text','text','text','text'),
460 array($this->getId(),
461 $sco_rec["sco_id"],
462 $a_user_id,
463 "package_attempts",
464 "cmi.core.lesson_status",
465 "cmi.core.total_time",
466 "cmi.core.score.raw")
467 );
468
469 $score = $time = $status = "";
470
471 while($data_rec = $ilDB->fetchAssoc($data_set))
472 {
473 switch($data_rec["lvalue"])
474 {
475 case "cmi.core.lesson_status":
476 $status = $data_rec["rvalue"];
477 break;
478
479 case "cmi.core.total_time":
480 $time = $data_rec["rvalue"];
481 break;
482
483 case "cmi.core.score.raw":
484 $score = $data_rec["rvalue"];
485 break;
486 }
487 }
488 //create sco_object
489 include_once './Modules/ScormAicc/classes/SCORM/class.ilSCORMItem.php';
490 $sc_item =& new ilSCORMItem($sco_rec["sco_id"]);
491 $data[] = array("sco_id"=>$sco_rec["sco_id"], "title" => $sc_item->getTitle(),
492 "score" => $score, "time" => $time, "status" => $status);
493
494 }
495 return (array) $data;
496 }
497
498 function getTrackingDataAggSco($a_sco_id)
499 {
500 global $ilDB;
501
502 // get all users with any tracking data
503 $user_set = $ilDB->queryF('
504 SELECT DISTINCT user_id FROM scorm_tracking
505 WHERE obj_id = %s
506 AND sco_id = %s',
507 array('integer','integer'),
508 array($this->getId(),$a_sco_id));
509
510 $data = array();
511 while($user_rec = $ilDB->fetchAssoc($user_set))
512 {
513
514 $data_set = $ilDB->queryF('
515 SELECT * FROM scorm_tracking
516 WHERE obj_id = %s
517 AND sco_id = %s
518 AND user_id = %s
519 AND (lvalue = %s
520 OR lvalue = %s
521 OR lvalue = %s)',
522 array('integer','integer','integer','text','text','text'),
523 array($this->getId(),
524 $a_sco_id,
525 $user_rec["user_id"],
526 "cmi.core.lesson_status",
527 "cmi.core.total_time",
528 "cmi.core.score.raw")
529 );
530
531 $score = $time = $status = "";
532
533 while($data_rec = $ilDB->fetchAssoc($data_set))
534 {
535 switch($data_rec["lvalue"])
536 {
537 case "cmi.core.lesson_status":
538 $status = $data_rec["rvalue"];
539 break;
540
541 case "cmi.core.total_time":
542 $time = $data_rec["rvalue"];
543 break;
544
545 case "cmi.core.score.raw":
546 $score = $data_rec["rvalue"];
547 break;
548 }
549 }
550
551 $data[] = array("user_id" => $user_rec["user_id"],
552 "score" => $score, "time" => $time, "status" => $status);
553 }
554
555 return $data;
556 }
557
558
559
567 public function exportSelected($a_all, $a_users = array())
568 {
569 global $ilDB, $ilUser;
570 include_once('./Modules/ScormAicc/classes/class.ilSCORMTrackingItems.php');
571 include_once("./Services/Tracking/classes/class.ilLearningProgressBaseGUI.php");
572 include_once('./Services/PrivacySecurity/classes/class.ilPrivacySettings.php');
574 $allowExportPrivacy = $privacy->enabledExportSCORM();
575
576 $csv = "";
577 $query = 'SELECT * FROM sahs_user WHERE obj_id = %s';
578 if (count($a_users) >0) $query .= ' AND '.$ilDB->in('user_id', $a_users, false, 'integer');
579 $res = $ilDB->queryF(
580 $query,
581 array('integer'),
582 array($this->getId())
583 );
584 while ($data = $ilDB->fetchAssoc($res)) {
585 $csv = $csv. $data["obj_id"]
586 . ";\"" . $this->getTitle() ."\""
587 . ";" . $data["module_version"]
588 . ";\"" . implode("\";\"",ilSCORMTrackingItems::userDataArrayForExport($data["user_id"], $allowExportPrivacy)) ."\""
589 . ";\"" . $data["last_access"] ."\""
590 . ";\"" . ilLearningProgressBaseGUI::__readStatus($data["obj_id"],$data["user_id"]) ."\"" //not $data["status"] because modifications to learning progress could have made before export
591 . ";" . $data["package_attempts"]
592 . ";" . $data["percentage_completed"]
593 . ";" . $data["sco_total_time_sec"]
594// . ";\"" . $certificateDate ."\""
595 . "\n";
596 }
598 $header = "LearningModuleId;LearningModuleTitle;LearningModuleVersion;".str_replace(',',';',$udh["cols"]).";"
599 . "LastAccess;Status;Attempts;percentageCompletedSCOs;SumTotal_timeSeconds\n";
600
601 $this->sendExportFile($header, $csv);
602 }
603
604
605 function importTrackingData($a_file)
606 {
607 global $ilDB, $ilUser;
608
609 $error = 0;
610 //echo file_get_contents($a_file);
611 $method = null;
612
613 //lets import
614 $fhandle = fopen($a_file, "r");
615
616 //the top line is the field names
617 $fields = fgetcsv($fhandle, pow(2, 16), ';');
618 //lets check the import method
619 fclose($fhandle);
620
621 switch($fields[0])
622 {
623 case "Scoid":
624 case "SCO-Identifier":
625 $error = $this->importRaw($a_file);
626 break;
627 case "Department":
628 case "LearningModuleId":
629 $error = $this->importSuccess($a_file);
630 break;
631 default:
632 return -1;
633 break;
634 }
635 return $error;
636 }
637
638 function importSuccess($a_file) {
639
640 global $ilDB, $ilUser;
641 include_once("./Services/Tracking/classes/class.ilLPStatus.php");
642 $scos = array();
643 //get all SCO's of this object ONLY RELEVANT!
644 include_once './Services/Object/classes/class.ilObjectLP.php';
645 $olp = ilObjectLP::getInstance($this->getId());
646 $collection = $olp->getCollectionInstance();
647 if($collection)
648 {
649 $scos = $collection->getItems();
650 }
651
652 $fhandle = fopen($a_file, "r");
653
654 $obj_id = $this->getID();
655 $fields = fgetcsv($fhandle, pow(2, 16), ';');
656 // $users = array();
657 while(($csv_rows = fgetcsv($fhandle, pow(2, 16), ";")) !== FALSE)
658 {
659 $data = array_combine($fields, $csv_rows);
660 //no check the format - sufficient to import users
661 if ($data["Login"]) $user_id = $this->get_user_id($data["Login"]);
662 if ($data["login"]) $user_id = $this->get_user_id($data["login"]);
663 //add mail in future
664 if ($data["user"] && is_int($data["user"])) $user_id = $data["user"];
665 if ($user_id>0) {
666
667 $last_access = ilUtil::now();
668 if ($data['Date']) {
669 $date_ex = explode('.', $data['Date']);
670 $last_access = implode('-', array($date_ex[2], $date_ex[1], $date_ex[0]));
671 }
672 if ($data['LastAccess']) {
673 $last_access = $data['LastAccess'];
674 }
675
677 // $users[] = $user_id;
678 if ($data["Status"]) {
679 if (is_int($data["Status"])) $status = $data["Status"];
683 }
684 $attempts = null;
685 if($data["Attempts"]) $attempts = $data["Attempts"];
686
687 $percentage_completed = 0;
688 if ($status == ilLPStatus::LP_STATUS_COMPLETED_NUM) $percentage_completed = 100;
689 if ($data['percentageCompletedSCOs']) $percentage_completed = $data['percentageCompletedSCOs'];
690
691 $sco_total_time_sec = null;
692 if ($data['SumTotal_timeSeconds']) $sco_total_time_sec = $data['SumTotal_timeSeconds'];
693
694 $this->importSuccessForSahsUser($user_id, $last_access, $status, $attempts, $percentage_completed, $sco_total_time_sec);
695
697 foreach ($scos as $sco_id)
698 {
699 $statement = $ilDB->queryF('
700 SELECT * FROM scorm_tracking
701 WHERE user_id = %s
702 AND sco_id = %s
703 AND lvalue = %s
704 AND obj_id = %s',
705 array('integer','integer','text','integer'),
706 array($user_id, $sco_id, 'cmi.core.lesson_status',$obj_id)
707 );
708 if($ilDB->numRows($statement) > 0)
709 {
710 $ilDB->update('scorm_tracking',
711 array(
712 'rvalue' => array('clob', 'completed'),
713 'c_timestamp' => array('timestamp', $last_access)
714 ),
715 array(
716 'user_id' => array('integer', $user_id),
717 'sco_id' => array('integer', $sco_id),
718 'lvalue' => array('text', 'cmi.core.lesson_status'),
719 'obj_id' => array('integer', $obj_id)
720 )
721 );
722 }
723 else
724 {
725 $ilDB->insert('scorm_tracking', array(
726 'obj_id' => array('integer', $obj_id),
727 'user_id' => array('integer', $user_id),
728 'sco_id' => array('integer', $sco_id),
729 'lvalue' => array('text', 'cmi.core.lesson_status'),
730 'rvalue' => array('clob', 'completed'),
731 'c_timestamp' => array('timestamp', $last_access)
732 ));
733 }
734 }
735 }
736 } else {
737 //echo "Warning! User $csv_rows[0] does not exist in ILIAS. Data for this user was skipped.\n";
738 }
739 }
740
741 include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
743// <4.2.6: foreach ($users as $user_id) {ilLPStatusWrapper::_updateStatus($obj_id, $user_id);}
744 return 0;
745 }
746
747 function importSuccessForSahsUser($user_id, $last_access, $status, $attempts=null, $percentage_completed=null, $sco_total_time_sec=null){
748 global $ilDB;
749 $statement = $ilDB->queryF('SELECT * FROM sahs_user WHERE obj_id = %s AND user_id = %s',
750 array('integer','integer'),
751 array($this->getID(),$user_id)
752 );
753 if($ilDB->numRows($statement) > 0)
754 {
755 $ilDB->update('sahs_user',
756 array(
757 'last_access' => array('timestamp', $last_access),
758 'status' => array('integer', $status),
759 'package_attempts' => array('integer', $attempts),
760 'percentage_completed' => array('integer', $percentage_completed),
761 'sco_total_time_sec' => array('integer', $sco_total_time_sec)
762 ),
763 array(
764 'obj_id' => array('integer', $this->getID()),
765 'user_id' => array('integer', $user_id)
766 )
767 );
768 }
769 else
770 {
771 $ilDB->insert('sahs_user', array(
772 'obj_id' => array('integer', $this->getID()),
773 'user_id' => array('integer', $user_id),
774 'last_access' => array('timestamp', $last_access),
775 'status' => array('integer', $status),
776 'package_attempts' => array('integer', $attempts),
777 'percentage_completed' => array('integer', $percentage_completed),
778 'sco_total_time_sec' => array('integer', $sco_total_time_sec)
779 ));
780 }
781 }
782
788 private function parseUserId($il_id)
789 {
790 global $ilSetting;
791
792 $parts = explode('_', $il_id);
793
794 if(!count((array) $parts))
795 {
796 return 0;
797 }
798 if(!isset($parts[2]) or !isset($parts[3]))
799 {
800 return 0;
801 }
802 if($parts[2] != $ilSetting->get('inst_id',$parts[2]))
803 {
804 return 0;
805 }
806 return $parts[3];
807 }
808
816 private function importRaw($a_file)
817 {
818 global $ilDB, $ilUser,$lng;
819 $lng->loadLanguageModule("scormtrac");
820
821 $fhandle = fopen($a_file, "r");
822
823 $fields = fgetcsv($fhandle, pow(2, 16), ';');
824 $users = array();
825 while(($csv_rows = fgetcsv($fhandle, pow(2, 16), ";")) !== FALSE)
826 {
827 $data = array_combine($fields, $csv_rows);
828 if ($data['Userid']) {
829 $user_id = $this->parseUserId($data['Userid']);
830 }
831 else if ($data[$lng->txt("user")])
832 {
833 if (is_int($data[$lng->txt("user")])) $user_id = $data[$lng->txt("user")];
834 }
835 if ($data[$lng->txt("login")])
836 {
837 $user_id = $this->get_user_id($data[$lng->txt("login")]);
838 }
839 if(!$user_id)
840 {
841 continue;
842 }
843
844 if ($data['Scoid'])
845 {
846 $il_sco_id = $this->lookupSCOId($data['Scoid']);
847 }
848 if ($data[$lng->txt("identifierref")])
849 {
850 $il_sco_id = $this->lookupSCOId($data[$lng->txt("identifierref")]);
851 }
852 if(!$il_sco_id)
853 {
854 continue;
855 }
856
857 $c_timestamp="";
858 if ($data['Timestamp'])
859 {
860 $c_timestamp = $data['Timestamp'];
861 }
862 if ($data[$lng->txt("c_timestamp")])
863 {
864 $c_timestamp = $data[$lng->txt("c_timestamp")];
865 }
866 if ($c_timestamp == "")
867 {
868 $date = new DateTime();
869 $c_timestamp = $date->getTimestamp();
870 }
871
872 if(!$data['Key'])
873 {
874 continue;
875 }
876 if(!$data['Value'])
877 {
878 $data['Value'] = "";
879 }
880 //do the actual import
881 if($il_sco_id > 0)
882 {
883 $statement = $ilDB->queryF('
884 SELECT * FROM scorm_tracking
885 WHERE user_id = %s
886 AND sco_id = %s
887 AND lvalue = %s
888 AND obj_id = %s',
889 array('integer', 'integer', 'text', 'integer'),
890 array($user_id, $il_sco_id, $data['Key'], $this->getID())
891 );
892 if($ilDB->numRows($statement) > 0)
893 {
894 $ilDB->update('scorm_tracking',
895 array(
896 'rvalue' => array('clob', $data['Value']),
897 'c_timestamp' => array('timestamp', $c_timestamp)
898 ),
899 array(
900 'user_id' => array('integer', $user_id),
901 'sco_id' => array('integer', $il_sco_id),
902 'lvalue' => array('text', $data['Key']),
903 'obj_id' => array('integer', $this->getId())
904 )
905 );
906 }
907 else
908 {
909 $ilDB->insert('scorm_tracking', array(
910 'obj_id' => array('integer', $this->getId()),
911 'user_id' => array('integer', $user_id),
912 'sco_id' => array('integer', $il_sco_id),
913 'lvalue' => array('text', $data['Key']),
914 'rvalue' => array('clob', $data['Value']),
915 'c_timestamp' => array('timestamp', $data['Timestamp'])
916 ));
917 }
918 }
919 $package_attempts = 1;
920 if($il_sco_id == 0)
921 {
922 if ($data['Key'] == "package_attempts") $package_attempts = $data['Value'];
923 }
924 //UK determineStatus, percentage_completed and syncGlobalStatus
925
926 }
927 fclose($fhandle);
928
929 include_once './Services/Tracking/classes/class.ilLPStatusWrapper.php';
931
932 return 0;
933 }
934
935
941 function decreaseAttemptsForUser($a_user_id) {
942 global $ilDB;
943
944 foreach ($a_user_id as $user)
945 {
946 //first check if there is a package_attempts entry
947 $val_set = $ilDB->queryF('SELECT package_attempts FROM sahs_user WHERE user_id = %s AND obj_id = %s',
948 array('integer','integer'),
949 array($user,$this->getID()));
950
951 $val_rec = $ilDB->fetchAssoc($val_set);
952
953 if ($val_rec["package_attempts"] != null && $val_rec["package_attempts"] != 0)
954 {
955 $new_rec = 0;
956 //decrease attempt by 1
957 if ((int)$val_rec["package_attempts"] > 0) $new_rec = (int)$val_rec["package_attempts"]-1;
958 $ilDB->manipulateF('UPDATE sahs_user SET package_attempts = %s WHERE user_id = %s AND obj_id = %s',
959 array('integer','integer','integer'),
960 array($new_rec,$user,$this->getID()));
961
962 //following 2 lines were before 4.4 only for SCORM 1.2
963 include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
965 }
966 }
967 }
968
969
970 //helper function
971 function get_user_id($a_login) {
972 global $ilDB, $ilUser;
973
974 $val_set = $ilDB->queryF('SELECT * FROM usr_data WHERE(login=%s)',
975 array('text'),array($a_login));
976 $val_rec = $ilDB->fetchAssoc($val_set);
977
978 if (count($val_rec)>0) {
979 return $val_rec['usr_id'];
980 } else {
981 return null;
982 }
983 }
984
985
989 private function lookupSCOId($a_referrer){
990 global $ilDB, $ilUser;
991
992 //non specific SCO entries
993 if ($a_referrer=="0") {
994 return 0;
995 }
996
997 $val_set = $ilDB->queryF('
998 SELECT obj_id FROM sc_item,scorm_tree
999 WHERE (obj_id = child
1000 AND identifierref = %s
1001 AND slm_id = %s)',
1002 array('text','integer'), array($a_referrer,$this->getID()));
1003 $val_rec = $ilDB->fetchAssoc($val_set);
1004
1005 return $val_rec["obj_id"];
1006 }
1007
1011 function getUserIdEmail($a_mail)
1012 {
1013 global $ilDB, $ilUser;
1014
1015 $val_set = $ilDB->queryF('SELECT usr_id FROM usr_data WHERE(email=%s)',
1016 array('text'),array($a_mail));
1017 $val_rec = $ilDB->fetchAssoc($val_set);
1018
1019
1020 return $val_rec["usr_id"];
1021 }
1022
1023
1027 function sendExportFile($a_header,$a_content)
1028 {
1029 $timestamp = time();
1030 $refid = $this->getRefId();
1031 $filename = "scorm_tracking_".$refid."_".$timestamp.".csv";
1032 //Header
1033 header("Expires: 0");
1034 header("Cache-control: private");
1035 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
1036 header("Content-Description: File Transfer");
1037 header("Content-Type: application/octet-stream");
1038 header("Content-disposition: attachment; filename=$filename");
1039 echo $a_header.$a_content;
1040 exit;
1041 }
1042
1048 public static function _getAllScoIds($a_id)
1049 {
1050 global $ilDB;
1051
1052 $scos = array();
1053
1054 $val_set = $ilDB->queryF('
1055 SELECT scorm_object.obj_id,
1056 scorm_object.title,
1057 scorm_object.c_type,
1058 scorm_object.slm_id,
1059 scorm_object.obj_id scoid
1060 FROM scorm_object,sc_item,sc_resource
1061 WHERE(scorm_object.slm_id = %s
1062 AND scorm_object.obj_id = sc_item.obj_id
1063 AND sc_item.identifierref = sc_resource.import_id
1064 AND sc_resource.scormtype = %s)
1065 GROUP BY scorm_object.obj_id,
1066 scorm_object.title,
1067 scorm_object.c_type,
1068 scorm_object.slm_id,
1069 scorm_object.obj_id ',
1070 array('integer', 'text'),
1071 array($a_id,'sco'));
1072
1073 while ($val_rec = $ilDB->fetchAssoc($val_set))
1074 {
1075 array_push($scos,$val_rec['scoid']);
1076 }
1077 return $scos;
1078 }
1079
1088 public static function _getStatusForUser($a_id, $a_user,$a_allScoIds,$a_numerical=false)
1089 {
1090 global $ilDB, $lng;
1091
1092 $scos = $a_allScoIds;
1093 //check if all SCO's are completed
1094 $scos_c = implode(',',$scos);
1095
1096 $val_set = $ilDB->queryF('
1097 SELECT * FROM scorm_tracking
1098 WHERE (user_id = %s
1099 AND obj_id = %s
1100 AND '.$ilDB->in('sco_id', $scos, false, 'integer').'
1101 AND ((lvalue = %s AND '.$ilDB->like('rvalue', 'clob', 'completed').')
1102 OR (lvalue = %s AND '.$ilDB->like('rvalue', 'clob', 'passed').')))',
1103 array('integer','integer','text','text'),
1104 array($a_user,$a_id,'cmi.core.lesson_status', 'cmi.core.lesson_status'));
1105 while ($val_rec = $ilDB->fetchAssoc($val_set))
1106 {
1107 $key = array_search($val_rec['sco_id'], $scos);
1108 unset ($scos[$key]);
1109 }
1110 //check for completion
1111 if (count($scos) == 0) {
1112 $completion = ($a_numerical===true) ? true: $lng->txt("cont_complete");
1113 }
1114 if (count($scos) > 0) {
1115 $completion = ($a_numerical===true) ? false: $lng->txt("cont_incomplete");
1116 }
1117 return $completion;
1118 }
1119
1126 public static function _getCourseCompletionForUser($a_id, $a_user)
1127 {
1129 }
1130
1131 function getAllScoIds(){
1132 global $ilDB;
1133
1134 $scos = array();
1135 //get all SCO's of this object
1136 $val_set = $ilDB->queryF('
1137 SELECT scorm_object.obj_id,
1138 scorm_object.title,
1139 scorm_object.c_type,
1140 scorm_object.slm_id,
1141 scorm_object.obj_id scoid
1142 FROM scorm_object, sc_item,sc_resource
1143 WHERE(scorm_object.slm_id = %s
1144 AND scorm_object.obj_id = sc_item.obj_id
1145 AND sc_item.identifierref = sc_resource.import_id
1146 AND sc_resource.scormtype = %s )
1147 GROUP BY scorm_object.obj_id,
1148 scorm_object.title,
1149 scorm_object.c_type,
1150 scorm_object.slm_id,
1151 scorm_object.obj_id',
1152 array('integer','text'),
1153 array($this->getId(),'sco'));
1154
1155 while ($val_rec = $ilDB->fetchAssoc($val_set))
1156 {
1157 array_push($scos,$val_rec['scoid']);
1158 }
1159 return $scos;
1160 }
1161
1162 function getStatusForUser($a_user,$a_allScoIds,$a_numerical=false){
1163 global $ilDB;
1164 $scos = $a_allScoIds;
1165 //loook up status
1166 //check if all SCO's are completed
1167 $scos_c = implode(',',$scos);
1168
1169 $val_set = $ilDB->queryF('
1170 SELECT sco_id FROM scorm_tracking
1171 WHERE (user_id = %s
1172 AND obj_id = %s
1173 AND '.$ilDB->in('sco_id', $scos, false, 'integer').'
1174 AND ((lvalue = %s AND '.$ilDB->like('rvalue', 'clob', 'completed').') OR (lvalue = %s AND '.$ilDB->like('rvalue', 'clob', 'passed').') ) )',
1175 array('integer','integer','text','text',),
1176 array($a_user,$this->getID(),'cmi.core.lesson_status','cmi.core.lesson_status'));
1177 while ($val_rec = $ilDB->fetchAssoc($val_set))
1178 {
1179 $key = array_search($val_rec['sco_id'], $scos);
1180 unset ($scos[$key]);
1181 }
1182 //check for completion
1183 if (count($scos) == 0) {
1184 $completion = ($a_numerical===true) ? true: $this->lng->txt("cont_complete");
1185 }
1186 if (count($scos) > 0) {
1187 $completion = ($a_numerical===true) ? false: $this->lng->txt("cont_incomplete");
1188 }
1189 return $completion;
1190 }
1191
1192 function getCourseCompletionForUser($a_user) {
1193 return $this->getStatusForUser($a_user,$this->getAllScoIds,true);
1194 }
1195
1196 //to be called from IlObjUser
1197 public static function _removeTrackingDataForUser($user_id) {
1198 global $ilDB;
1199 //gobjective
1200 $ilDB->manipulateF(
1201 'DELETE FROM scorm_tracking WHERE user_id = %s',
1202 array('integer'),
1203 array($user_id)
1204 );
1205 $ilDB->manipulateF(
1206 'DELETE FROM sahs_user WHERE user_id = %s',
1207 array('integer'),
1208 array($user_id)
1209 );
1210 }
1211
1212 function _getScoresForUser($a_item_id, $a_user_id)
1213 {
1214 global $ilDB;
1215
1216 $retAr = array("raw" => null, "max" => null, "scaled" => null);
1217 $val_set = $ilDB->queryF("
1218 SELECT lvalue, rvalue FROM scorm_tracking
1219 WHERE sco_id = %s
1220 AND user_id = %s
1221 AND (lvalue = 'cmi.core.score.raw' OR lvalue = 'cmi.core.score.max')",
1222 array('integer', 'integer'),
1223 array($a_item_id, $a_user_id)
1224 );
1225 while ($val_rec = $ilDB->fetchAssoc($val_set))
1226 {
1227 if ($val_rec['lvalue'] == "cmi.core.score.raw") $retAr["raw"] = $val_rec["rvalue"];
1228 if ($val_rec['lvalue'] == "cmi.core.score.max") $retAr["max"] = $val_rec["rvalue"];
1229 }
1230 if ($retAr["raw"] != null && $retAr["max"] != null) $retAr["scaled"] = ($retAr["raw"] / $retAr["max"]);
1231
1232 return $retAr;
1233 }
1234
1235
1236 public function getLastVisited($user_id)
1237 {
1238 global $ilDB;
1239 $val_set = $ilDB->queryF('SELECT last_visited FROM sahs_user WHERE obj_id = %s AND user_id = %s',
1240 array('integer','integer'),
1241 array($this->getID(),$user_id)
1242 );
1243 while ($val_rec = $ilDB->fetchAssoc($val_set))
1244 {
1245 if ($val_rec["last_visited"] != null) return "".$val_rec["last_visited"];
1246 }
1247 return '0';
1248 }
1249
1250 function deleteTrackingDataOfUsers($a_users)
1251 {
1252 global $ilDB;
1253 include_once("./Services/Tracking/classes/class.ilChangeEvent.php");
1254 include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
1255
1257
1258 foreach($a_users as $user)
1259 {
1260 $ilDB->manipulateF('
1261 DELETE FROM scorm_tracking
1262 WHERE user_id = %s
1263 AND obj_id = %s',
1264 array('integer', 'integer'),
1265 array($user, $this->getID()));
1266
1267 $ilDB->manipulateF('
1268 DELETE FROM sahs_user
1269 WHERE user_id = %s
1270 AND obj_id = %s',
1271 array('integer', 'integer'),
1272 array($user, $this->getID()));
1273
1274 ilLPStatusWrapper::_updateStatus($this->getId(), $user);
1275 }
1276 }
1277
1278}
1279?>
$result
$n
Definition: RandomTest.php:80
$filename
Definition: buildRTE.php:89
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:81
const DB_FETCHMODE_ASSOC
Definition: class.ilDB.php:10
static _deleteReadEventsForUsers($a_obj_id, array $a_user_ids)
static _updateStatus($a_obj_id, $a_usr_id, $a_obj=null, $a_percentage=false, $a_no_raise=false, $a_force_raise=false)
Update status.
_refreshStatus($a_obj_id, $a_users=null)
Set dirty.
const LP_STATUS_COMPLETED_NUM
const LP_STATUS_FAILED
const LP_STATUS_IN_PROGRESS_NUM
const LP_STATUS_NOT_ATTEMPTED_NUM
const LP_STATUS_FAILED_NUM
const LP_STATUS_NOT_ATTEMPTED
const LP_STATUS_IN_PROGRESS
Class ilObjSCORMLearningModule.
getDataDirectory($mode="filesystem")
get data directory of lm
Class ilObjSCORMLearningModule.
getStatusForUser($a_user, $a_allScoIds, $a_numerical=false)
setLearningProgressSettingsAtUpload()
set settings for learning progress determination per default at upload
getModuleVersionForUsers()
Get module version for users.
importRaw($a_file)
Import raw data @global ilDB $ilDB @global ilObjUser $ilUser.
ilObjSCORMLearningModule($a_id=0, $a_call_by_reference=true)
Constructor @access public.
exportSelected($a_all, $a_users=array())
Export selected user tracking data @global ilDB $ilDB @global ilObjUser $ilUser.
static _getStatusForUser($a_id, $a_user, $a_allScoIds, $a_numerical=false)
Get the status of a SCORM module for a given user.
getAttemptsForUser($a_user_id)
get number of atttempts for a certain user and package
_getTrackingItems($a_obj_id)
get all tracking items of scorm object @access static
lookupSCOId($a_referrer)
resolves manifest SCOID to internal ILIAS SCO ID
getAttemptsForUsers()
Get attempts for all users @global ilDB $ilDB.
parseUserId($il_id)
Parse il_usr_123_6 id.
static _lookupLastAccess($a_obj_id, $a_usr_id)
Return the last access timestamp for a given user.
importSuccessForSahsUser($user_id, $last_access, $status, $attempts=null, $percentage_completed=null, $sco_total_time_sec=null)
validate($directory)
Validate all XML-Files in a SCOM-Directory.
getTrackingDataPerUser($a_sco_id, $a_user_id)
Get tracking data per user @global ilDB $ilDB.
sendExportFile($a_header, $a_content)
send export file to browser
static _getCourseCompletionForUser($a_id, $a_user)
Get the completion of a SCORM module for a given user.
readObject()
read manifest file @access public
getTrackedItems()
get all tracked items of current user
static _getAllScoIds($a_id)
Get an array of id's for all Sco's in the module.
decreaseAttemptsForUser($a_user_id)
Decrease attempts for user @global ilDB $ilDB.
getUserIdEmail($a_mail)
assumes that only one account exists for a mailadress
getModuleVersionForUser($a_user_id)
get module version that tracking data for a user was recorded on
Validation of SCORM-XML Files.
static _enabledLearningProgress()
check wether learing progress is enabled or not
static getInstance($a_obj_id)
getRefId()
get reference id @access public
getId()
get object id @access public
getTitle()
get object title @access public
static _getInstance()
Get instance of ilPrivacySettings.
userDataArrayForExport($user, $b_allowExportPrivacy=false)
SCORM Object Tree.
ILIAS Setting Class.
static now()
Return current timestamp in Y-m-d H:i:s format.
$_POST['username']
Definition: cron.php:12
exit
Definition: login.php:54
redirection script todo: (a better solution should control the processing via a xml file)
global $ilSetting
Definition: privfeed.php:40
global $ilDB
$lm_set
global $ilUser
Definition: imgupload.php:15