setManifest($manifest); } public function getManifest() { return $this->manifest; } public function setManifest(DOMDocument $manifest = null) { $this->manifest = $manifest; } public function hasManifest() { return $this->getManifest() !== null; } public function export($options = []) { if (!$this->containsItem()) { $report = parent::export($options); if ($report->getType() !== \common_report_Report::TYPE_ERROR || !$report->containsError()) { try { $exportResult = []; if (is_array($report->getData())) { $exportResult = $report->getData(); } $this->exportManifest($options, $exportResult); } catch (ExportException $e) { $report->setType(\common_report_Report::TYPE_ERROR); $report->setMessage($e->getUserMessage()); } } return $report; } return \common_report_Report::createSuccess(); } /** * Whenever the item is already in the manifest * @return boolean */ protected function containsItem() { $found = false; if ($this->hasManifest()) { foreach ($this->getManifest()->getElementsByTagName('resource') as $resourceNode) { /** @var \DOMElement $resourceNode */ if ($resourceNode->getAttribute('identifier') == $this->buildIdentifier()) { $found = true; break; } } } return $found; } public function buildBasePath() { return tao_helpers_Uri::getUniqueId($this->getItem()->getUri()); } public function buildIdentifier() { return tao_helpers_Uri::getUniqueId($this->getItem()->getUri()); } /** * Build, merge and export the IMS Manifest into the target ZIP archive. * * @throws */ public function exportManifest($options = [], $exportResult = []) { $base = $this->buildBasePath(); $zipArchive = $this->getZip(); $qtiFile = ''; $qtiResources = []; $sharedAssets = isset($exportResult['portableAssets']) ? $exportResult['portableAssets'] : []; for ($i = 0; $i < $zipArchive->numFiles; $i++) { $fileName = $zipArchive->getNameIndex($i); //shared assets are authorized to be added at the root of the package if (preg_match("@^" . preg_quote($base) . "@", $fileName) || in_array($fileName, $sharedAssets)) { if (basename($fileName) == 'qti.xml') { $qtiFile = $fileName; } else { if (!empty($fileName)) { $qtiResources[] = $fileName; } } } } $qtiItemService = Service::singleton(); //@todo add support of multi language packages $rdfItem = $this->getItem(); $qtiItem = $qtiItemService->getDataItemByRdfItem($rdfItem); if (!is_null($qtiItem)) { // -- Prepare data transfer to the imsmanifest.tpl template. $qtiItemData = []; // alter identifier for export to avoid any "clash". $qtiItemData['identifier'] = $this->buildIdentifier(); $qtiItemData['filePath'] = $qtiFile; $qtiItemData['medias'] = $qtiResources; $qtiItemData['adaptive'] = ($qtiItem->getAttributeValue('adaptive') === 'adaptive') ? true : false; $qtiItemData['timeDependent'] = ($qtiItem->getAttributeValue('timeDependent') === 'timeDependent') ? true : false; $qtiItemData['toolName'] = $qtiItem->getAttributeValue('toolVendor'); $qtiItemData['toolVersion'] = $qtiItem->getAttributeValue('toolVersion'); $qtiItemData['interactions'] = []; foreach ($qtiItem->getInteractions() as $interaction) { $interactionData = []; $interactionData['type'] = $interaction->getQtiTag(); $qtiItemData['interactions'][] = $interactionData; } // -- Build a brand new IMS Manifest. $newManifest = $this->renderManifest($options, $qtiItemData); if ($this->hasManifest()) { // Merge old manifest and new one. $dom1 = $this->getManifest(); $dom2 = $newManifest; $resourceNodes = $dom2->getElementsByTagName('resource'); $resourcesNodes = $dom1->getElementsByTagName('resources'); foreach ($resourcesNodes as $resourcesNode) { foreach ($resourceNodes as $resourceNode) { $newResourceNode = $dom1->importNode($resourceNode, true); $resourcesNode->appendChild($newResourceNode); } } // rendered manifest is now useless. unset($dom2); } else { // Brand new manifest. $this->setManifest($newManifest); } $manifest = $this->getManifest(); $this->getMetadataExporter()->export($this->getItem(), $manifest); $this->setManifest($manifest); // -- Overwrite manifest in the current ZIP archive. $zipArchive->addFromString('imsmanifest.xml', $this->getManifest()->saveXML()); } else { //the item has no item content, there are 2 possibilities: $itemLabel = $this->getItem()->getLabel(); if (empty($itemLabel)) { //it has no label at all: the item does not exist anymore throw new ExportException($this->getItem()->getUri(), 'item not found'); } else { //there is one, so the item does exist but might not have any content throw new ExportException($itemLabel, 'no item content'); } } } protected function renderManifest(array $options, array $qtiItemData) { $asApip = isset($options['apip']) && $options['apip'] === true; $dir = \common_ext_ExtensionsManager::singleton()->getExtensionById('taoQtiItem')->getDir(); $tpl = ($asApip === false) ? $dir . 'model/qti/templates/imsmanifest.tpl.php' : $dir . 'model/qti/templates/imsmanifestApip.tpl.php'; $templateRenderer = new taoItems_models_classes_TemplateRenderer($tpl, [ 'qtiItems' => [$qtiItemData], 'manifestIdentifier' => 'MANIFEST-' . tao_helpers_Display::textCleaner(uniqid('tao', true), '-') ]); $renderedManifest = $templateRenderer->render(); $newManifest = new DOMDocument('1.0', TAO_DEFAULT_ENCODING); $newManifest->loadXML($renderedManifest); return $newManifest; } protected function itemContentPostProcessing($content) { return $content; } }