/**
  * It is sometimes necessary to identify the link between assessmentItemRefs described in a QTI Test definition and the resources
  * describing items in IMS Manifest file. This utility method helps you to achieve this.
  * 
  * The method will return an array describing the IMS Manifest resources that were found in an IMS Manifest file on basis of
  * the assessmentItemRefs found in an AssessmentTest definition. The keys of the arrays are assessmentItemRef identifiers and
  * values are IMS Manifest Resources. 
  * 
  * If an IMS Manifest Resource cannot be found for a given assessmentItemRef, the value in the returned array will be false.
  * 
  * @param XmlDocument $test A QTI Test Definition.
  * @param taoQtiTest_models_classes_ManifestParser $manifestParser A Manifest Parser.
  * @param string $basePath The base path of the folder the IMS archive is exposed as a file system component.
  * @return array An array containing two arrays (items and dependencies) where keys are identifiers and values are oat\taoQtiItem\model\qti\Resource objects or false.
  */
 public static function buildAssessmentItemRefsTestMap(XmlDocument $test, taoQtiTest_models_classes_ManifestParser $manifestParser, $basePath)
 {
     $assessmentItemRefs = $test->getDocumentComponent()->getComponentsByClassName('assessmentItemRef');
     $map = array('items' => array(), 'dependencies' => array());
     $itemResources = $manifestParser->getResources(array('imsqti_item_xmlv2p1', 'imsqti_apipitem_xmlv2p1'), taoQtiTest_models_classes_ManifestParser::FILTER_RESOURCE_TYPE);
     $allResources = $manifestParser->getResources();
     // cleanup $basePath.
     $basePath = rtrim($basePath, "/\\");
     $basePath = helpers_File::truePath($basePath);
     $basePath .= DIRECTORY_SEPARATOR;
     $documentURI = preg_replace('/^file:\\//', '', $test->getDomDocument()->documentURI);
     $testPathInfo = pathinfo($documentURI);
     $testBasePath = tao_helpers_File::truePath($testPathInfo['dirname']) . DIRECTORY_SEPARATOR;
     foreach ($assessmentItemRefs as $itemRef) {
         // Find the QTI Resource (in IMS Manifest) related to the item ref.
         // To achieve this, we compare their path.
         $itemRefRelativeHref = str_replace('/', DIRECTORY_SEPARATOR, $itemRef->getHref());
         $itemRefRelativeHref = ltrim($itemRefRelativeHref, "/\\");
         $itemRefCanonicalHref = helpers_File::truePath($testBasePath . $itemRefRelativeHref);
         $map['items'][$itemRef->getIdentifier()] = false;
         // Compare with items referenced in the manifest.
         foreach ($itemResources as $itemResource) {
             $itemResourceRelativeHref = str_replace('/', DIRECTORY_SEPARATOR, $itemResource->getFile());
             $itemResourceRelativeHref = ltrim($itemResourceRelativeHref, "/\\");
             $itemResourceCanonicalHref = helpers_File::truePath($basePath . $itemResourceRelativeHref);
             // With some Windows flavours (Win7, Win8), the $itemRefCanonicalHref comes out with
             // a leading 'file:\' component. Let's clean this. (str_replace is binary-safe \0/)
             $os = tao_helpers_Environment::getOperatingSystem();
             if ($os === 'WINNT' || $os === 'WIN32' || $os === 'Windows') {
                 $itemRefCanonicalHref = str_replace('file:\\', '', $itemRefCanonicalHref);
                 // And moreover, it sometimes refer the temp directory as Windows\TEMP instead of Windows\Temp.
                 $itemRefCanonicalHref = str_replace('\\TEMP\\', '\\Temp\\', $itemRefCanonicalHref);
             }
             // With some MacOS flavours, the $itemRefCanonicalHref comes out with
             // a leading '/private' component. Clean it!
             if ($os === 'Darwin') {
                 $itemRefCanonicalHref = str_replace('/private', '', $itemRefCanonicalHref);
             }
             if ($itemResourceCanonicalHref == $itemRefCanonicalHref && is_file($itemResourceCanonicalHref)) {
                 // assessmentItemRef <-> IMS Manifest resource successful binding!
                 $map['items'][$itemRef->getIdentifier()] = $itemResource;
                 //get dependencies for each item
                 foreach ($itemResource->getDependencies() as $dependencyIdentifier) {
                     /** @var taoQtiTest_models_classes_QtiResource $resource */
                     foreach ($allResources as $resource) {
                         if ($dependencyIdentifier == $resource->getIdentifier()) {
                             $map['dependencies'][$dependencyIdentifier] = $resource;
                             break;
                         }
                     }
                 }
                 break;
             }
         }
     }
     return $map;
 }
 /**
  * Import a QTI Test Package containing one or more QTI Test definitions.
  *
  * @param core_kernel_classes_Class $targetClass The Target RDFS class where you want the Test Resources to be created.
  * @param string $file The path to the IMS archive you want to import tests from.
  * @return common_report_Report An import report.
  */
 public function importMultipleTests(core_kernel_classes_Class $targetClass, $file)
 {
     $testClass = $targetClass;
     $report = new common_report_Report(common_report_Report::TYPE_INFO);
     $validPackage = false;
     $validManifest = false;
     $testsFound = false;
     // Validate the given IMS Package itself (ZIP integrity, presence of an 'imsmanifest.xml' file.
     $invalidArchiveMsg = __("The provided archive is invalid. Make sure it is not corrupted and that it contains an 'imsmanifest.xml' file.");
     try {
         $qtiPackageParser = new taoQtiTest_models_classes_PackageParser($file);
         $qtiPackageParser->validate();
         $validPackage = true;
     } catch (Exception $e) {
         $report->add(common_report_Report::createFailure($invalidArchiveMsg));
     }
     // Validate the manifest (well formed XML, valid against the schema).
     if ($validPackage === true) {
         $folder = $qtiPackageParser->extract();
         if (is_dir($folder) === false) {
             $report->add(common_report_Report::createFailure($invalidArchiveMsg));
         } else {
             $qtiManifestParser = new taoQtiTest_models_classes_ManifestParser($folder . 'imsmanifest.xml');
             $qtiManifestParser->validate();
             if ($qtiManifestParser->isValid() === true) {
                 $validManifest = true;
                 $tests = array();
                 foreach (Resource::getTestTypes() as $type) {
                     $tests = array_merge($tests, $qtiManifestParser->getResources($type));
                 }
                 $testsFound = count($tests) !== 0;
                 if ($testsFound !== true) {
                     $report->add(common_report_Report::createFailure(__("Package is valid but no tests were found. Make sure that it contains valid QTI tests.")));
                 } else {
                     foreach ($tests as $qtiTestResource) {
                         $report->add($this->importTest($testClass, $qtiTestResource, $qtiManifestParser, $folder));
                     }
                 }
             } else {
                 $msg = __("The 'imsmanifest.xml' file found in the archive is not valid.");
                 $report->add(common_report_Report::createFailure($msg));
             }
             // Cleanup the folder where the archive was extracted.
             tao_helpers_File::deltree($folder);
         }
     }
     if ($report->containsError() === true) {
         $report->setMessage(__('The IMS QTI Test Package could not be imported.'));
         $report->setType(common_report_Report::TYPE_ERROR);
     } else {
         $report->setMessage(__('IMS QTI Test Package successfully imported.'));
         $report->setType(common_report_Report::TYPE_SUCCESS);
     }
     if ($report->containsError() === true && $validPackage === true && $validManifest === true && $testsFound === true) {
         // We consider a test package as an atomic component, we then rollback it.
         $itemService = taoItems_models_classes_ItemsService::singleton();
         foreach ($report as $r) {
             $data = $r->getData();
             // Delete all imported items.
             foreach ($data->items as $item) {
                 common_Logger::i("Rollbacking item '" . $item->getLabel() . "'...");
                 @$itemService->deleteItem($item);
             }
             // Delete the target Item RDFS class.
             common_Logger::i("Rollbacking Items target RDFS class '" . $data->itemClass->getLabel() . "'...");
             @$data->itemClass->delete();
             // Delete test definition.
             common_Logger::i("Rollbacking test '" . $data->rdfsResource->getLabel() . "...");
             @$this->deleteTest($data->rdfsResource);
             if (count($data->items) > 0) {
                 $msg = __("The resources related to the IMS QTI Test referenced as \"%s\" in the IMS Manifest file were rolled back.", $data->manifestResource->getIdentifier());
                 $report->add(new common_report_Report(common_report_Report::TYPE_WARNING, $msg));
             }
         }
     }
     return $report;
 }
Example #3
0
 public function addItems($directory)
 {
     $qtiManifestParser = new \taoQtiTest_models_classes_ManifestParser($directory . 'imsmanifest.xml');
     $itemTypes = array('imsqti_item_xmlv2p1', 'imsqti_apipitem_xmlv2p2', 'imsqti_apipitem_xmlv2p1');
     $items = $qtiManifestParser->getResources();
     $todo = array();
     foreach ($items as $res) {
         if (in_array($res->getType(), $itemTypes)) {
             $this->addXml($directory . $res->getFile());
         }
         foreach ($res->getAuxiliaryFiles() as $file) {
             $mime = \tao_helpers_File::getMimeType($directory . $file);
             $prefix = substr($mime, 0, strpos($mime, '/'));
             if ($prefix == 'image') {
                 $this->replaceImage($directory . $file);
             }
         }
     }
 }