19 declare(strict_types=1);
28 public const DB_ENCODE_XSL =
'../components/ILIAS/Scorm2004/templates/xsl/op/op-scorm13.xsl';
29 public const CONVERT_XSL =
'../components/ILIAS/Scorm2004/templates/xsl/op/scorm12To2004.xsl';
30 public const DB_DECODE_XSL =
'../components/ILIAS/Scorm2004/templates/xsl/op/op-scorm13-revert.xsl';
31 public const VALIDATE_XSD =
'../vendor/ilias/Scorm2004/xsd/op/op-scorm13.xsd';
33 public const WRAPPER_HTML =
'../components/ILIAS/Scorm2004/scripts/converter/GenericRunTimeWrapper1.0_aadlc/GenericRunTimeWrapper.htm';
34 public const WRAPPER_JS =
'../components/ILIAS/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');
167 $x = simplexml_load_string($this->manifest->saveXML());
168 $x[
'persistPreviousAttempts'] = $this->packageData[
'persistprevattempts'];
171 $x[
'defaultLessonMode'] = $this->packageData[
'default_lesson_mode'];
172 $x[
'credit'] = $this->packageData[
'credit'];
173 $x[
'autoReview'] = $this->packageData[
'auto_review'];
177 foreach ($x->resource as $xe) {
178 $r[strval($xe[
'id'])] = $xe;
182 foreach ($x->xpath(
'//*[local-name()="item"]') as $xe) {
184 if (
$b = (
$r[strval($xe[
'resourceId'])] ??
false)) {
185 $xe[
'href'] = strval(
$b[
'base']) . strval(
$b[
'href']);
186 unset($xe[
'resourceId']);
187 if (strval(
$b[
'scormType']) ===
'sco') {
195 $this->
jsonNode($x->organization, $j[
'item']);
196 foreach ($x->sequencing as $s) {
197 $this->
jsonNode($s, $j[
'sequencing'][]);
200 $j[
'item'][
'base'] = strval($x[
'base']);
202 $j[
'base'] = $packageFolder .
'/';
203 $j[
'foreignId'] = floatval($x[
'foreignId']);
204 $j[
'id'] = strval($x[
'id']);
206 for($i = 0; $i < count($j[
'item'][
'item']); $i++) {
212 $adl_tree = $act->buildNodeSeqTree($this->imsmanifestFile);
216 'xmldata' => array(
'clob', $x->asXML()),
217 'jsdata' => array(
'clob', json_encode($j)),
218 'activitytree' => array(
'clob', json_encode($adl_tree[
'tree'])),
219 'global_to_system' => array(
'integer', (
int) $adl_tree[
'global']),
220 'shared_data_global_to_system' => array(
'integer', (
int) $adl_tree[
'dataglobal'])
223 'obj_id' => array(
'integer', (
int) $this->packageId)
232 return $j[
'item'][
'title'];
243 public function jsonNode(
object $node, ?array &$sink): void
245 foreach ($node->attributes() as $k => $v) {
250 } elseif ($v ===
"false") {
252 } elseif (is_numeric($v)) {
257 foreach ($node->children() as $name => $child) {
258 self::jsonNode($child, $sink[$name][]);
262 public function dbImport(
object $node, ?
int &$lft = 1, ?
int $depth = 1, ?
int $parent = 0): void
265 $ilDB = $DIC->database();
267 switch ($node->nodeType) {
268 case XML_DOCUMENT_NODE:
273 'SELECT * FROM cp_package WHERE obj_id = %s AND c_identifier = %s',
274 array(
'integer',
'text'),
275 array($this->packageId, $this->packageName)
278 $query =
'UPDATE cp_package ' 279 .
'SET persistprevattempts = %s, c_settings = %s ' 280 .
'WHERE obj_id = %s AND c_identifier= %s';
283 array(
'integer',
'text',
'integer',
'text'),
284 array(0,
null, $this->packageId, $this->packageName)
287 $query =
'INSERT INTO cp_package (obj_id, c_identifier, persistprevattempts, c_settings) ' 288 .
'VALUES (%s, %s, %s, %s)';
291 array(
'integer',
'text',
'integer',
'text'),
292 array($this->packageId, $this->packageName, 0,
null)
297 $this->
dbImport($node->documentElement);
300 case XML_ELEMENT_NODE:
301 if ($node->nodeName ===
'manifest') {
302 if ($node->getAttribute(
'uri') ==
"") {
304 $node->setAttribute(
'uri',
'md5:' . $this->packageHash);
308 $cp_node_id =
$ilDB->nextId(
'cp_node');
310 $query =
'INSERT INTO cp_node (cp_node_id, slm_id, nodename) ' 311 .
'VALUES (%s, %s, %s)';
314 array(
'integer',
'integer',
'text'),
315 array($cp_node_id, $this->packageId, $node->nodeName)
318 $query =
'INSERT INTO cp_tree (child, depth, lft, obj_id, parent, rgt) ' 319 .
'VALUES (%s, %s, %s, %s, %s, %s)';
322 array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),
323 array($cp_node_id, $depth, $lft++, $this->packageId, $parent, 0)
328 $names = array(
'cp_node_id');
329 $values = array($cp_node_id);
330 $types = array(
'integer');
332 foreach ($node->attributes as $attr) {
333 switch (strtolower($attr->name)) {
334 case 'completionsetbycontent': $names[] =
'completionbycontent';
336 case 'objectivesetbycontent': $names[] =
'objectivebycontent';
338 case 'type': $names[] =
'c_type';
340 case 'mode': $names[] =
'c_mode';
342 case 'language': $names[] =
'c_language';
346 case 'operator': $names[] =
'c_operator';
349 case 'readnormalizedmeasure': $names[] =
'readnormalmeasure';
351 case 'writenormalizedmeasure': $names[] =
'writenormalmeasure';
353 case 'minnormalizedmeasure': $names[] =
'minnormalmeasure';
355 case 'primary': $names[] =
'c_primary';
358 case 'persistpreviousattempts': $names[] =
'persistprevattempts';
360 case 'identifier': $names[] =
'c_identifier';
362 case 'settings': $names[] =
'c_settings';
364 case 'activityabsolutedurationlimit': $names[] =
'activityabsdurlimit';
366 case 'activityexperienceddurationlimit': $names[] =
'activityexpdurlimit';
368 case 'attemptabsolutedurationlimit': $names[] =
'attemptabsdurlimit';
370 case 'measuresatisfactionifactive': $names[] =
'measuresatisfactive';
372 case 'objectivemeasureweight': $names[] =
'objectivemeasweight';
374 case 'requiredforcompleted': $names[] =
'requiredcompleted';
376 case 'requiredforincomplete': $names[] =
'requiredincomplete';
378 case 'requiredfornotsatisfied': $names[] =
'requirednotsatisfied';
380 case 'rollupobjectivesatisfied': $names[] =
'rollupobjectivesatis';
382 case 'rollupprogresscompletion': $names[] =
'rollupprogcompletion';
384 case 'usecurrentattemptobjectiveinfo': $names[] =
'usecurattemptobjinfo';
386 case 'usecurrentattemptprogressinfo': $names[] =
'usecurattemptproginfo';
388 default: $names[] = strtolower($attr->name);
393 $names[count($names) - 1],
394 array(
'flow',
'completionbycontent',
395 'objectivebycontent',
'rollupobjectivesatis',
397 'choiceexit',
'satisfiedbymeasure',
398 'c_primary',
'constrainchoice',
399 'forwardonly',
'global_to_system',
400 'writenormalmeasure',
'writesatisfiedstatus',
401 'readnormalmeasure',
'readsatisfiedstatus',
402 'preventactivation',
'measuresatisfactive',
403 'reorderchildren',
'usecurattemptproginfo',
404 'usecurattemptobjinfo',
'rollupprogcompletion',
405 'read_shared_data',
'write_shared_data',
406 'shared_data_global_to_system',
'completedbymeasure')
408 if ($attr->value ===
'true') {
410 } elseif ($attr->value ===
'false') {
413 $values[] = (
int) $attr->value;
416 $values[] = $attr->value;
420 $names[count($names) - 1],
421 array(
'objectivesglobtosys',
'attemptlimit',
422 'flow',
'completionbycontent',
423 'objectivebycontent',
'rollupobjectivesatis',
425 'choiceexit',
'satisfiedbymeasure',
426 'c_primary',
'constrainchoice',
427 'forwardonly',
'global_to_system',
428 'writenormalmeasure',
'writesatisfiedstatus',
429 'readnormalmeasure',
'readsatisfiedstatus',
430 'preventactivation',
'measuresatisfactive',
431 'reorderchildren',
'usecurattemptproginfo',
432 'usecurattemptobjinfo',
'rollupprogcompletion',
433 'read_shared_data',
'write_shared_data',
434 'shared_data_global_to_system')
436 $types[] =
'integer';
438 $names[count($names) - 1],
439 array(
'jsdata',
'xmldata',
'activitytree',
'data')
442 } elseif ($names[count($names) - 1] ===
'objectivemeasweight') {
449 if ($node->nodeName ===
'datamap') {
452 $types[] =
'integer';
454 $names[] =
'sco_node_id';
456 $types[] =
'integer';
460 $insert_data = array();
461 foreach ($names as $key => $db_field) {
462 $insert_data[$db_field] = array($types[$key], trim((
string) $values[$key]));
464 $ilDB->insert(
'cp_' . strtolower($node->nodeName), $insert_data);
466 $node->setAttribute(
'foreignId', (
string) $cp_node_id);
467 $this->idmap[$node->getAttribute(
'id')] = $cp_node_id;
470 foreach ($node->childNodes as $child) {
471 $this->
dbImport($child, $lft, $depth + 1, $cp_node_id);
475 $query =
'UPDATE cp_tree SET rgt = %s WHERE child = %s';
478 array(
'integer',
'integer'),
479 array($lft++, $cp_node_id)
496 $ilDB = $DIC->database();
503 'SELECT cp_node.cp_node_id FROM cp_node WHERE cp_node.slm_id = %s',
505 array($this->packageId)
508 $cp_nodes[] =
$data[
'cp_node_id'];
512 foreach (self::$elements[
'cp'] as $t) {
515 $in =
$ilDB->in(strtolower($t) .
'.cp_node_id', $cp_nodes,
false,
'integer');
516 $ilDB->manipulate(
'DELETE FROM ' . strtolower($t) .
' WHERE ' . $in);
521 'DELETE FROM cp_tree WHERE cp_tree.obj_id = %s',
523 array($this->packageId)
527 'DELETE FROM cp_node WHERE cp_node.slm_id = %s',
529 array($this->packageId)
534 'DELETE FROM cp_package WHERE cp_package.obj_id = %s',
536 array($this->packageId)
554 if (!@$xsl->load($xslfile)) {
555 die(
'ERROR: load StyleSheet ' . $xslfile);
557 $prc =
new XSLTProcessor();
558 $prc->registerPHPFunctions();
559 $r = @$prc->importStyleSheet($xsl);
560 if (
false === @$prc->importStyleSheet($xsl)) {
561 die(
'ERROR: importStyleSheet ' . $xslfile);
564 file_put_contents($outputpath, $prc->transformToXML($inputdoc));
566 return $prc->transformToDoc($inputdoc);
bool DOMDocument $manifest
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="")
__construct(?int $packageId=null)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return 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 _removeTrackingDataForUser(int $user_id)