getRequestMetadata($args)) { $this->createItem( $metadata, [ 'scormPackage' => $args['object'], ] ); } } public function handle_file_update($args) { if (isset($args['initialFileId']) && $metadata = $this->getRequestMetadata($args)) { $relationlib = TikiLib::lib('relation'); $items = $relationlib->get_relations_to('file', $args['initialFileId'], 'tiki.file.attach'); $transaction = TikiDb::get()->begin(); foreach ($items as $item) { if ($item['type'] == 'trackeritem') { $this->updateItem( $item['itemId'], $metadata, [ 'scormPackage' => $args['object'], ] ); } } $transaction->commit(); } } private function getRequestMetadata($args) { $metadata = null; $file = \Tiki\FileGallery\File::id($args['object']); if ( $this->isZipFile($args) && $zip = $this->getZipFile($file) ) { if ($manifest = $this->getScormManifest($zip)) { $metadata = $this->getMetadata($manifest); } $zip->close(); } return $metadata; } private function isZipFile($args) { if (! isset($args['filetype'])) { return false; } return in_array($args['filetype'], ['application/zip', 'application/x-zip', 'application/x-zip-compressed']); } private function getZipFile($file) { global $prefs; if (! class_exists('ZipArchive')) { return null; } $zip = new ZipArchive(); $filepath = $file->getWrapper()->getReadableFile(); if ($zip->open($filepath) === true) { return $zip; } } private function getScormManifest($zip) { return $zip->getFromName('imsmanifest.xml'); } private function getMetadata($manifest) { $dom = new DOMDocument(); $dom->loadXML($manifest); $metadata = []; foreach ($dom->getElementsByTagName('general')->item(0)->childNodes as $node) { if ($node instanceof DOMElement) { $metadata[$this->getKey($node)][] = $this->getData($node); } } return $metadata; } private function getKey($node) { $raw = $node->tagName; return substr($raw, strpos($raw, ':') + 1); } private function getData($node) { $data = []; foreach ($node->getElementsByTagName('langstring') as $text) { $data[$text->getAttribute('xml:lang')] = trim($text->textContent); } return $data; } private function createItem($metadata, $additional) { $definition = $this->getScormTracker(); $fields = $this->buildFields($definition, $metadata, $additional); $utilities = new Services_Tracker_Utilities(); $utilities->insertItem( $definition, [ 'status' => 'o', 'fields' => $fields, ] ); } private function updateItem($itemId, $metadata, $additional) { $definition = $this->getScormTracker(); $fields = $this->buildFields($definition, $metadata, $additional); $utilities = new Services_Tracker_Utilities(); $utilities->updateItem( $definition, [ 'itemId' => (int) $itemId, 'status' => 'o', 'fields' => $fields, ] ); } private function getScormTracker() { global $prefs; return Tracker_Definition::get($prefs['scorm_tracker']); } private function buildFields($definition, $metadata, $additional) { $fields = []; foreach ($metadata as $key => $values) { if ($field = $definition->getFieldFromPermName($key)) { if ($field['type'] === 'F') { $fields[$key] = $this->getTagString($values); } elseif ($field['isMultilingual'] == 'y') { $fields[$key] = reset($values); } else { $fields[$key] = $this->getForDefaultLanguage($values); } } } return array_merge($fields, $additional); } private function getTagString($values) { $completeSet = []; foreach ($values as $val) { $completeSet = array_merge($completeSet, array_values($val)); } return implode(' ', array_unique($completeSet)); } private function getForDefaultLanguage($values) { global $prefs; $defaultLanguage = $prefs['language']; foreach ($values as $valueSet) { if (isset($valueSet[$defaultLanguage])) { return $valueSet[$defaultLanguage]; } } // If nothing matching the language found, return the first value return reset(reset($values)); } }