1<?php 2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4include_once("./Services/Export/classes/class.ilXmlImporter.php"); 5 6/** 7 * Importer class for files 8 * 9 * @author Stefan Meyer <meyer@leifos.com> 10 * @version $Id$ 11 * @ingroup ModulesLearningModule 12 */ 13class ilTestImporter extends ilXmlImporter 14{ 15 /** 16 * @var array 17 */ 18 public static $finallyProcessedTestsRegistry = array(); 19 20 /** 21 * Import XML 22 * 23 * @param 24 * @return 25 */ 26 public function importXmlRepresentation($a_entity, $a_id, $a_xml, $a_mapping) 27 { 28 // Container import => test object already created 29 include_once "./Modules/Test/classes/class.ilObjTest.php"; 30 ilObjTest::_setImportDirectory($this->getImportDirectoryContainer()); 31 32 if ($new_id = $a_mapping->getMapping('Services/Container', 'objs', $a_id)) { 33 // container content 34 $newObj = ilObjectFactory::getInstanceByObjId($new_id, false); 35 $_SESSION['tst_import_subdir'] = $this->getImportPackageName(); 36 $newObj->saveToDb(); // this generates test id first time 37 $questionParentObjId = $newObj->getId(); 38 $newObj->setOfflineStatus(false); 39 $questionParentObjId = $newObj->getId(); 40 } else { 41 // single object 42 $new_id = $a_mapping->getMapping('Modules/Test', 'tst', 'new_id'); 43 $newObj = ilObjectFactory::getInstanceByObjId($new_id, false); 44 45 if (isset($_SESSION['tst_import_qst_parent'])) { 46 $questionParentObjId = $_SESSION['tst_import_qst_parent']; 47 } else { 48 $questionParentObjId = $newObj->getId(); 49 } 50 } 51 52 $newObj->loadFromDb(); 53 54 list($xml_file, $qti_file) = $this->parseXmlFileNames(); 55 56 global $DIC; /* @var ILIAS\DI\Container $DIC */ 57 if (!@file_exists($xml_file)) { 58 $DIC['ilLog']->write(__METHOD__ . ': Cannot find xml definition: ' . $xml_file); 59 return false; 60 } 61 if (!@file_exists($qti_file)) { 62 $DIC['ilLog']->write(__METHOD__ . ': Cannot find xml definition: ' . $qti_file); 63 return false; 64 } 65 66 /* @var ilObjTest $newObj */ 67 68 // FIXME: Copied from ilObjTestGUI::importVerifiedFileObject 69 // TODO: move all logic to ilObjTest::importVerifiedFile and call 70 // this method from ilObjTestGUI and ilTestImporter 71 $newObj->mark_schema->flush(); 72 73 74 if (isset($_SESSION['tst_import_idents'])) { 75 $idents = $_SESSION['tst_import_idents']; 76 } else { 77 $idents = null; 78 } 79 80 // start parsing of QTI files 81 include_once "./Services/QTI/classes/class.ilQTIParser.php"; 82 $qtiParser = new ilQTIParser($qti_file, IL_MO_PARSE_QTI, $questionParentObjId, $idents); 83 $qtiParser->setTestObject($newObj); 84 $result = $qtiParser->startParsing(); 85 86 // import page data 87 include_once("./Modules/LearningModule/classes/class.ilContObjParser.php"); 88 $contParser = new ilContObjParser($newObj, $xml_file, basename($this->getImportDirectory())); 89 $contParser->setQuestionMapping($qtiParser->getImportMapping()); 90 $contParser->startParsing(); 91 92 foreach ($qtiParser->getQuestionIdMapping() as $oldQuestionId => $newQuestionId) { 93 $a_mapping->addMapping( 94 "Services/Taxonomy", 95 "tax_item", 96 "tst:quest:$oldQuestionId", 97 $newQuestionId 98 ); 99 100 $a_mapping->addMapping( 101 "Services/Taxonomy", 102 "tax_item_obj_id", 103 "tst:quest:$oldQuestionId", 104 $newObj->getId() 105 ); 106 107 $a_mapping->addMapping( 108 "Modules/Test", 109 "quest", 110 $oldQuestionId, 111 $newQuestionId 112 ); 113 } 114 115 if ($newObj->isRandomTest()) { 116 $newObj->questions = array(); 117 $this->importRandomQuestionSetConfig($newObj, $xml_file, $a_mapping); 118 } 119 120 // import test results 121 if (@file_exists($_SESSION["tst_import_results_file"])) { 122 include_once("./Modules/Test/classes/class.ilTestResultsImportParser.php"); 123 $results = new ilTestResultsImportParser($_SESSION["tst_import_results_file"], $newObj); 124 $results->setQuestionIdMapping($a_mapping->getMappingsOfEntity('Modules/Test', 'quest')); 125 $results->setSrcPoolDefIdMapping($a_mapping->getMappingsOfEntity('Modules/Test', 'rnd_src_pool_def')); 126 $results->startParsing(); 127 } 128 129 $newObj->saveToDb(); // this creates test_fi 130 $newObj->update(); // this saves ilObject data 131 132 // import skill assignments 133 $importedAssignmentList = $this->importQuestionSkillAssignments($a_mapping, $newObj, $xml_file); 134 $this->importSkillLevelThresholds($a_mapping, $importedAssignmentList, $newObj, $xml_file); 135 136 $a_mapping->addMapping("Modules/Test", "tst", $a_id, $newObj->getId()); 137 138 ilObjTest::_setImportDirectory(); 139 } 140 141 /** 142 * Final processing 143 * 144 * @param ilImportMapping $a_mapping 145 * @return 146 */ 147 public function finalProcessing($a_mapping) 148 { 149 $maps = $a_mapping->getMappingsOfEntity("Modules/Test", "tst"); 150 151 foreach ($maps as $old => $new) { 152 if ($old == "new_id" || (int) $old <= 0) { 153 continue; 154 } 155 156 if (isset(self::$finallyProcessedTestsRegistry[$new])) { 157 continue; 158 } 159 160 /* @var ilObjTest $testOBJ */ 161 $testOBJ = ilObjectFactory::getInstanceByObjId($new, false); 162 if ($testOBJ->isRandomTest()) { 163 $this->finalRandomTestTaxonomyProcessing($a_mapping, $old, $new, $testOBJ); 164 } 165 166 self::$finallyProcessedTestsRegistry[$new] = true; 167 } 168 } 169 170 protected function finalRandomTestTaxonomyProcessing(ilImportMapping $mapping, $oldTstObjId, $newTstObjId, ilObjTest $testOBJ) 171 { 172 require_once 'Services/Taxonomy/classes/class.ilObjTaxonomy.php'; 173 174 // get all new taxonomies of this object and store usage for test object 175 176 $new_tax_ids = $mapping->getMapping( 177 'Services/Taxonomy', 178 'tax_usage_of_obj', 179 $oldTstObjId 180 ); 181 182 if ($new_tax_ids !== false) { 183 $tax_ids = explode(":", $new_tax_ids); 184 185 foreach ($tax_ids as $tid) { 186 ilObjTaxonomy::saveUsage($tid, $newTstObjId); 187 } 188 } 189 190 // update all source pool definition's tax/taxNode ids with new mapped id 191 global $DIC; /* @var ILIAS\DI\Container $DIC */ 192 $ilDB = $DIC['ilDB']; 193 194 require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionFactory.php'; 195 $srcPoolDefFactory = new ilTestRandomQuestionSetSourcePoolDefinitionFactory( 196 $ilDB, 197 $testOBJ 198 ); 199 200 require_once 'Modules/Test/classes/class.ilTestRandomQuestionSetSourcePoolDefinitionList.php'; 201 $srcPoolDefList = new ilTestRandomQuestionSetSourcePoolDefinitionList( 202 $ilDB, 203 $testOBJ, 204 $srcPoolDefFactory 205 ); 206 207 $srcPoolDefList->loadDefinitions(); 208 209 foreach ($srcPoolDefList as $definition) { 210 // #21330 211 if (!is_array($definition->getMappedTaxonomyFilter()) || 0 === count($definition->getMappedTaxonomyFilter())) { 212 continue; 213 } 214 215 $definition->setMappedTaxonomyFilter( 216 $this->getNewMappedTaxonomyFilter( 217 $mapping, 218 $definition->getMappedTaxonomyFilter() 219 ) 220 ); 221 $definition->saveToDb(); 222 } 223 } 224 225 /** 226 * @param ilImportMapping $mapping 227 * @param array $mappedFilter 228 * @return array 229 */ 230 protected function getNewMappedTaxonomyFilter(ilImportMapping $mapping, array $mappedFilter) 231 { 232 $newMappedFilter = array(); 233 234 foreach ($mappedFilter as $taxId => $taxNodes) { 235 $newTaxId = $mapping->getMapping( 236 'Services/Taxonomy', 237 'tax', 238 $taxId 239 ); 240 241 if (!$newTaxId) { 242 continue; 243 } 244 245 $newMappedFilter[$newTaxId] = array(); 246 247 foreach ($taxNodes as $taxNodeId) { 248 $newTaxNodeId = $mapping->getMapping( 249 'Services/Taxonomy', 250 'tax_tree', 251 $taxNodeId 252 ); 253 254 if (!$newTaxNodeId) { 255 continue; 256 } 257 258 $newMappedFilter[$newTaxId][] = $newTaxNodeId; 259 } 260 } 261 262 return $newMappedFilter; 263 } 264 265 /** 266 * Create qti and xml file name 267 * @return array 268 */ 269 protected function parseXmlFileNames() 270 { 271 global $DIC; /* @var ILIAS\DI\Container $DIC */ 272 $DIC['ilLog']->write(__METHOD__ . ': ' . $this->getImportDirectory()); 273 274 $basename = basename($this->getImportDirectory()); 275 276 $xml = $this->getImportDirectory() . '/' . $basename . '.xml'; 277 $qti = $this->getImportDirectory() . '/' . preg_replace('/test|tst/', 'qti', $basename) . '.xml'; 278 279 return array($xml,$qti); 280 } 281 282 private function getImportDirectoryContainer() 283 { 284 $dir = $this->getImportDirectory(); 285 $dir = dirname($dir); 286 return $dir; 287 } 288 289 private function getImportPackageName() 290 { 291 $dir = $this->getImportDirectory(); 292 $name = basename($dir); 293 return $name; 294 } 295 296 protected function importRandomQuestionSetConfig(ilObjTest $testOBJ, $xmlFile, $a_mapping) 297 { 298 require_once 'Modules/Test/classes/class.ilObjTestXMLParser.php'; 299 $parser = new ilObjTestXMLParser($xmlFile); 300 $parser->setTestOBJ($testOBJ); 301 $parser->setImportMapping($a_mapping); 302 $parser->startParsing(); 303 } 304 305 /** 306 * @param ilImportMapping $mappingRegistry 307 * @param ilObjTest $testOBJ 308 * @param string $xmlfile 309 * @return ilAssQuestionSkillAssignmentList 310 */ 311 protected function importQuestionSkillAssignments(ilImportMapping $mapping, ilObjTest $testOBJ, $xmlFile) 312 { 313 require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssQuestionSkillAssignmentXmlParser.php'; 314 $parser = new ilAssQuestionSkillAssignmentXmlParser($xmlFile); 315 $parser->startParsing(); 316 317 require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssQuestionSkillAssignmentImporter.php'; 318 $importer = new ilAssQuestionSkillAssignmentImporter(); 319 $importer->setTargetParentObjId($testOBJ->getId()); 320 $importer->setImportInstallationId($this->getInstallId()); 321 $importer->setImportMappingRegistry($mapping); 322 $importer->setImportMappingComponent('Modules/Test'); 323 $importer->setImportAssignmentList($parser->getAssignmentList()); 324 325 $importer->import(); 326 327 if ($importer->getFailedImportAssignmentList()->assignmentsExist()) { 328 require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssQuestionSkillAssignmentImportFails.php'; 329 $qsaImportFails = new ilAssQuestionSkillAssignmentImportFails($testOBJ->getId()); 330 $qsaImportFails->registerFailedImports($importer->getFailedImportAssignmentList()); 331 332 $testOBJ->setOnline(false); 333 } 334 335 return $importer->getSuccessImportAssignmentList(); 336 } 337 338 /** 339 * @param ilImportMapping $mapping 340 * @param ilAssQuestionSkillAssignmentList $assignmentList 341 * @param ilObjTest $testOBJ 342 * @param $xmlFile 343 */ 344 protected function importSkillLevelThresholds(ilImportMapping $mapping, ilAssQuestionSkillAssignmentList $assignmentList, ilObjTest $testOBJ, $xmlFile) 345 { 346 require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdXmlParser.php'; 347 $parser = new ilTestSkillLevelThresholdXmlParser($xmlFile); 348 $parser->startParsing(); 349 350 require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdImporter.php'; 351 $importer = new ilTestSkillLevelThresholdImporter(); 352 $importer->setTargetTestId($testOBJ->getTestId()); 353 $importer->setImportInstallationId($this->getInstallId()); 354 $importer->setImportMappingRegistry($mapping); 355 $importer->setImportedQuestionSkillAssignmentList($assignmentList); 356 $importer->setImportThresholdList($parser->getSkillLevelThresholdImportList()); 357 $importer->import(); 358 359 if ($importer->getFailedThresholdImportSkillList()->skillsExist()) { 360 require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdImportFails.php'; 361 $sltImportFails = new ilTestSkillLevelThresholdImportFails($testOBJ->getId()); 362 $sltImportFails->registerFailedImports($importer->getFailedThresholdImportSkillList()); 363 364 $testOBJ->setOfflineStatus(true); 365 } 366 } 367} 368