1<?php 2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4/** 5* Test results import parser 6* 7* @author Helmut Schottmüller <ilias@aurealis.de> 8* @version $Id$ 9* @ingroup ModulesTest 10*/ 11include_once("./Services/Xml/classes/class.ilSaxParser.php"); 12 13class ilTestResultsImportParser extends ilSaxParser 14{ 15 private $tst_obj; 16 private $table; 17 private $active_id_mapping; 18 private $question_id_mapping; 19 private $user_criteria_field; 20 private $user_criteria_type; 21 private $user_criteria_checked = false; 22 23 protected $src_pool_def_id_mapping; 24 25 /** 26 * Constructor 27 */ 28 public function __construct($a_xml_file, &$test_object) 29 { 30 parent::__construct($a_xml_file, true); 31 $this->tst_obj = &$test_object; 32 $this->table = ''; 33 $this->active_id_mapping = array(); 34 $this->question_id_mapping = array(); 35 $this->user_criteria_checked = false; 36 $this->src_pool_def_id_mapping = array(); 37 } 38 39 /** 40 * @return array 41 */ 42 public function getQuestionIdMapping() 43 { 44 return $this->question_id_mapping; 45 } 46 47 /** 48 * @param array $question_id_mapping 49 */ 50 public function setQuestionIdMapping($question_id_mapping) 51 { 52 $this->question_id_mapping = $question_id_mapping; 53 } 54 55 /** 56 * @return array 57 */ 58 public function getSrcPoolDefIdMapping() 59 { 60 return $this->src_pool_def_id_mapping; 61 } 62 63 /** 64 * @param array $src_pool_def_id_mapping 65 */ 66 public function setSrcPoolDefIdMapping($src_pool_def_id_mapping) 67 { 68 $this->src_pool_def_id_mapping = $src_pool_def_id_mapping; 69 } 70 71 /** 72 * set event handler 73 * should be overwritten by inherited class 74 * @access private 75 */ 76 public function setHandlers($a_xml_parser) 77 { 78 xml_set_object($a_xml_parser, $this); 79 xml_set_element_handler($a_xml_parser, 'handlerBeginTag', 'handlerEndTag'); 80 xml_set_character_data_handler($a_xml_parser, 'handlerParseCharacterData'); 81 } 82 83 /** 84 * handler for begin of element parser 85 */ 86 public function handlerBeginTag($a_xml_parser, $a_name, $a_attribs) 87 { 88 global $DIC; 89 $ilDB = $DIC['ilDB']; 90 91 $this->sametag = false; 92 $this->characterbuffer = ""; 93 $this->depth[$a_xml_parser]++; 94 $this->path[$this->depth[$a_xml_parser]] = strtolower($a_name); 95 $this->qti_element = $a_name; 96 97 switch (strtolower($a_name)) { 98 case "results": 99 break; 100 case "row": 101 switch ($this->table) { 102 case 'tst_active': 103 if (!$this->user_criteria_checked) { 104 $this->user_criteria_checked = true; 105 if ($ilDB->tableColumnExists('usr_data', $a_attribs['user_criteria'])) { 106 $analyzer = new ilDBAnalyzer(); 107 $info = $analyzer->getFieldInformation('usr_data'); 108 $this->user_criteria_field = $a_attribs['user_criteria']; 109 $this->user_criteria_type = $info[$a_attribs['user_criteria']]['type']; 110 } 111 } 112 $usr_id = ANONYMOUS_USER_ID; 113 if (strlen($this->user_criteria_field)) { 114 $result = $ilDB->queryF( 115 "SELECT usr_id FROM usr_data WHERE " . $this->user_criteria_field . " = %s", 116 array($this->user_criteria_type), 117 array($a_attribs[$this->user_criteria_field]) 118 ); 119 if ($result->numRows()) { 120 $row = $ilDB->fetchAssoc($result); 121 $usr_id = $row['usr_id']; 122 } 123 } 124 $next_id = $ilDB->nextId('tst_active'); 125 126 $ilDB->insert('tst_active', array( 127 'active_id' => array('integer', $next_id), 128 'user_fi' => array('integer', $usr_id), 129 'anonymous_id' => array('text', strlen($a_attribs['anonymous_id']) ? $a_attribs['anonymous_id'] : null), 130 'test_fi' => array('integer', $this->tst_obj->getTestId()), 131 'lastindex' => array('integer', $a_attribs['lastindex']), 132 'tries' => array('integer', $a_attribs['tries']), 133 'submitted' => array('integer', $a_attribs['submitted']), 134 'submittimestamp' => array('timestamp', strlen($a_attribs['submittimestamp']) ? $a_attribs['submittimestamp'] : null), 135 'tstamp' => array('integer', $a_attribs['tstamp']), 136 'importname' => array('text', $a_attribs['fullname']), 137 'last_finished_pass' => array('integer', $this->fetchLastFinishedPass($a_attribs)), 138 'last_started_pass' => array('integer', $this->fetchLastStartedPass($a_attribs)), 139 'answerstatusfilter' => array('integer', $this->fetchAttribute($a_attribs, 'answer_status_filter')), 140 'objective_container' => array('integer', $this->fetchAttribute($a_attribs, 'objective_container')) 141 )); 142 $this->active_id_mapping[$a_attribs['active_id']] = $next_id; 143 break; 144 case 'tst_test_rnd_qst': 145 $nextId = $ilDB->nextId('tst_test_rnd_qst'); 146 $newActiveId = $this->active_id_mapping[$a_attribs['active_fi']]; 147 $newQuestionId = $this->question_id_mapping[$a_attribs['question_fi']]; 148 $newSrcPoolDefId = $this->src_pool_def_id_mapping[$a_attribs['src_pool_def_fi']]; 149 $ilDB->insert('tst_test_rnd_qst', array( 150 'test_random_question_id' => array('integer', $nextId), 151 'active_fi' => array('integer', $newActiveId), 152 'question_fi' => array('integer', $newQuestionId), 153 'sequence' => array('integer', $a_attribs['sequence']), 154 'pass' => array('integer', $a_attribs['pass']), 155 'tstamp' => array('integer', $a_attribs['tstamp']), 156 'src_pool_def_fi' => array('integer', $newSrcPoolDefId) 157 )); 158 break; 159 case 'tst_pass_result': 160 $affectedRows = $ilDB->manipulateF( 161 "INSERT INTO tst_pass_result (active_fi, pass, points, maxpoints, questioncount, answeredquestions, workingtime, tstamp) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)", 162 array( 163 'integer', 164 'integer', 165 'float', 166 'float', 167 'integer', 168 'integer', 169 'integer', 170 'integer' 171 ), 172 array( 173 $this->active_id_mapping[$a_attribs['active_fi']], 174 strlen($a_attribs['pass']) ? $a_attribs['pass'] : 0, 175 ($a_attribs["points"]) ? $a_attribs["points"] : 0, 176 ($a_attribs["maxpoints"]) ? $a_attribs["maxpoints"] : 0, 177 $a_attribs["questioncount"], 178 $a_attribs["answeredquestions"], 179 ($a_attribs["workingtime"]) ? $a_attribs["workingtime"] : 0, 180 $a_attribs["tstamp"] 181 ) 182 ); 183 break; 184 case 'tst_result_cache': 185 $affectedRows = $ilDB->manipulateF( 186 "INSERT INTO tst_result_cache (active_fi, pass, max_points, reached_points, mark_short, mark_official, passed, failed, tstamp) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)", 187 array( 188 'integer', 189 'integer', 190 'float', 191 'float', 192 'text', 193 'text', 194 'integer', 195 'integer', 196 'integer' 197 ), 198 array( 199 $this->active_id_mapping[$a_attribs['active_fi']], 200 strlen($a_attribs['pass']) ? $a_attribs['pass'] : 0, 201 ($a_attribs["max_points"]) ? $a_attribs["max_points"] : 0, 202 ($a_attribs["reached_points"]) ? $a_attribs["reached_points"] : 0, 203 strlen($a_attribs["mark_short"]) ? $a_attribs["mark_short"] : " ", 204 strlen($a_attribs["mark_official"]) ? $a_attribs["mark_official"] : " ", 205 ($a_attribs["passed"]) ? 1 : 0, 206 ($a_attribs["failed"]) ? 1 : 0, 207 $a_attribs["tstamp"] 208 ) 209 ); 210 break; 211 case 'tst_sequence': 212 $affectedRows = $ilDB->insert("tst_sequence", array( 213 "active_fi" => array("integer", $this->active_id_mapping[$a_attribs['active_fi']]), 214 "pass" => array("integer", $a_attribs['pass']), 215 "sequence" => array("clob", $a_attribs['sequence']), 216 "postponed" => array("text", (strlen($a_attribs['postponed'])) ? $a_attribs['postponed'] : null), 217 "hidden" => array("text", (strlen($a_attribs['hidden'])) ? $a_attribs['hidden'] : null), 218 "tstamp" => array("integer", $a_attribs['tstamp']) 219 )); 220 break; 221 case 'tst_solutions': 222 $next_id = $ilDB->nextId('tst_solutions'); 223 $affectedRows = $ilDB->insert("tst_solutions", array( 224 "solution_id" => array("integer", $next_id), 225 "active_fi" => array("integer", $this->active_id_mapping[$a_attribs['active_fi']]), 226 "question_fi" => array("integer", $this->question_id_mapping[$a_attribs['question_fi']]), 227 "value1" => array("clob", (strlen($a_attribs['value1'])) ? $a_attribs['value1'] : null), 228 "value2" => array("clob", (strlen($a_attribs['value2'])) ? $a_attribs['value2'] : null), 229 "pass" => array("integer", $a_attribs['pass']), 230 "tstamp" => array("integer", $a_attribs['tstamp']) 231 )); 232 break; 233 case 'tst_test_result': 234 $next_id = $ilDB->nextId('tst_test_result'); 235 $affectedRows = $ilDB->manipulateF( 236 "INSERT INTO tst_test_result (test_result_id, active_fi, question_fi, points, pass, manual, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s)", 237 array('integer', 'integer','integer', 'float', 'integer', 'integer','integer'), 238 array($next_id, $this->active_id_mapping[$a_attribs['active_fi']], $this->question_id_mapping[$a_attribs['question_fi']], $a_attribs['points'], $a_attribs['pass'], (strlen($a_attribs['manual'])) ? $a_attribs['manual'] : 0, $a_attribs['tstamp']) 239 ); 240 break; 241 case 'tst_times': 242 $next_id = $ilDB->nextId('tst_times'); 243 $affectedRows = $ilDB->manipulateF( 244 "INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)", 245 array('integer', 'integer', 'timestamp', 'timestamp', 'integer', 'integer'), 246 array($next_id, $this->active_id_mapping[$a_attribs['active_fi']], $a_attribs['started'], $a_attribs['finished'], $a_attribs['pass'], $a_attribs['tstamp']) 247 ); 248 break; 249 } 250 break; 251 default: 252 $this->table = $a_name; 253 break; 254 } 255 } 256 257 /** 258 * handler for end of element 259 */ 260 public function handlerEndTag($a_xml_parser, $a_name) 261 { 262 switch (strtolower($a_name)) { 263 case "tst_active": 264 global $DIC; 265 $ilLog = $DIC['ilLog']; 266 $ilLog->write("active id mapping: " . print_r($this->active_id_mapping, true)); 267 break; 268 case "tst_test_question": 269 global $DIC; 270 $ilLog = $DIC['ilLog']; 271 $ilLog->write("question id mapping: " . print_r($this->question_id_mapping, true)); 272 break; 273 } 274 } 275 276 /** 277 * handler for character data 278 */ 279 public function handlerParseCharacterData($a_xml_parser, $a_data) 280 { 281 // do nothing 282 } 283 284 private function fetchAttribute($attributes, $name) 285 { 286 if (isset($attributes[$name])) { 287 return $attributes[$name]; 288 } 289 290 return null; 291 } 292 293 private function fetchLastFinishedPass($attribs) 294 { 295 if (isset($attribs['last_finished_pass'])) { 296 return $attribs['last_finished_pass']; 297 } 298 299 if ($attribs['tries'] > 0) { 300 return $attribs['tries'] - 1; 301 } 302 303 return null; 304 } 305 306 private function fetchLastStartedPass($attribs) 307 { 308 if (isset($attribs['last_started_pass'])) { 309 return $attribs['last_started_pass']; 310 } 311 312 if ($attribs['tries'] > 0) { 313 return $attribs['tries'] - 1; 314 } 315 316 return null; 317 } 318} 319