3 declare(strict_types=1);
28 public const DB_ENCODE_XSL =
'./Modules/Scorm2004/templates/xsl/op/op-scorm13.xsl';
29 public const CONVERT_XSL =
'./Modules/Scorm2004/templates/xsl/op/scorm12To2004.xsl';
30 public const DB_DECODE_XSL =
'./Modules/Scorm2004/templates/xsl/op/op-scorm13-revert.xsl';
31 public const VALIDATE_XSD =
'./libs/ilias/Scorm2004/xsd/op/op-scorm13.xsd';
33 public const WRAPPER_HTML =
'./Modules/Scorm2004/scripts/converter/GenericRunTimeWrapper1.0_aadlc/GenericRunTimeWrapper.htm';
34 public const WRAPPER_JS =
'./Modules/Scorm2004/scripts/converter/GenericRunTimeWrapper1.0_aadlc/SCOPlayerWrapper.js';
86 $this->packagesFolder =
'';
87 if ($packageId != null) {
88 $this->
load($packageId);
92 public function load(
int $packageId): void
95 $ilDB = $DIC->database();
97 $lm_set =
$ilDB->queryF(
'SELECT * FROM sahs_lm WHERE id = %s', array(
'integer'), array($packageId));
99 $pg_set =
$ilDB->queryF(
'SELECT * FROM cp_package WHERE obj_id = %s', array(
'integer'), array($packageId));
102 $this->packageData = array_merge($lm_data, $pg_data);
104 $this->packageFolder = $this->packagesFolder .
'/' .
$packageId;
106 $this->imsmanifestFile = $this->packageFolder .
'/' .
'imsmanifest.xml';
114 public function il_import(
string $packageFolder,
int $packageId,
bool $reimport =
false): bool|string
117 $ilDB = $DIC->database();
123 if ($reimport ===
true) {
128 $this->packageData[
'persistprevattempts'] = 0;
129 $this->packageData[
'default_lesson_mode'] =
'normal';
130 $this->packageData[
'credit'] =
'credit';
131 $this->packageData[
'auto_review'] =
'n';
135 $this->imsmanifestFile = $this->packageFolder .
'/' .
'imsmanifest.xml';
139 if (!@$this->imsmanifest->load($this->imsmanifestFile)) {
140 $this->diagnostic[] =
'XML not wellformed';
145 $this->manifest = $this->
transform($this->imsmanifest, self::DB_ENCODE_XSL);
147 if (!$this->manifest) {
148 $this->diagnostic[] =
'Cannot transform into normalized manifest';
152 $path =
new DOMXpath($this->manifest);
153 $path->registerNamespace(
"scorm",
"http://www.openpalms.net/scorm/scorm13");
154 $items =
$path->query(
"//scorm:item");
155 if ($items->length == 1) {
156 $n = $items->item(0);
157 $resource =
$path->query(
"//scorm:resource");
158 foreach ($resource as
$res) {
159 if ($n !== null && $res->getAttribute(
'id') == $n->getAttribute(
"resourceId")) {
160 $res->setAttribute(
'scormType',
'sco');
166 if (file_exists($this->packageFolder .
'/' .
'index.xml')) {
167 $doc = simplexml_load_file($this->packageFolder .
'/' .
'index.xml');
168 $l = $doc->xpath(
"/ContentObject/MetaData");
171 $mdxml->startParsing();
172 $mdo = $mdxml->getMDObject();
180 $title = $importer->getTitle();
181 $description = $importer->getDescription();
182 if ($description !=
"") {
188 $x = simplexml_load_string($this->manifest->saveXML());
189 $x[
'persistPreviousAttempts'] = $this->packageData[
'persistprevattempts'];
192 $x[
'defaultLessonMode'] = $this->packageData[
'default_lesson_mode'];
193 $x[
'credit'] = $this->packageData[
'credit'];
194 $x[
'autoReview'] = $this->packageData[
'auto_review'];
198 foreach ($x->resource as $xe) {
199 $r[strval($xe[
'id'])] = $xe;
203 foreach ($x->xpath(
'//*[local-name()="item"]') as $xe) {
205 if (
$b = (
$r[strval($xe[
'resourceId'])] ??
false)) {
206 $xe[
'href'] = strval(
$b[
'base']) . strval(
$b[
'href']);
207 unset($xe[
'resourceId']);
208 if (strval(
$b[
'scormType']) ===
'sco') {
216 $this->
jsonNode($x->organization, $j[
'item']);
217 foreach ($x->sequencing as $s) {
218 $this->
jsonNode($s, $j[
'sequencing'][]);
221 $j[
'item'][
'base'] = strval($x[
'base']);
223 $j[
'base'] = $packageFolder .
'/';
224 $j[
'foreignId'] = floatval($x[
'foreignId']);
225 $j[
'id'] = strval($x[
'id']);
227 for($i = 0; $i < count($j[
'item'][
'item']); $i++) {
233 $adl_tree = $act->buildNodeSeqTree($this->imsmanifestFile);
237 'xmldata' => array(
'clob', $x->asXML()),
238 'jsdata' => array(
'clob', json_encode($j)),
239 'activitytree' => array(
'clob', json_encode($adl_tree[
'tree'])),
240 'global_to_system' => array(
'integer', (
int) $adl_tree[
'global']),
241 'shared_data_global_to_system' => array(
'integer', (
int) $adl_tree[
'dataglobal'])
244 'obj_id' => array(
'integer', (
int) $this->packageId)
253 return $j[
'item'][
'title'];
264 public function jsonNode(
object $node, ?array &$sink): void
266 foreach ($node->attributes() as $k => $v) {
271 } elseif ($v ===
"false") {
273 } elseif (is_numeric($v)) {
278 foreach ($node->children() as $name => $child) {
279 self::jsonNode($child, $sink[$name][]);
283 public function dbImport(
object $node, ?
int &$lft = 1, ?
int $depth = 1, ?
int $parent = 0): void
286 $ilDB = $DIC->database();
288 switch ($node->nodeType) {
289 case XML_DOCUMENT_NODE:
294 'SELECT * FROM cp_package WHERE obj_id = %s AND c_identifier = %s',
295 array(
'integer',
'text'),
296 array($this->packageId, $this->packageName)
299 $query =
'UPDATE cp_package ' 300 .
'SET persistprevattempts = %s, c_settings = %s ' 301 .
'WHERE obj_id = %s AND c_identifier= %s';
304 array(
'integer',
'text',
'integer',
'text'),
305 array(0, null, $this->packageId, $this->packageName)
308 $query =
'INSERT INTO cp_package (obj_id, c_identifier, persistprevattempts, c_settings) ' 309 .
'VALUES (%s, %s, %s, %s)';
312 array(
'integer',
'text',
'integer',
'text'),
313 array($this->packageId, $this->packageName, 0, null)
318 $this->
dbImport($node->documentElement);
321 case XML_ELEMENT_NODE:
322 if ($node->nodeName ===
'manifest') {
323 if ($node->getAttribute(
'uri') ==
"") {
325 $node->setAttribute(
'uri',
'md5:' . $this->packageHash);
329 $cp_node_id =
$ilDB->nextId(
'cp_node');
331 $query =
'INSERT INTO cp_node (cp_node_id, slm_id, nodename) ' 332 .
'VALUES (%s, %s, %s)';
335 array(
'integer',
'integer',
'text'),
336 array($cp_node_id, $this->packageId, $node->nodeName)
339 $query =
'INSERT INTO cp_tree (child, depth, lft, obj_id, parent, rgt) ' 340 .
'VALUES (%s, %s, %s, %s, %s, %s)';
343 array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),
344 array($cp_node_id, $depth, $lft++, $this->packageId, $parent, 0)
349 $names = array(
'cp_node_id');
350 $values = array($cp_node_id);
351 $types = array(
'integer');
353 foreach ($node->attributes as $attr) {
354 switch (strtolower($attr->name)) {
355 case 'completionsetbycontent': $names[] =
'completionbycontent';
357 case 'objectivesetbycontent': $names[] =
'objectivebycontent';
359 case 'type': $names[] =
'c_type';
361 case 'mode': $names[] =
'c_mode';
363 case 'language': $names[] =
'c_language';
365 case 'condition': $names[] =
'c_condition';
367 case 'operator': $names[] =
'c_operator';
369 case 'readnormalizedmeasure': $names[] =
'readnormalmeasure';
371 case 'writenormalizedmeasure': $names[] =
'writenormalmeasure';
373 case 'minnormalizedmeasure': $names[] =
'minnormalmeasure';
375 case 'primary': $names[] =
'c_primary';
378 case 'persistpreviousattempts': $names[] =
'persistprevattempts';
380 case 'identifier': $names[] =
'c_identifier';
382 case 'settings': $names[] =
'c_settings';
384 case 'activityabsolutedurationlimit': $names[] =
'activityabsdurlimit';
386 case 'activityexperienceddurationlimit': $names[] =
'activityexpdurlimit';
388 case 'attemptabsolutedurationlimit': $names[] =
'attemptabsdurlimit';
390 case 'measuresatisfactionifactive': $names[] =
'measuresatisfactive';
392 case 'objectivemeasureweight': $names[] =
'objectivemeasweight';
394 case 'requiredforcompleted': $names[] =
'requiredcompleted';
396 case 'requiredforincomplete': $names[] =
'requiredincomplete';
398 case 'requiredfornotsatisfied': $names[] =
'requirednotsatisfied';
400 case 'rollupobjectivesatisfied': $names[] =
'rollupobjectivesatis';
402 case 'rollupprogresscompletion': $names[] =
'rollupprogcompletion';
404 case 'usecurrentattemptobjectiveinfo': $names[] =
'usecurattemptobjinfo';
406 case 'usecurrentattemptprogressinfo': $names[] =
'usecurattemptproginfo';
408 default: $names[] = strtolower($attr->name);
413 $names[count($names) - 1],
414 array(
'flow',
'completionbycontent',
415 'objectivebycontent',
'rollupobjectivesatis',
417 'choiceexit',
'satisfiedbymeasure',
418 'c_primary',
'constrainchoice',
419 'forwardonly',
'global_to_system',
420 'writenormalmeasure',
'writesatisfiedstatus',
421 'readnormalmeasure',
'readsatisfiedstatus',
422 'preventactivation',
'measuresatisfactive',
423 'reorderchildren',
'usecurattemptproginfo',
424 'usecurattemptobjinfo',
'rollupprogcompletion',
425 'read_shared_data',
'write_shared_data',
426 'shared_data_global_to_system',
'completedbymeasure')
428 if ($attr->value ===
'true') {
430 } elseif ($attr->value ===
'false') {
433 $values[] = (
int) $attr->value;
436 $values[] = $attr->value;
440 $names[count($names) - 1],
441 array(
'objectivesglobtosys',
'attemptlimit',
442 'flow',
'completionbycontent',
443 'objectivebycontent',
'rollupobjectivesatis',
445 'choiceexit',
'satisfiedbymeasure',
446 'c_primary',
'constrainchoice',
447 'forwardonly',
'global_to_system',
448 'writenormalmeasure',
'writesatisfiedstatus',
449 'readnormalmeasure',
'readsatisfiedstatus',
450 'preventactivation',
'measuresatisfactive',
451 'reorderchildren',
'usecurattemptproginfo',
452 'usecurattemptobjinfo',
'rollupprogcompletion',
453 'read_shared_data',
'write_shared_data',
454 'shared_data_global_to_system')
456 $types[] =
'integer';
458 $names[count($names) - 1],
459 array(
'jsdata',
'xmldata',
'activitytree',
'data')
462 } elseif ($names[count($names) - 1] ===
'objectivemeasweight') {
469 if ($node->nodeName ===
'datamap') {
472 $types[] =
'integer';
474 $names[] =
'sco_node_id';
476 $types[] =
'integer';
480 $insert_data = array();
481 foreach ($names as
$key => $db_field) {
482 $insert_data[$db_field] = array($types[
$key], trim((
string) $values[$key]));
484 $ilDB->insert(
'cp_' . strtolower($node->nodeName), $insert_data);
486 $node->setAttribute(
'foreignId', (
string) $cp_node_id);
487 $this->idmap[$node->getAttribute(
'id')] = $cp_node_id;
490 foreach ($node->childNodes as $child) {
491 $this->
dbImport($child, $lft, $depth + 1, $cp_node_id);
495 $query =
'UPDATE cp_tree SET rgt = %s WHERE child = %s';
498 array(
'integer',
'integer'),
499 array($lft++, $cp_node_id)
516 $ilDB = $DIC->database();
523 'SELECT cp_node.cp_node_id FROM cp_node WHERE cp_node.slm_id = %s',
525 array($this->packageId)
528 $cp_nodes[] =
$data[
'cp_node_id'];
532 foreach (self::$elements[
'cp'] as $t) {
535 $in =
$ilDB->in(strtolower($t) .
'.cp_node_id', $cp_nodes,
false,
'integer');
536 $ilDB->manipulate(
'DELETE FROM ' . strtolower($t) .
' WHERE ' . $in);
541 'DELETE FROM cp_tree WHERE cp_tree.obj_id = %s',
543 array($this->packageId)
547 'DELETE FROM cp_node WHERE cp_node.slm_id = %s',
549 array($this->packageId)
554 'DELETE FROM cp_package WHERE cp_package.obj_id = %s',
556 array($this->packageId)
574 if (!@$xsl->load($xslfile)) {
575 die(
'ERROR: load StyleSheet ' . $xslfile);
577 $prc =
new XSLTProcessor();
578 $prc->registerPHPFunctions();
579 $r = @$prc->importStyleSheet($xsl);
580 if (
false === @$prc->importStyleSheet($xsl)) {
581 die(
'ERROR: importStyleSheet ' . $xslfile);
584 file_put_contents($outputpath, $prc->transformToXML($inputdoc));
586 return $prc->transformToDoc($inputdoc);
bool DOMDocument $manifest
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getLogger(string $a_component_id)
Get component logger.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
__construct(?int $packageId=null)
dbImport(object $node, ?int &$lft=1, ?int $depth=1, ?int $parent=0)
il_import(string $packageFolder, int $packageId, bool $reimport=false)
Imports an extracted SCORM 2004 module from ilias-data dir into database.
static _refreshStatus(int $a_obj_id, ?array $a_users=null)
jsonNode(object $node, ?array &$sink)
Helper for UploadAndImport Recursively copies values from XML into PHP array for export as json Eleme...
transform(\DOMDocument $inputdoc, string $xslfile, ?string $outputpath=null)
static removeCMIDataForUser(int $user_id)
static removeCMIDataForPackage(int $packageId)
static _lookupType(int $id, bool $reference=false)
static _removeTrackingDataForUser(int $user_id)
static _writeDescription(int $obj_id, string $desc)
write description to db (static)