public static function importDelivery(core_kernel_classes_Class $deliveryClass, $archiveFile) { $folder = tao_helpers_File::createTempDir(); $zip = new ZipArchive(); if ($zip->open($archiveFile) === true) { if ($zip->extractTo($folder)) { $returnValue = $folder; } $zip->close(); } $manifestPath = $folder . self::MANIFEST_FILE; if (!file_exists($manifestPath)) { return common_report_Report::createFailure(__('Manifest not found in assembly')); } $manifest = json_decode(file_get_contents($manifestPath), true); $label = $manifest['label']; $serviceCall = tao_models_classes_service_ServiceCall::fromString(base64_decode($manifest['runtime'])); $dirs = $manifest['dir']; $resultServer = taoResultServer_models_classes_ResultServerAuthoringService::singleton()->getDefaultResultServer(); try { foreach ($dirs as $id => $relPath) { tao_models_classes_service_FileStorage::singleton()->import($id, $folder . $relPath); } $delivery = $deliveryClass->createInstanceWithProperties(array(RDFS_LABEL => $label, PROPERTY_COMPILEDDELIVERY_DIRECTORY => array_keys($dirs), PROPERTY_COMPILEDDELIVERY_TIME => time(), PROPERTY_COMPILEDDELIVERY_RUNTIME => $serviceCall->toOntology(), TAO_DELIVERY_RESULTSERVER_PROP => $resultServer)); $report = common_report_Report::createSuccess(__('Delivery "%s" successfully imported', $label), $delivery); } catch (Exception $e) { if (isset($delivery) && $delivery instanceof core_kernel_classes_Resource) { $delivery->delete(); } $report = common_report_Report::createFailure(__('Unkown error during impoort')); } return $report; }
public function importDelivery(core_kernel_classes_Class $deliveryClass, $archiveFile) { $folder = tao_helpers_File::createTempDir(); $zip = new ZipArchive(); if ($zip->open($archiveFile) !== true) { return common_report_Report::createFailure(__('Unable to export Archive')); } $zip->extractTo($folder); $zip->close(); $manifestPath = $folder . self::MANIFEST_FILE; if (!file_exists($manifestPath)) { return common_report_Report::createFailure(__('Manifest not found in assembly')); } $manifest = json_decode(file_get_contents($manifestPath), true); try { $this->importDeliveryFiles($deliveryClass, $manifest, $folder); $delivery = $this->importDeliveryResource($deliveryClass, $manifest); $report = common_report_Report::createSuccess(__('Delivery "%s" successfully imported', $delivery->getUri()), $delivery); } catch (Exception $e) { common_Logger::w($e->getMessage()); if (isset($delivery) && $delivery instanceof core_kernel_classes_Resource) { $delivery->delete(); } $report = common_report_Report::createFailure(__('Unkown error during impoort')); } return $report; }
/** * Create a formatted failure report and log a warning * * @param $userMessage * @param null $model * @return Report */ private function createFailure($userMessage, $model = null) { $typeIdentifier = is_null($model) ? 'unknown type' : $model->getTypeIdentifier(); $message = 'The portable element cannot be registered "' . $typeIdentifier . '", reason: ' . $userMessage; \common_Logger::w($message); return Report::createFailure($message); }
/** * (non-PHPdoc) * @see tao_models_classes_import_ImportHandler::import() */ public function import($class, $form) { $fileInfo = $form->getValue('source'); //import for CSV if (isset($fileInfo)) { set_time_limit(200); //the zip extraction is a long process that can exced the 30s timeout //get the services instances we will need $itemService = taoItems_models_classes_ItemsService::singleton(); $uploadedFile = $fileInfo['uploaded_file']; $uploadedFileBaseName = basename($uploadedFile); // uploaded file name contains an extra prefix that we have to remove. $uploadedFileBaseName = preg_replace('/^([0-9a-z])+_/', '', $uploadedFileBaseName, 1); $uploadedFileBaseName = preg_replace('/.zip|.ZIP$/', '', $uploadedFileBaseName); $validate = count($form->getValue('disable_validation')) == 0 ? true : false; try { $report = taoDelivery_models_classes_import_Assembler::importDelivery($class, $uploadedFile); } catch (common_Exception $e) { $report = common_report_Report::createFailure(__('An error occured during the import')); if ($e instanceof common_exception_UserReadableException) { $report->add($e); } } tao_helpers_File::remove($uploadedFile); } else { throw new common_exception_Error('No file provided as parameter \'source\' for OWI import'); } return $report; }
public function export($formValues, $destPath) { if (isset($formValues['filename']) && isset($formValues['uri'])) { try { /** @var TestExporter $exporterService */ $exporterService = $this->getServiceManager()->get(TestMetadataExporter::SERVICE_ID); $file = $exporterService->export($formValues['uri']); return $this->output($file); } catch (ExtractorException $e) { return \common_report_Report::createFailure('Selected object does not have any item to export.'); } } }
/** * (non-PHPdoc) * @see tao_models_classes_import_ImportHandler::import() */ public function import($class, $form) { $fileInfo = $form->getValue('source'); $file = $fileInfo['uploaded_file']; //validate the file to import $parser = new tao_models_classes_Parser($file, array('extension' => 'rdf')); $parser->validate(); if (!$parser->isValid()) { $report = common_report_Report::createFailure(__('Nothing imported')); $report->add($parser->getReport()); return $report; } else { return $this->flatImport($file, $class); } }
/** * After form submitting, export data & output file * * @param array $formValues * @param string $destPath * @return \common_report_Report|void * @throws \common_Exception * @throws \common_exception_BadRequest */ public function export($formValues, $destPath) { if (isset($formValues['filename']) && isset($formValues['classUri'])) { $classToExport = $this->getClassToExport($formValues['classUri']); if ($classToExport->exists()) { try { /** @var ItemExporter $exporterService */ $exporterService = $this->getServiceManager()->get(SimpleExporter::SERVICE_ID); $file = $exporterService->export($this->getInstances($classToExport), true); return $this->output($file); } catch (ExtractorException $e) { return \common_report_Report::createFailure('Selected object does not have any item to export.'); } } } return; }
protected function verifyParams($params) { $this->finalReport = new \common_report_Report(\common_report_Report::TYPE_SUCCESS); $class_uri = array_shift($params); $deliveryRootClass = DeliveryAssemblyService::singleton()->getRootClass(); if (is_null($class_uri)) { $deliveryClass = $deliveryRootClass; } else { $deliveryClass = new \core_kernel_classes_Class($class_uri); if (!$deliveryClass->isSubClassOf($deliveryRootClass)) { $msg = "Usage: php index.php '" . __CLASS__ . "' [CLASS_URI]" . PHP_EOL; $msg .= "CLASS_URI : a valid delivery class uri" . PHP_EOL . PHP_EOL; $msg .= "Uri : " . $class_uri . " is not a valid delivery class" . PHP_EOL; $this->finalReport->add(\common_report_Report::createFailure($msg)); } } $this->deliveryClass = $deliveryClass; }
/** * (non-PHPdoc) * @see tao_models_classes_import_ImportHandler::import() */ public function import($class, $form) { try { $fileInfo = $form->getValue('source'); if (isset($fileInfo['uploaded_file'])) { $uploadedFile = $fileInfo['uploaded_file']; // The zip extraction is a long process that can exceed the 30s timeout helpers_TimeOutHelper::setTimeOutLimit(helpers_TimeOutHelper::LONG); $report = taoQtiTest_models_classes_QtiTestService::singleton()->importMultipleTests($class, $uploadedFile); helpers_TimeOutHelper::reset(); tao_helpers_File::remove($uploadedFile); } else { throw new common_exception_Error('No source file for import'); } return $report; } catch (Exception $e) { return common_report_Report::createFailure($e->getMessage()); } }
public function testRenderNested() { $report = common_report_Report::createSuccess('Success!'); $report->add(common_report_Report::createSuccess('Another success!')); $report->add(common_report_Report::createFailure('Failure!')); $expected = '<div class="feedback-success feedback-nesting-0 hierarchical tao-scope">'; $expected .= '<span class="icon-success hierarchical-icon"></span>'; $expected .= 'Success!'; $expected .= '<div class="feedback-success feedback-nesting-1 leaf tao-scope">'; $expected .= '<span class="icon-success leaf-icon"></span>'; $expected .= 'Another success!'; $expected .= '</div>'; $expected .= '<div class="feedback-error feedback-nesting-1 leaf tao-scope">'; $expected .= '<span class="icon-error leaf-icon"></span>'; $expected .= 'Failure!'; $expected .= '</div>'; $expected .= '<p>'; $expected .= '<button id="import-continue" class="btn-info"><span class="icon-right"></span>Continue</button>'; $expected .= '</p>'; $expected .= '</div>'; $this->assertEquals($expected, tao_helpers_report_Rendering::render($report)); }
/** * Starts the import based on the form * * @param \core_kernel_classes_Class $class * @param \tao_helpers_form_Form $form * @return \common_report_Report */ public function import($class, $form) { //as upload may be called multiple times, we remove the session lock as soon as possible session_write_close(); try { $file = $form->getValue('source'); $resource = new core_kernel_classes_Class($form->getValue('classUri')); // unzip the file try { $directory = $this->extractArchive($file['uploaded_file']); } catch (\Exception $e) { return \common_report_Report::createFailure(__('Unable to extract the archive')); } // get list of directory in order to create classes $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($directory, \RecursiveDirectoryIterator::CURRENT_AS_FILEINFO | \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY); $service = MediaService::singleton(); $language = $form->getValue('lang'); $this->directoryMap = array(rtrim($directory, DIRECTORY_SEPARATOR) => $resource->getUri()); /** @var $file \SplFileInfo */ $report = \common_report_Report::createSuccess(__('Media imported successfully')); foreach ($iterator as $file) { if ($file->isFile()) { \common_Logger::i('File ' . $file->getPathname()); if (isset($this->directoryMap[$file->getPath()])) { $classUri = $this->directoryMap[$file->getPath()]; } else { $classUri = $this->createClass($file->getPath()); } $service->createMediaInstance($file->getRealPath(), $classUri, $language, $file->getFilename()); $report->add(\common_report_Report::createSuccess(__('Imported %s', substr($file->getRealPath(), strlen($directory))))); } } return $report; } catch (\Exception $e) { $report = \common_report_Report::createFailure($e->getMessage()); return $report; } }
/** * Validate files by checking: * - Model requirement * - Existing as file or alias * * @param PortableElementObject $object * @param string $source Temporary directory source * @param array $files Array of file relative path * @return bool * @throws PortableElementInvalidAssetException * @throws PortableElementInvalidModelException * @throws PortableElementParserException * @throws \common_exception_Error */ public function validateAssets(PortableElementObject $object, $source, array $files = []) { if (empty($files)) { $files = $this->getAssets($object, $files); } if (empty($files)) { return false; } $errorReport = \common_report_Report::createFailure('Portable element validation has failed.'); foreach ($files as $key => $file) { try { $this->validFile($source, $file); } catch (PortableElementInvalidAssetException $e) { $subReport = \common_report_Report::createFailure(__('Cannot locate the file "%s"', $file)); $errorReport->add($subReport); } } if ($errorReport->containsError()) { $exception = new PortableElementInvalidModelException(); $exception->setReport($errorReport); throw $exception; } return true; }
/** * Validate an xml file, convert file linked inside and store it into media manager * @param \core_kernel_classes_Resource $instance the instance to edit * @param string $lang language of the shared stimulus * @param string $xmlFile File to store * @return \common_report_Report */ protected function replaceSharedStimulus($instance, $lang, $xmlFile) { //if the class does not belong to media classes create a new one with its name (for items) $mediaClass = new core_kernel_classes_Class(MediaService::ROOT_CLASS_URI); if (!$instance->isInstanceOf($mediaClass)) { $report = \common_report_Report::createFailure('The instance ' . $instance->getUri() . ' is not a Media instance'); return $report; } SharedStimulusImporter::isValidSharedStimulus($xmlFile); $name = basename($xmlFile, '.xml'); $name .= '.xhtml'; $filepath = dirname($xmlFile) . '/' . $name; \tao_helpers_File::copy($xmlFile, $filepath); $service = MediaService::singleton(); if (!$service->editMediaInstance($filepath, $instance->getUri(), $lang)) { $report = \common_report_Report::createFailure(__('Fail to edit Shared Stimulus')); } else { $report = \common_report_Report::createSuccess(__('Shared Stimulus edited successfully')); } return $report; }
/** * Overriden export from QTI items. * * @see taoItems_models_classes_ItemExporter::export() * @param array $options An array of options. * @return \common_report_Report * @throws ExportException * @throws \common_Exception * @throws \common_exception_Error * @throws \core_kernel_persistence_Exception * @throws PortableElementInvalidAssetException */ public function export($options = array()) { $report = \common_report_Report::createSuccess(); $asApip = isset($options['apip']) && $options['apip'] === true; $lang = \common_session_SessionManager::getSession()->getDataLanguage(); $basePath = $this->buildBasePath(); if (is_null($this->getItemModel())) { throw new ExportException('', 'No Item Model found for item : ' . $this->getItem()->getUri()); } $dataFile = (string) $this->getItemModel()->getOnePropertyValue(new core_kernel_classes_Property(TAO_ITEM_MODEL_DATAFILE_PROPERTY)); $resolver = new ItemMediaResolver($this->getItem(), $lang); $replacementList = array(); $modelsAssets = $this->getPortableElementAssets($this->getItem(), $lang); $service = new PortableElementService(); $service->setServiceLocator(ServiceManager::getServiceManager()); $portableElementsToExport = $portableAssetsToExport = []; foreach ($modelsAssets as $key => $portableElements) { /** @var $element */ foreach ($portableElements as $element) { if (!$element instanceof Element) { continue; } try { $object = $service->retrieve($key, $element->getTypeIdentifier()); } catch (PortableElementException $e) { $message = __('Fail to export item') . ' (' . $this->getItem()->getLabel() . '): ' . $e->getMessage(); return \common_report_Report::createFailure($message); } $portableElementsToExport[$element->getTypeIdentifier()] = $object; $files = $object->getModel()->getValidator()->getAssets($object, 'runtime'); $baseUrl = $basePath . DIRECTORY_SEPARATOR . $object->getTypeIdentifier(); $portableAssetsToExport[$object->getTypeIdentifier()] = []; foreach ($files as $url) { try { // Skip shared libraries into portable element if (strpos($url, './') !== 0) { \common_Logger::i('Shared libraries skipped : ' . $url); $portableAssetsToExport[$object->getTypeIdentifier()][$url] = $url; continue; } $stream = $service->getFileStream($object, $url); $replacement = $this->copyAssetFile($stream, $baseUrl, $url, $replacementList); $portableAssetToExport = preg_replace('/^(.\\/)(.*)/', $object->getTypeIdentifier() . "/\$2", $replacement); $portableAssetsToExport[$object->getTypeIdentifier()][$url] = $portableAssetToExport; \common_Logger::i('File copied: "' . $url . '" for portable element ' . $object->getTypeIdentifier()); } catch (\tao_models_classes_FileNotFoundException $e) { \common_Logger::i($e->getMessage()); $report->setMessage('Missing resource for ' . $url); $report->setType(\common_report_Report::TYPE_ERROR); } } } } $assets = $this->getAssets($this->getItem(), $lang); foreach ($assets as $assetUrl) { try { $mediaAsset = $resolver->resolve($assetUrl); $mediaSource = $mediaAsset->getMediaSource(); if (!$mediaSource instanceof HttpSource) { $link = $mediaAsset->getMediaIdentifier(); $stream = $mediaSource->getFileStream($link); $baseName = $mediaSource instanceof LocalItemSource ? $link : 'assets/' . $mediaSource->getBaseName($link); $replacement = $this->copyAssetFile($stream, $basePath, $baseName, $replacementList); $replacementList[$assetUrl] = $replacement; } } catch (\tao_models_classes_FileNotFoundException $e) { $replacementList[$assetUrl] = ''; $report->setMessage('Missing resource for ' . $assetUrl); $report->setType(\common_report_Report::TYPE_ERROR); } } $xml = Service::singleton()->getXmlByRdfItem($this->getItem()); $dom = new DOMDocument('1.0', 'UTF-8'); $dom->preserveWhiteSpace = false; $dom->formatOutput = true; if ($dom->loadXML($xml) === true) { $xpath = new \DOMXPath($dom); $attributeNodes = $xpath->query('//@*'); $portableEntryNodes = $xpath->query("//*[local-name()='entry']") ?: []; unset($xpath); foreach ($attributeNodes as $node) { if (isset($replacementList[$node->value])) { $node->value = $replacementList[$node->value]; } } foreach ($portableEntryNodes as $node) { $node->nodeValue = strtr(htmlentities($node->nodeValue, ENT_XML1), $replacementList); } $this->exportPortableAssets($dom, 'portableCustomInteraction', 'customInteractionTypeIdentifier', 'pci', $portableElementsToExport, $portableAssetsToExport); $this->exportPortableAssets($dom, 'portableInfoControl', 'infoControlTypeIdentifier', 'pic', $portableElementsToExport, $portableAssetsToExport); } else { throw new ExportException($this->getItem()->getLabel(), 'Unable to load XML'); } $dom->preserveWhiteSpace = true; $dom->formatOutput = true; if (($content = $dom->saveXML()) === false) { throw new ExportException($this->getItem()->getLabel(), 'Unable to save XML'); } // Possibility to delegate (if necessary) some item content post-processing to sub-classes. $content = $this->itemContentPostProcessing($content); // add xml file $this->getZip()->addFromString($basePath . '/' . $dataFile, $content); if (!$report->getMessage()) { $report->setMessage(__('Item ' . $this->getItem()->getLabel() . ' exported.')); } return $report; }
public function sharedStimulusImportProvider() { $sampleDir = dirname(__DIR__) . '/sample/sharedStimulus/'; return array(array($sampleDir . 'UnknowFile.zip', \common_report_Report::createFailure(__('Unable to open archive ' . $sampleDir . 'UnknowFile.zip')), false), array($sampleDir . 'missingXmlArchive.zip', \common_report_Report::createFailure('XML not found'), false), array($sampleDir . 'stimulusPackage.zip', \common_report_Report::createSuccess(__('Shared Stimulus %s successfully')), true)); }
/** * @param $folder * @param \taoQtiTest_models_classes_QtiResource $qtiItemResource * @param $itemClass * @param bool|false $extractApip * @param array $dependencies * @return common_report_Report * @throws common_exception_Error */ public function importQtiItem($folder, Resource $qtiItemResource, $itemClass, $extractApip = false, $dependencies = array()) { try { //load the information about resources in the manifest $itemService = taoItems_models_classes_ItemsService::singleton(); $qtiService = Service::singleton(); // The metadata import feature needs a DOM representation of the manifest. $domManifest = new DOMDocument('1.0', 'UTF-8'); $domManifest->load($folder . 'imsmanifest.xml'); $metadataMapping = $qtiService->getMetadataRegistry()->getMapping(); $metadataInjectors = array(); $metadataGuardians = array(); $metadataClassLookups = array(); $metadataValues = array(); foreach ($metadataMapping['injectors'] as $injector) { $metadataInjectors[] = new $injector(); } foreach ($metadataMapping['guardians'] as $guardian) { $metadataGuardians[] = new $guardian(); } foreach ($metadataMapping['classLookups'] as $classLookup) { $metadataClassLookups[] = new $classLookup(); } foreach ($metadataMapping['extractors'] as $extractor) { $metadataExtractor = new $extractor(); $metadataValues = array_merge($metadataValues, $metadataExtractor->extract($domManifest)); } $sources = MediaService::singleton()->getWritableSources(); $sharedStorage = array_shift($sources); $sharedFiles = array(); try { $resourceIdentifier = $qtiItemResource->getIdentifier(); // Use the guardians to check whether or not the item has to be imported. foreach ($metadataGuardians as $guardian) { if (isset($metadataValues[$resourceIdentifier]) === true) { if (($guard = $guardian->guard($metadataValues[$resourceIdentifier])) !== false) { $msg = __('The IMS QTI Item referenced as "%s" in the IMS Manifest file was already stored in the Item Bank.', $qtiItemResource->getIdentifier()); $report = common_report_Report::createInfo($msg, $guard); // Simply do not import again. return $report; } } } $targetClass = false; // Use the classLookups to determine where the item has to go. foreach ($metadataClassLookups as $classLookup) { if (isset($metadataValues[$resourceIdentifier]) === true) { if (($targetClass = $classLookup->lookup($metadataValues[$resourceIdentifier])) !== false) { break; } } } $qtiFile = $folder . $qtiItemResource->getFile(); $qtiModel = $this->createQtiItemModel($qtiFile); $rdfItem = $this->createRdfItem($targetClass !== false ? $targetClass : $itemClass, $qtiModel); $name = $rdfItem->getLabel(); $itemContent = $itemService->getItemContent($rdfItem); $xincluded = array(); foreach ($qtiModel->getBody()->getComposingElements('oat\\taoQtiItem\\model\\qti\\Xinclude') as $xincludeEle) { $xincluded[] = $xincludeEle->attr('href'); } $local = new LocalItemSource(array('item' => $rdfItem)); foreach ($qtiItemResource->getAuxiliaryFiles() as $auxResource) { // file on FS $auxFile = $folder . str_replace('/', DIRECTORY_SEPARATOR, $auxResource); // rel path in item $auxPath = str_replace(DIRECTORY_SEPARATOR, '/', helpers_File::getRelPath($qtiFile, $auxFile)); if (!empty($sharedStorage) && in_array($auxPath, $xincluded)) { $md5 = md5_file($auxFile); if (isset($sharedFiles[$md5])) { $info = $sharedFiles[$md5]; \common_Logger::i('Auxiliary file \'' . $auxPath . '\' linked to shared storage.'); } else { // TODO cleanup sharedstimulus import/export // move to taoQti item or library // validate the shared stimulus SharedStimulusImporter::isValidSharedStimulus($auxFile); // embed assets in the shared stimulus $newXmlFile = SharedStimulusPackageImporter::embedAssets($auxFile); $info = $sharedStorage->add($newXmlFile, basename($auxFile), $name); if (method_exists($sharedStorage, 'forceMimeType')) { // add() does not return link, so we need to parse it $resolver = new ItemMediaResolver($rdfItem, ''); $asset = $resolver->resolve($info['uri']); $sharedStorage->forceMimeType($asset->getMediaIdentifier(), 'application/qti+xml'); } $sharedFiles[$md5] = $info; \common_Logger::i('Auxiliary file \'' . $auxPath . '\' added to shared storage.'); } } else { // store locally, in a safe directory $safePath = ''; if (dirname($auxPath) !== '.') { $safePath = str_replace('../', '', dirname($auxPath)) . '/'; } $info = $local->add($auxFile, basename($auxFile), $safePath); \common_Logger::i('Auxiliary file \'' . $auxPath . '\' copied.'); } // replace uri if changed if ($auxPath != ltrim($info['uri'], '/')) { $itemContent = str_replace($auxPath, $info['uri'], $itemContent); } } foreach ($qtiItemResource->getDependencies() as $dependency) { // file on FS if (isset($dependencies[$dependency])) { $auxFile = $dependencies[$dependency]->getFile(); $auxFile = $folder . str_replace('/', DIRECTORY_SEPARATOR, $auxFile); // rel path in item $auxPath = str_replace(DIRECTORY_SEPARATOR, '/', helpers_File::getRelPath($qtiFile, $auxFile)); if (!empty($sharedStorage) && in_array($auxPath, $xincluded)) { $md5 = md5_file($auxFile); if (isset($sharedFiles[$md5])) { $info = $sharedFiles[$md5]; \common_Logger::i('Auxiliary file \'' . $auxPath . '\' linked to shared storage.'); } else { // TODO cleanup sharedstimulus import/export // move to taoQti item or library // validate the shared stimulus SharedStimulusImporter::isValidSharedStimulus($auxFile); // embed assets in the shared stimulus $newXmlFile = SharedStimulusPackageImporter::embedAssets($auxFile); $info = $sharedStorage->add($newXmlFile, basename($auxFile), $name); if (method_exists($sharedStorage, 'forceMimeType')) { // add() does not return link, so we need to parse it $resolver = new ItemMediaResolver($rdfItem, ''); $asset = $resolver->resolve($info['uri']); $sharedStorage->forceMimeType($asset->getMediaIdentifier(), 'application/qti+xml'); } $sharedFiles[$md5] = $info; \common_Logger::i('Auxiliary file \'' . $auxPath . '\' added to shared storage.'); } } else { // store locally, in a safe directory $safePath = ''; if (dirname($auxPath) !== '.') { $safePath = str_replace('../', '', dirname($auxPath)) . '/'; } $info = $local->add($auxFile, basename($auxFile), $safePath); \common_Logger::i('Auxiliary file \'' . $auxPath . '\' copied.'); } // replace uri if changed if ($auxPath != ltrim($info['uri'], '/')) { $itemContent = str_replace($auxPath, $info['uri'], $itemContent); } } } // Finally, import metadata. $this->importItemMetadata($metadataValues, $qtiItemResource, $rdfItem, $metadataInjectors); // And Apip if wanted if ($extractApip) { $this->storeApip($qtiFile, $rdfItem); } $itemService->setItemContent($rdfItem, $itemContent); $msg = __('The IMS QTI Item referenced as "%s" in the IMS Manifest file was successfully imported.', $qtiItemResource->getIdentifier()); $report = common_report_Report::createSuccess($msg, $rdfItem); } catch (ParsingException $e) { $report = new common_report_Report(common_report_Report::TYPE_ERROR, $e->getUserMessage()); } catch (ValidationException $ve) { $report = \common_report_Report::createFailure(__('IMS QTI Item referenced as "%s" in the IMS Manifest file could not be imported.', $qtiItemResource->getIdentifier())); $report->add($ve->getReport()); } catch (Exception $e) { // an error occured during a specific item $report = new common_report_Report(common_report_Report::TYPE_ERROR, __("An unknown error occured while importing the IMS QTI Package.")); common_Logger::e($e->getMessage()); } } catch (ValidationException $ve) { $validationReport = \common_report_Report::createFailure("The IMS Manifest file could not be validated"); $validationReport->add($ve->getReport()); $report->setMessage(__("No Items could be imported from the given IMS QTI package.")); $report->setType(common_report_Report::TYPE_ERROR); $report->add($validationReport); } catch (common_exception_UserReadableException $e) { $report = new common_report_Report(common_report_Report::TYPE_ERROR, __($e->getUserMessage())); $report->add($e); } return $report; }
/** * Main method to import Iterator data to Ontology object * * @param array $data * @param boolean $dryrun If set to true no data will be written * @return \common_report_Report */ public function import(array $data, $dryrun = false) { try { /** @var Injector[] $injectors */ $injectors = $this->getInjectors(); } catch (InconsistencyConfigException $e) { return \common_report_Report::createFailure('Config problem: ' . $e->getMessage()); } // Global report $report = \common_report_Report::createInfo('Report of metadata import.'); // Foreach line of dateSource foreach ($data as $uri => $dataSource) { try { // Check if resource exists $resource = $this->getResource($uri); if (!$resource->exists()) { throw new MetadataImportException('Unable to find resource associated to uri : "' . $uri . '"'); } $lineReport = \common_report_Report::createInfo('Report by line.'); $dataSource = array_change_key_case($dataSource); // Foreach injector to map a target source /** @var Injector $injector */ foreach ($injectors as $name => $injector) { $injectorReport = null; try { $dataRead = $injector->read($dataSource); $injector->write($resource, $dataRead, $dryrun); $injectorReport = \common_report_Report::createSuccess('Injector "' . $name . '" successfully ran.'); } catch (MetadataInjectorReadException $e) { $injectorReport = \common_report_Report::createFailure('Injector "' . $name . '" failed to run at read: ' . $e->getMessage()); } catch (MetadataInjectorWriteException $e) { $injectorReport = \common_report_Report::createFailure('Injector "' . $name . '" failed to run at write: ' . $e->getMessage()); } // Skip if there are no report (no data to read for this injector) if (!is_null($injectorReport)) { $lineReport->add($injectorReport); } } } catch (MetadataImportException $e) { $lineReport = \common_report_Report::createFailure($e->getMessage()); } $report->add($lineReport); } return $report; }
/** * imports a qti package and * returns the number of items imported * * @access public * @author Joel Bout, <*****@*****.**> * @param $file * @param core_kernel_classes_Class $itemClass * @param bool $validate * @param core_kernel_versioning_Repository $repository * @param bool $rollbackOnError * @param bool $rollbackOnWarning * @throws Exception * @throws ExtractException * @throws ParsingException * @throws \common_Exception * @throws \common_ext_ExtensionException * @throws common_exception_Error * @return common_report_Report */ public function importQTIPACKFile($file, core_kernel_classes_Class $itemClass, $validate = true, core_kernel_versioning_Repository $repository = null, $rollbackOnError = false, $rollbackOnWarning = false) { //load and validate the package $qtiPackageParser = new PackageParser($file); if ($validate) { $qtiPackageParser->validate(); if (!$qtiPackageParser->isValid()) { throw new ParsingException('Invalid QTI package format'); } } //extract the package $folder = $qtiPackageParser->extract(); if (!is_dir($folder)) { throw new ExtractException(); } $report = new common_report_Report(common_report_Report::TYPE_SUCCESS, ''); $successItems = array(); $allCreatedClasses = array(); try { // -- Initializing metadata services. $metadataMapping = Service::singleton()->getMetadataRegistry()->getMapping(); $metadataInjectors = array(); $metadataGuardians = array(); $metadataClassLookups = array(); $metadataValues = array(); // The metadata import feature needs a DOM representation of the manifest. $domManifest = new DOMDocument('1.0', 'UTF-8'); $domManifest->load($folder . 'imsmanifest.xml'); foreach ($metadataMapping['injectors'] as $injector) { $metadataInjectors[] = new $injector(); \common_Logger::i("Metadata Injector '{$injector}' registered."); } foreach ($metadataMapping['guardians'] as $guardian) { $metadataGuardians[] = new $guardian(); \common_Logger::i("Metadata Guardian '{$guardian}' registered."); } foreach ($metadataMapping['classLookups'] as $classLookup) { $metadataClassLookups[] = new $classLookup(); \common_Logger::i("Metadata Class Lookup '{$classLookup}' registered."); } $qtiItemResources = $this->createQtiManifest($folder . 'imsmanifest.xml'); foreach ($metadataMapping['extractors'] as $extractor) { $metadataExtractor = new $extractor(); \common_Logger::i("Metatada Extractor '{$extractor}' registered."); $metadataValues = array_merge($metadataValues, $metadataExtractor->extract($domManifest)); } $metadataCount = count($metadataValues, COUNT_RECURSIVE); \common_Logger::i("{$metadataCount} Metadata Values found in manifest by extractor(s)."); $itemCount = 0; $sharedFiles = array(); $createdClasses = array(); foreach ($qtiItemResources as $qtiItemResource) { $itemCount++; $itemReport = $this->importQtiItem($folder, $qtiItemResource, $itemClass, array(), $metadataValues, $metadataInjectors, $metadataGuardians, $metadataClassLookups, $sharedFiles, $createdClasses); $allCreatedClasses = array_merge($allCreatedClasses, $createdClasses); $rdfItem = $itemReport->getData(); if ($rdfItem) { $successItems[$qtiItemResource->getIdentifier()] = $rdfItem; } $report->add($itemReport); } } catch (ValidationException $ve) { $validationReport = \common_report_Report::createFailure("The IMS Manifest file could not be validated"); $validationReport->add($ve->getReport()); $report->setMessage(__("No Items could be imported from the given IMS QTI package.")); $report->setType(common_report_Report::TYPE_ERROR); $report->add($validationReport); } catch (common_exception_UserReadableException $e) { $report = new common_report_Report(common_report_Report::TYPE_ERROR, __($e->getUserMessage())); $report->add($e); } if (!empty($successItems)) { // Some items were imported from the package. $report->setMessage(__('%d Item(s) of %d imported from the given IMS QTI Package.', count($successItems), $itemCount)); if (count($successItems) !== $itemCount) { $report->setType(common_report_Report::TYPE_WARNING); } } else { $report->setMessage(__('No Items could be imported from the given IMS QTI package.')); $report->setType(common_report_Report::TYPE_ERROR); } if ($rollbackOnError === true) { if ($report->getType() === common_report_Report::TYPE_ERROR || $report->contains(common_report_Report::TYPE_ERROR)) { $this->rollback($successItems, $report, $allCreatedClasses); } } elseif ($rollbackOnWarning === true) { if ($report->contains(common_report_Report::TYPE_WARNING)) { $this->rollback($successItems, $report, $allCreatedClasses); } } // cleanup tao_helpers_File::delTree($folder); return $report; }
/** * Starts the import based on the form * * @param \core_kernel_classes_Class $class * @param \tao_helpers_form_Form $form * @return \common_report_Report $report */ public function import($class, $form) { //as upload may be called multiple times, we remove the session lock as soon as possible session_write_close(); try { $file = $form->getValue('source'); $service = MediaService::singleton(); $classUri = $class->getUri(); if (is_null($this->instanceUri) || $this->instanceUri === $classUri) { //if the file is a zip do a zip import if ($file['type'] !== 'application/zip') { try { self::isValidSharedStimulus($file['uploaded_file']); $filepath = $file['uploaded_file']; $name = $file['name']; if (!$service->createMediaInstance($filepath, $classUri, \tao_helpers_Uri::decode($form->getValue('lang')), $name, 'application/qti+xml')) { $report = \common_report_Report::createFailure(__('Fail to import Shared Stimulus')); } else { $report = \common_report_Report::createSuccess(__('Shared Stimulus imported successfully')); } } catch (XmlStorageException $e) { // The shared stimulus is not qti compliant, display error $report = \common_report_Report::createFailure($e->getMessage()); } } else { $report = $this->zipImporter->import($class, $form); } } else { if ($file['type'] !== 'application/zip') { self::isValidSharedStimulus($file['uploaded_file']); $filepath = $file['uploaded_file']; if (in_array($file['type'], array('application/xml', 'text/xml'))) { $name = basename($file['name'], 'xml'); $name .= 'xhtml'; $filepath = dirname($file['name']) . '/' . $name; \tao_helpers_File::copy($file['uploaded_file'], $filepath); } if (!$service->editMediaInstance($filepath, $this->instanceUri, \tao_helpers_Uri::decode($form->getValue('lang')))) { $report = \common_report_Report::createFailure(__('Fail to edit shared stimulus')); } else { $report = \common_report_Report::createSuccess(__('Shared Stimulus edited successfully')); } } else { $report = $this->zipImporter->edit(new \core_kernel_classes_Resource($this->instanceUri), $form); } } return $report; } catch (\Exception $e) { $report = \common_report_Report::createFailure($e->getMessage()); return $report; } }
/** * Import a QTI Test and its dependent Items into the TAO Platform. * * @param core_kernel_classes_Class $targetClass The RDFS Class where Ontology resources must be created. * @param oat\taoQtiItem\model\qti\Resource $qtiTestResource The QTI Test Resource representing the IMS QTI Test to be imported. * @param taoQtiTest_models_classes_ManifestParser $manifestParser The parser used to retrieve the IMS Manifest. * @param string $folder The absolute path to the folder where the IMS archive containing the test content * @return common_report_Report A report about how the importation behaved. */ protected function importTest(core_kernel_classes_Class $targetClass, Resource $qtiTestResource, taoQtiTest_models_classes_ManifestParser $manifestParser, $folder) { $itemImportService = ImportService::singleton(); $itemService = taoItems_models_classes_ItemsService::singleton(); $testClass = $targetClass; // Create an RDFS resource in the knowledge base that will hold // the information about the imported QTI Test. $testResource = $this->createInstance($testClass); $qtiTestModelResource = new core_kernel_classes_Resource(INSTANCE_TEST_MODEL_QTI); $modelProperty = new core_kernel_classes_Property(PROPERTY_TEST_TESTMODEL); $testResource->editPropertyValues($modelProperty, $qtiTestModelResource); // Create the report that will hold information about the import // of $qtiTestResource in TAO. $report = new common_report_Report(common_report_Report::TYPE_INFO); // The class where the items that belong to the test will be imported. $itemClass = new core_kernel_classes_Class(TAO_ITEM_CLASS); $targetClass = $itemClass->createSubClass($testResource->getLabel()); // Load and validate the manifest $qtiManifestParser = new taoQtiTest_models_classes_ManifestParser($folder . 'imsmanifest.xml'); $qtiManifestParser->validate(); // Prepare Metadata mechanisms. $metadataMapping = oat\taoQtiItem\model\qti\Service::singleton()->getMetadataRegistry()->getMapping(); $metadataInjectors = array(); $metadataGuardians = array(); $metadataClassLookups = array(); $metadataValues = array(); $domManifest = new DOMDocument('1.0', 'UTF-8'); $domManifest->load($folder . 'imsmanifest.xml'); foreach ($metadataMapping['injectors'] as $injector) { $metadataInjectors[] = new $injector(); } foreach ($metadataMapping['guardians'] as $guardian) { $metadataGuardians[] = new $guardian(); } foreach ($metadataMapping['classLookups'] as $classLookup) { $metadataClassLookups[] = new $classLookup(); } foreach ($metadataMapping['extractors'] as $extractor) { $metadataExtractor = new $extractor(); $metadataValues = array_merge($metadataValues, $metadataExtractor->extract($domManifest)); } // Set up $report with useful information for client code (especially for rollback). $reportCtx = new stdClass(); $reportCtx->manifestResource = $qtiTestResource; $reportCtx->rdfsResource = $testResource; $reportCtx->itemClass = $targetClass; $reportCtx->items = array(); $report->setData($reportCtx); // Expected test.xml file location. $expectedTestFile = $folder . str_replace('/', DIRECTORY_SEPARATOR, $qtiTestResource->getFile()); // Already imported test items (qti xml file paths). $alreadyImportedTestItemFiles = array(); // -- Check if the file referenced by the test QTI resource exists. if (is_readable($expectedTestFile) === false) { $report->add(common_report_Report::createFailure(__('No file found at location "%s".', $qtiTestResource->getFile()))); } else { // -- Load the test in a QTISM flavour. $testDefinition = new XmlDocument(); try { $testDefinition->load($expectedTestFile, true); // -- Load all items related to test. $itemError = false; // discover test's base path. $dependencies = taoQtiTest_helpers_Utils::buildAssessmentItemRefsTestMap($testDefinition, $manifestParser, $folder); if (count($dependencies['items']) > 0) { foreach ($dependencies['items'] as $assessmentItemRefId => $qtiDependency) { if ($qtiDependency !== false) { if (Resource::isAssessmentItem($qtiDependency->getType())) { $resourceIdentifier = $qtiDependency->getIdentifier(); // Check if the item is already stored in the bank. foreach ($metadataGuardians as $guardian) { if (isset($metadataValues[$resourceIdentifier]) === true) { if (($guard = $guardian->guard($metadataValues[$resourceIdentifier])) !== false) { common_Logger::i("Item with identifier '{$resourceIdentifier}' already in Item Bank."); $msg = __('The IMS QTI Item referenced as "%s" in the IMS Manifest file was already stored in the Item Bank.', $resourceIdentifier); $report->add(common_report_Report::createInfo($msg, $guard)); $reportCtx->items[$assessmentItemRefId] = $guard; // Simply do not import again. continue 2; } } } // Determine target class from metadata, if possible. // This is applied to items, not for test definitions. // The test definitions' target class will not be affected // by class lookups. $lookupTargetClass = false; foreach ($metadataClassLookups as $classLookup) { if (isset($metadataValues[$resourceIdentifier]) === true) { if (($lookupTargetClass = $classLookup->lookup($metadataValues[$resourceIdentifier])) !== false) { break; } } } $qtiFile = $folder . str_replace('/', DIRECTORY_SEPARATOR, $qtiDependency->getFile()); // Skip if $qtiFile already imported (multiple assessmentItemRef "hrefing" the same file). if (array_key_exists($qtiFile, $alreadyImportedTestItemFiles) === false) { $isApip = $qtiDependency->getType() === 'imsqti_apipitem_xmlv2p1'; $itemReport = $itemImportService->importQtiItem($folder, $qtiDependency, $lookupTargetClass !== false ? $lookupTargetClass : $targetClass, $isApip, $dependencies['dependencies']); $rdfItem = $itemReport->getData(); if ($rdfItem) { $reportCtx->items[$assessmentItemRefId] = $rdfItem; $alreadyImportedTestItemFiles[$qtiFile] = $rdfItem; $itemReport->setMessage(__('IMS QTI Item referenced as "%s" in the IMS Manifest file successfully imported.', $qtiDependency->getIdentifier())); } else { $itemReport->setType(common_report_Report::TYPE_ERROR); $itemReport->setMessage(__('IMS QTI Item referenced as "%s" in the IMS Manifest file could not be imported.', $qtiDependency->getIdentifier())); $itemError = $itemError === false ? true : $itemError; } $report->add($itemReport); } else { $reportCtx->items[$assessmentItemRefId] = $alreadyImportedTestItemFiles[$qtiFile]; } } } else { $msg = __('The dependency to the IMS QTI AssessmentItemRef "%s" in the IMS Manifest file could not be resolved.', $assessmentItemRefId); $report->add(common_report_Report::createFailure($msg)); $itemError = $itemError === false ? true : $itemError; } } // If items did not produce errors, we import the test definition. if ($itemError === false) { common_Logger::i('Importing test...'); // Second step is to take care of the test definition and the related media (auxiliary files). // 1. Import test definition (i.e. the QTI-XML Test file). $testContent = $this->importTestDefinition($testResource, $testDefinition, $qtiTestResource, $reportCtx->items, $folder, $report); if ($testContent !== false) { // 2. Import test auxilliary files (e.g. stylesheets, images, ...). $this->importTestAuxiliaryFiles($testContent, $qtiTestResource, $folder, $report); // 3. Give meaningful names to resources. $testTitle = $testDefinition->getDocumentComponent()->getTitle(); $testResource->setLabel($testDefinition->getDocumentComponent()->getTitle()); $targetClass->setLabel($testDefinition->getDocumentComponent()->getTitle()); // 4. if $targetClass does not contain any instances (because everything resolved by class lookups), // Just delete it. if ($targetClass->countInstances() == 0) { $targetClass->delete(); } } } else { $msg = __("One or more dependent IMS QTI Items could not be imported."); $report->add(common_report_Report::createFailure($msg)); } } else { // No depencies found (i.e. no item resources bound to the test). $msg = __("No reference to any IMS QTI Item found."); $report->add(common_report_Report::createFailure($msg)); } } catch (StorageException $e) { // Source of the exception = $testDefinition->load() // What is the reason ? $finalErrorString = ''; $eStrs = array(); if (($libXmlErrors = $e->getErrors()) !== null) { foreach ($libXmlErrors as $libXmlError) { $eStrs[] = __('XML error at line %1$d column %2$d "%3$s".', $libXmlError->line, $libXmlError->column, trim($libXmlError->message)); } } $finalErrorString = implode("\n", $eStrs); if (empty($finalErrorString) === true) { // Not XML malformation related. No info from LibXmlErrors extracted. if (($previous = $e->getPrevious()) != null) { // Useful information could be found here. $finalErrorString = $previous->getMessage(); if ($previous instanceof UnmarshallingException) { $domElement = $previous->getDOMElement(); $finalErrorString = __('Inconsistency at line %1d:', $domElement->getLineNo()) . ' ' . $previous->getMessage(); } } else { $finalErrorString = __("Unknown error."); } } $msg = __("Error found in the IMS QTI Test:\n%s", $finalErrorString); $report->add(common_report_Report::createFailure($msg)); } } if ($report->containsError() === false) { $report->setType(common_report_Report::TYPE_SUCCESS); $msg = __("IMS QTI Test referenced as \"%s\" in the IMS Manifest file successfully imported.", $qtiTestResource->getIdentifier()); $report->setMessage($msg); } else { $report->setType(common_report_Report::TYPE_ERROR); $msg = __("The IMS QTI Test referenced as \"%s\" in the IMS Manifest file could not be imported.", $qtiTestResource->getIdentifier()); $report->setMessage($msg); } return $report; }
/** * Does EVERYTHING * @todo cleanup interface */ public function index() { $formData = array(); if ($this->hasRequestParameter('classUri')) { if (trim($this->getRequestParameter('classUri')) != '') { $formData['class'] = new core_kernel_classes_Class(tao_helpers_Uri::decode($this->getRequestParameter('classUri'))); } } if ($this->hasRequestParameter('uri') && $this->hasRequestParameter('classUri')) { if (trim($this->getRequestParameter('uri')) != '') { $formData['instance'] = new core_kernel_classes_Resource(tao_helpers_Uri::decode($this->getRequestParameter('uri'))); } } $formData['id'] = $this->getRequestParameter('id'); if (!$this->isExportable($formData)) { $this->setData('message', $this->getNotExportableMessage($formData)); $this->setView('form/export_error_feedback.tpl', 'tao'); return; } $handlers = $this->getAvailableExportHandlers(); $exporter = $this->getCurrentExporter(); $selectedResource = isset($formData['instance']) ? $formData['instance'] : $formData['class']; $formFactory = new tao_actions_form_Export($handlers, $exporter->getExportForm($selectedResource), $formData); $myForm = $formFactory->getForm(); if (!is_null($exporter)) { $myForm->setValues(array('exportHandler' => get_class($exporter))); } $this->setData('myForm', $myForm->render()); if ($this->hasRequestParameter('exportChooser_sent') && $this->getRequestParameter('exportChooser_sent') == 1) { //use method GET to allow direct file download (not ajax compatible) $exportData = $_GET; if (isset($exportData['instances'])) { $instanceCount = count($exportData['instances']); for ($i = 0; $i < $instanceCount; $i++) { $exportData['instances'][$i] = tao_helpers_Uri::decode($exportData['instances'][$i]); } } elseif (isset($exportData['exportInstance'])) { $exportData['exportInstance'] = tao_helpers_Uri::decode($exportData['exportInstance']); } $file = null; try { $report = $exporter->export($exportData, tao_helpers_Export::getExportPath()); $file = $report; } catch (common_exception_UserReadableException $e) { $report = common_report_Report::createFailure($e->getUserMessage()); } $html = ''; if ($report instanceof common_report_Report) { $file = $report->getData(); if ($report->getType() === common_report_Report::TYPE_ERROR) { $html = tao_helpers_report_Rendering::render($report); } } if ($html !== '') { echo $html; } elseif (!is_null($file) && file_exists($file)) { $this->sendFileToClient($file, $selectedResource); } return; } $context = Context::getInstance(); $this->setData('export_extension', $context->getExtensionName()); $this->setData('export_module', $context->getModuleName()); $this->setData('export_action', $context->getActionName()); $this->setData('formTitle', __('Export ')); $this->setView('form/export.tpl', 'tao'); }
/** * Import a QTI Test and its dependent Items into the TAO Platform. * * @param core_kernel_classes_Class $targetClass The RDFS Class where Ontology resources must be created. * @param oat\taoQtiItem\model\qti\Resource $qtiTestResource The QTI Test Resource representing the IMS QTI Test to be imported. * @param taoQtiTest_models_classes_ManifestParser $manifestParser The parser used to retrieve the IMS Manifest. * @param string $folder The absolute path to the folder where the IMS archive containing the test content * @return common_report_Report A report about how the importation behaved. */ protected function importTest(core_kernel_classes_Class $targetClass, Resource $qtiTestResource, taoQtiTest_models_classes_ManifestParser $manifestParser, $folder) { $itemImportService = ImportService::singleton(); $itemService = taoItems_models_classes_ItemsService::singleton(); $testClass = $targetClass; // Create an RDFS resource in the knowledge base that will hold // the information about the imported QTI Test. $testResource = $this->createInstance($testClass); $qtiTestModelResource = new core_kernel_classes_Resource(INSTANCE_TEST_MODEL_QTI); $modelProperty = new core_kernel_classes_Property(PROPERTY_TEST_TESTMODEL); $testResource->editPropertyValues($modelProperty, $qtiTestModelResource); // Create the report that will hold information about the import // of $qtiTestResource in TAO. $report = new common_report_Report(common_report_Report::TYPE_INFO); // The class where the items that belong to the test will be imported. $itemClass = new core_kernel_classes_Class(TAO_ITEM_CLASS); $targetClass = $itemClass->createSubClass($testResource->getLabel()); // Load and validate the manifest $qtiManifestParser = new taoQtiTest_models_classes_ManifestParser($folder . 'imsmanifest.xml'); $qtiManifestParser->validate(); // Set up $report with useful information for client code (especially for rollback). $reportCtx = new stdClass(); $reportCtx->manifestResource = $qtiTestResource; $reportCtx->rdfsResource = $testResource; $reportCtx->itemClass = $targetClass; $reportCtx->items = array(); $report->setData($reportCtx); // Expected test.xml file location. $expectedTestFile = $folder . str_replace('/', DIRECTORY_SEPARATOR, $qtiTestResource->getFile()); // Already imported test items (qti xml file paths). $alreadyImportedTestItemFiles = array(); // -- Check if the file referenced by the test QTI resource exists. if (is_readable($expectedTestFile) === false) { $report->add(common_report_Report::createFailure(__('No file found at location "%s".', $qtiTestResource->getFile()))); } else { // -- Load the test in a QTISM flavour. $testDefinition = new XmlDocument(); try { $testDefinition->load($expectedTestFile, true); // -- Load all items related to test. $itemError = false; // discover test's base path. $dependencies = taoQtiTest_helpers_Utils::buildAssessmentItemRefsTestMap($testDefinition, $manifestParser, $folder); if (count($dependencies) > 0) { foreach ($dependencies as $assessmentItemRefId => $qtiDependency) { if ($qtiDependency !== false) { if (Resource::isAssessmentItem($qtiDependency->getType())) { $qtiFile = $folder . str_replace('/', DIRECTORY_SEPARATOR, $qtiDependency->getFile()); // Skip if $qtiFile already imported (multiple assessmentItemRef "hrefing" the same file). if (array_key_exists($qtiFile, $alreadyImportedTestItemFiles) === false) { $itemReport = $itemImportService->importQTIFile($qtiFile, $targetClass); $rdfItem = $itemReport->getData(); if ($rdfItem) { $itemPath = taoItems_models_classes_ItemsService::singleton()->getItemFolder($rdfItem); foreach ($qtiDependency->getAuxiliaryFiles() as $auxResource) { // $auxResource is a relativ URL, so we need to replace the slashes with directory separators $auxPath = $folder . str_replace('/', DIRECTORY_SEPARATOR, $auxResource); // does the file referenced by $auxPath exist? if (is_readable($auxPath) === true) { $relPath = helpers_File::getRelPath($qtiFile, $auxPath); $destPath = $itemPath . $relPath; tao_helpers_File::copy($auxPath, $destPath, true); } else { $msg = __('Auxiliary file not found at location "%s".', $auxResource); $itemReport->add(new common_report_Report(common_report_Report::TYPE_WARNING, $msg)); } } $reportCtx->items[$assessmentItemRefId] = $rdfItem; $alreadyImportedTestItemFiles[$qtiFile] = $rdfItem; $itemReport->setMessage(__('IMS QTI Item referenced as "%s" in the IMS Manifest file successfully imported.', $qtiDependency->getIdentifier())); } else { $itemReport->setType(common_report_Report::TYPE_ERROR); $itemReport->setMessage(__('IMS QTI Item referenced as "%s" in the IMS Manifest file could not be imported.', $qtiDependency->getIdentifier())); $itemError = $itemError === false ? true : $itemError; } $report->add($itemReport); } else { $reportCtx->items[$assessmentItemRefId] = $alreadyImportedTestItemFiles[$qtiFile]; } } } else { $msg = __('The dependency to the IMS QTI AssessmentItemRef "%s" in the IMS Manifest file could not be resolved.', $assessmentItemRefId); $report->add(common_report_Report::createFailure($msg)); $itemError = $itemError === false ? true : $itemError; } } // If items did not produce errors, we import the test definition. if ($itemError === false) { common_Logger::i('Importing test...'); // Second step is to take care of the test definition and the related media (auxiliary files). // 1. Import test definition (i.e. the QTI-XML Test file). $testContent = $this->importTestDefinition($testResource, $testDefinition, $qtiTestResource, $reportCtx->items, $folder, $report); if ($testContent !== false) { // 2. Import test auxilliary files (e.g. stylesheets, images, ...). $this->importTestAuxiliaryFiles($testContent, $qtiTestResource, $folder, $report); // 3. Give meaningful names to resources. $testTitle = $testDefinition->getDocumentComponent()->getTitle(); $testResource->setLabel($testDefinition->getDocumentComponent()->getTitle()); $targetClass->setLabel($testDefinition->getDocumentComponent()->getTitle()); } } else { $msg = __("One or more dependent IMS QTI Items could not be imported."); $report->add(common_report_Report::createFailure($msg)); } } else { // No depencies found (i.e. no item resources bound to the test). $msg = __("No reference to any IMS QTI Item found."); $report->add(common_report_Report::createFailure($msg)); } } catch (StorageException $e) { // Source of the exception = $testDefinition->load() // What is the reason ? $finalErrorString = ''; $eStrs = array(); if (($libXmlErrors = $e->getErrors()) !== null) { foreach ($libXmlErrors as $libXmlError) { $eStrs[] = __('XML error at line %1$d column %2$d "%3$s".', $libXmlError->line, $libXmlError->column, trim($libXmlError->message)); } } $finalErrorString = implode("\n", $eStrs); if (empty($finalErrorString) === true) { // Not XML malformation related. No info from LibXmlErrors extracted. if (($previous = $e->getPrevious()) != null) { // Useful information could be found here. $finalErrorString = $previous->getMessage(); if ($previous instanceof UnmarshallingException) { $domElement = $previous->getDOMElement(); $finalErrorString = __('Inconsistency at line %1d:', $domElement->getLineNo()) . ' ' . $previous->getMessage(); } } else { $finalErrorString = __("Unknown error."); } } $msg = __("Error found in the IMS QTI Test:\n%s", $finalErrorString); $report->add(common_report_Report::createFailure($msg)); } } if ($report->containsError() === false) { $report->setType(common_report_Report::TYPE_SUCCESS); $msg = __("IMS QTI Test referenced as \"%s\" in the IMS Manifest file successfully imported.", $qtiTestResource->getIdentifier()); $report->setMessage($msg); } else { $report->setType(common_report_Report::TYPE_ERROR); $msg = __("The IMS QTI Test referenced as \"%s\" in the IMS Manifest file could not be imported.", $qtiTestResource->getIdentifier()); $report->setMessage($msg); } return $report; }
/** * @param PortableElementObject $object * @param Validatable $validatable * @param array $validationGroup * @return bool * @throws PortableElementInconsistencyModelException * @throws PortableElementInvalidModelException * @throws \common_exception_Error */ public static function validate(PortableElementObject $object, Validatable $validatable, $validationGroup = array()) { $constraints = self::getValidConstraints($validatable->getConstraints(), $validationGroup); $errorReport = \common_report_Report::createFailure('Portable element validation has failed.'); foreach ($constraints as $field => $constraint) { foreach ($constraint as $validator) { $getter = 'get' . ucfirst($field); if (!method_exists($object, $getter)) { throw new PortableElementInconsistencyModelException('Validator is not correctly set for model ' . get_class($object)); } $value = $object->{$getter}(); if ($validator instanceof \tao_helpers_form_Validator) { if (!$validator->evaluate($value)) { $subReport = \common_report_Report::createFailure(__("Unable to validate %s: %s", $field, $validator->getMessage())); $errorReport->add($subReport); } continue; } if (is_string($validator)) { if (array_key_exists($validator, self::$customValidators)) { $callable = self::$customValidators[$validator]; try { self::$callable($value); } catch (PortableElementInvalidFieldException $e) { $subReport = \common_report_Report::createFailure(__("Unable to validate %s: %s", $field, $e->getMessage())); $errorReport->add($subReport); } } continue; } return false; } } if ($errorReport->containsError()) { $exception = new PortableElementInvalidModelException(); $exception->setReport($errorReport); throw $exception; } return true; }
/** * Creates a report without title of the parsing result * @return common_report_Report */ public function getReport() { if ($this->isValid()) { return common_report_Report::createSuccess(''); } else { $report = new common_report_Report(''); foreach ($this->getErrors() as $error) { $report->add(common_report_Report::createFailure($error['message'])); } return $report; } }
/** * Starts the import based on the form * * @param \core_kernel_classes_Class $class * @param \tao_helpers_form_Form $form * @return \common_report_Report $report */ public function import($class, $form) { //as upload may be called multiple times, we remove the session lock as soon as possible session_write_close(); try { $file = $form->getValue('source'); $service = MediaService::singleton(); $classUri = $class->getUri(); if (is_null($this->instanceUri) || $this->instanceUri === $classUri) { //if the file is a zip do a zip import if ($file['type'] !== 'application/zip') { if (!$service->createMediaInstance($file["uploaded_file"], $classUri, \tao_helpers_Uri::decode($form->getValue('lang')), $file["name"])) { $report = \common_report_Report::createFailure(__('Fail to import media')); } else { $report = \common_report_Report::createSuccess(__('Media imported successfully')); } } else { $zipImporter = new ZipImporter(); $report = $zipImporter->import($class, $form); } } else { if ($file['type'] !== 'application/zip') { $service->editMediaInstance($file["uploaded_file"], $this->instanceUri, \tao_helpers_Uri::decode($form->getValue('lang'))); $report = \common_report_Report::createSuccess(__('Media imported successfully')); } else { $report = \common_report_Report::createFailure(__('You can\'t upload a zip file as a media')); } } return $report; } catch (\Exception $e) { $report = \common_report_Report::createFailure($e->getMessage()); return $report; } }
/** * @param core_kernel_classes_Class $destination * @param $propUri * @param $csvRow * @param $csvColumn * @return array */ protected function validate(core_kernel_classes_Class $destination, $propUri, $csvRow, $csvColumn) { /** @var tao_helpers_form_Validator $validator */ $validators = $this->getValidator($propUri); foreach ((array) $validators as $validator) { if (!$validator->evaluate(array($destination, $propUri, $csvRow[$csvColumn]))) { $this->addErrorMessage($propUri, common_report_Report::createFailure($validator->getMessage() . ' "' . $csvRow[$csvColumn] . '"')); return false; } } return true; }
/** * Imports the currently loaded CsvFile into the destination Class. * The map should be set in the options before executing it. * * @access public * @author Jerome Bogaerts, <*****@*****.**> * @param string $source * @param core_kernel_classes_Class $destination * @return common_report_Report */ public function import($source, core_kernel_classes_Class $destination = null) { if (!isset($this->options['map'])) { throw new BadFunctionCallException("import map not set"); } if (is_null($destination)) { throw new InvalidArgumentException("{$destination} must be a valid core_kernel_classes_Class"); } $csvData = $this->load($source); $createdResources = 0; $toImport = $csvData->count(); $rangeProperty = new core_kernel_classes_Property(RDFS_RANGE); $report = new common_report_Report(common_report_Report::TYPE_ERROR, __('Data not imported. All records are invalid.')); for ($rowIterator = 0; $rowIterator < $csvData->count(); $rowIterator++) { helpers_TimeOutHelper::setTimeOutLimit(helpers_TimeOutHelper::SHORT); common_Logger::d("CSV - Importing CSV row {$rowIterator}."); $resource = null; $csvRow = $csvData->getRow($rowIterator); try { // default values $evaluatedData = $this->options['staticMap']; // validate csv values foreach ($this->options['map'] as $propUri => $csvColumn) { $this->validate($destination, $propUri, $csvRow, $csvColumn); } // evaluate csv values foreach ($this->options['map'] as $propUri => $csvColumn) { if ($csvColumn != 'csv_null' && $csvColumn != 'csv_select') { // process value if (isset($csvRow[$csvColumn]) && !is_null($csvRow[$csvColumn])) { $property = new core_kernel_classes_Property($propUri); $evaluatedData[$propUri] = $this->evaluateValues($csvColumn, $property, $csvRow[$csvColumn]); } } } // create resource $resource = $destination->createInstanceWithProperties($evaluatedData); // Apply 'resourceImported' callbacks. foreach ($this->resourceImported as $callback) { $callback($resource); } $report->add(new common_report_Report(common_report_Report::TYPE_SUCCESS, __('Imported resource "%s"', $resource->getLabel()), $resource)); $createdResources++; } catch (ValidationException $valExc) { $failure = common_report_Report::createFailure(__('Row %s', $rowIterator + 1) . ' ' . $valExc->getProperty()->getLabel() . ': ' . $valExc->getUserMessage() . ' "' . $valExc->getValue() . '"'); $report->add($failure); } helpers_TimeOutHelper::reset(); } $this->addOption('to_import', $toImport); $this->addOption('imported', $createdResources); if ($createdResources == $toImport) { $report->setType(common_report_Report::TYPE_SUCCESS); $report->setMessage(__('Imported %d resources', $toImport)); } elseif ($createdResources > 0) { $report->setType(common_report_Report::TYPE_WARNING); $report->setMessage(__('Imported %1$d/%2$d. Some records are invalid.', $createdResources, $toImport)); } return $report; }