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.');
         }
     }
 }
예제 #6
0
 /**
  * (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());
     }
 }
예제 #10
0
 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;
 }
예제 #17
0
 /**
  * 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;
 }
예제 #18
0
 /**
  * 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;
 }
예제 #21
0
 /**
  * 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;
 }
예제 #23
0
 /**
  * @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;
 }
예제 #24
0
 /**
  * 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;
 }
예제 #27
0
 /**
  * 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;
 }