1<?php 2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4 5/** 6 * @author Björn Heyser <bheyser@databay.de> 7 * @version $Id$ 8 * 9 * @package Modules/TestQuestionPool 10 */ 11class ilAssQuestionUserSolutionAdopter 12{ 13 /** 14 * @var ressource 15 */ 16 protected static $preparedDeleteSolutionRecordsStatement = null; 17 18 /** 19 * @var ressource 20 */ 21 protected static $preparedSelectSolutionRecordsStatement = null; 22 23 /** 24 * @var ressource 25 */ 26 protected static $preparedInsertSolutionRecordStatement = null; 27 28 /** 29 * @var ressource 30 */ 31 protected static $preparedDeleteResultRecordStatement = null; 32 33 /** 34 * @var ressource 35 */ 36 protected static $preparedSelectResultRecordStatement = null; 37 38 /** 39 * @var ressource 40 */ 41 protected static $preparedInsertResultRecordStatement = null; 42 43 /** 44 * @var ilDBInterface 45 */ 46 protected $db; 47 48 /** 49 * @var ilAssQuestionProcessLockerFactory 50 */ 51 protected $processLockerFactory; 52 53 /** 54 * @var integer 55 */ 56 protected $userId; 57 58 /** 59 * @var integer 60 */ 61 protected $activeId; 62 63 /** 64 * @var integer 65 */ 66 protected $targetPass; 67 68 /** 69 * @var array 70 */ 71 protected $questionIds; 72 73 /** 74 * @param ilDBInterface $db 75 * @param ilSetting $assSettings 76 * @param bool $isAssessmentLogEnabled 77 */ 78 public function __construct(ilDBInterface $db, ilSetting $assSettings, $isAssessmentLogEnabled) 79 { 80 $this->db = $db; 81 82 $this->userId = null; 83 $this->activeId = null; 84 $this->targetPass = null; 85 $this->questionIds = array(); 86 87 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php'; 88 $this->processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $db); 89 $this->processLockerFactory->setAssessmentLogEnabled($isAssessmentLogEnabled); 90 } 91 92 /** 93 * @return int 94 */ 95 public function getUserId() 96 { 97 return $this->userId; 98 } 99 100 /** 101 * @param int $userId 102 */ 103 public function setUserId($userId) 104 { 105 $this->userId = $userId; 106 } 107 108 /** 109 * @return int 110 */ 111 public function getActiveId() 112 { 113 return $this->activeId; 114 } 115 116 /** 117 * @param int $activeId 118 */ 119 public function setActiveId($activeId) 120 { 121 $this->activeId = $activeId; 122 } 123 124 /** 125 * @return int 126 */ 127 public function getTargetPass() 128 { 129 return $this->targetPass; 130 } 131 132 /** 133 * @param int $targetPass 134 */ 135 public function setTargetPass($targetPass) 136 { 137 $this->targetPass = $targetPass; 138 } 139 140 /** 141 * @return array 142 */ 143 public function getQuestionIds() 144 { 145 return $this->questionIds; 146 } 147 148 /** 149 * @param array $questionIds 150 */ 151 public function setQuestionIds($questionIds) 152 { 153 $this->questionIds = $questionIds; 154 } 155 156 public function perform() 157 { 158 $this->processLockerFactory->setUserId($this->getUserId()); 159 160 foreach ($this->getQuestionIds() as $questionId) { 161 $this->processLockerFactory->setQuestionId($questionId); 162 $processLocker = $this->processLockerFactory->getLocker(); 163 164 $processLocker->executeUserTestResultUpdateLockOperation(function () use ($questionId) { 165 $this->adoptQuestionAnswer($questionId); 166 }); 167 } 168 } 169 170 protected function adoptQuestionAnswer($questionId) 171 { 172 $this->resetTargetSolution($questionId); 173 $this->resetTargetResult($questionId); 174 175 $sourcePass = $this->adoptSourceSolution($questionId); 176 177 if ($sourcePass !== null) { 178 $this->adoptSourceResult($questionId, $sourcePass); 179 } 180 } 181 182 protected function resetTargetSolution($questionId) 183 { 184 $this->db->execute( 185 $this->getPreparedDeleteSolutionRecordsStatement(), 186 array($this->getActiveId(), $questionId, $this->getTargetPass()) 187 ); 188 } 189 190 protected function resetTargetResult($questionId) 191 { 192 $this->db->execute( 193 $this->getPreparedDeleteResultRecordStatement(), 194 array($this->getActiveId(), $questionId, $this->getTargetPass()) 195 ); 196 } 197 198 protected function adoptSourceSolution($questionId) 199 { 200 $res = $this->db->execute( 201 $this->getPreparedSelectSolutionRecordsStatement(), 202 array($this->getActiveId(), $questionId, $this->getTargetPass()) 203 ); 204 205 $sourcePass = null; 206 207 while ($row = $this->db->fetchAssoc($res)) { 208 if ($sourcePass === null) { 209 $sourcePass = $row['pass']; 210 } elseif ($row['pass'] < $sourcePass) { 211 break; 212 } 213 214 $solutionId = $this->db->nextId('tst_solutions'); 215 216 $this->db->execute($this->getPreparedInsertSolutionRecordStatement(), array( 217 $solutionId, $this->getActiveId(), $questionId, $this->getTargetPass(), time(), 218 $row['points'], $row['value1'], $row['value2'] 219 )); 220 } 221 222 return $sourcePass; 223 } 224 225 protected function adoptSourceResult($questionId, $sourcePass) 226 { 227 $res = $this->db->execute( 228 $this->getPreparedSelectResultRecordStatement(), 229 array($this->getActiveId(), $questionId, $sourcePass) 230 ); 231 232 $row = $this->db->fetchAssoc($res); 233 234 $resultId = $this->db->nextId('tst_test_result'); 235 236 $this->db->execute($this->getPreparedInsertResultRecordStatement(), array( 237 $resultId, $this->getActiveId(), $questionId, $this->getTargetPass(), time(), 238 $row['points'], $row['manual'], $row['hint_count'], $row['hint_points'], $row['answered'] 239 )); 240 } 241 242 protected function getPreparedDeleteSolutionRecordsStatement() 243 { 244 if (self::$preparedDeleteSolutionRecordsStatement === null) { 245 self::$preparedDeleteSolutionRecordsStatement = $this->db->prepareManip( 246 "DELETE FROM tst_solutions WHERE active_fi = ? AND question_fi = ? AND pass = ?", 247 array('integer', 'integer', 'integer') 248 ); 249 } 250 251 return self::$preparedDeleteSolutionRecordsStatement; 252 } 253 254 protected function getPreparedSelectSolutionRecordsStatement() 255 { 256 if (self::$preparedSelectSolutionRecordsStatement === null) { 257 $query = " 258 SELECT pass, points, value1, value2 FROM tst_solutions 259 WHERE active_fi = ? AND question_fi = ? AND pass < ? ORDER BY pass DESC 260 "; 261 262 self::$preparedSelectSolutionRecordsStatement = $this->db->prepare( 263 $query, 264 array('integer', 'integer', 'integer') 265 ); 266 } 267 268 return self::$preparedSelectSolutionRecordsStatement; 269 } 270 271 protected function getPreparedInsertSolutionRecordStatement() 272 { 273 if (self::$preparedInsertSolutionRecordStatement === null) { 274 $query = " 275 INSERT INTO tst_solutions ( 276 solution_id, active_fi, question_fi, pass, tstamp, points, value1, value2 277 ) VALUES ( 278 ?, ?, ?, ?, ?, ?, ?, ? 279 ) 280 "; 281 282 self::$preparedInsertSolutionRecordStatement = $this->db->prepareManip( 283 $query, 284 array('integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'text', 'text') 285 ); 286 } 287 288 return self::$preparedInsertSolutionRecordStatement; 289 } 290 291 protected function getPreparedDeleteResultRecordStatement() 292 { 293 if (self::$preparedDeleteResultRecordStatement === null) { 294 self::$preparedDeleteResultRecordStatement = $this->db->prepareManip( 295 "DELETE FROM tst_test_result WHERE active_fi = ? AND question_fi = ? AND pass = ?", 296 array('integer', 'integer', 'integer') 297 ); 298 } 299 300 return self::$preparedDeleteResultRecordStatement; 301 } 302 303 protected function getPreparedSelectResultRecordStatement() 304 { 305 if (self::$preparedSelectResultRecordStatement === null) { 306 $query = " 307 SELECT points, manual, hint_count, hint_points, answered FROM tst_test_result 308 WHERE active_fi = ? AND question_fi = ? AND pass = ? 309 "; 310 311 self::$preparedSelectResultRecordStatement = $this->db->prepare( 312 $query, 313 array('integer', 'integer', 'integer') 314 ); 315 } 316 317 return self::$preparedSelectResultRecordStatement; 318 } 319 320 protected function getPreparedInsertResultRecordStatement() 321 { 322 if (self::$preparedInsertResultRecordStatement === null) { 323 $query = " 324 INSERT INTO tst_test_result ( 325 test_result_id, active_fi, question_fi, pass, tstamp, 326 points, manual, hint_count, hint_points, answered 327 ) VALUES ( 328 ?, ?, ?, ?, ?, ?, ?, ?, ?, ? 329 ) 330 "; 331 332 self::$preparedInsertResultRecordStatement = $this->db->prepareManip( 333 $query, 334 array('integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer') 335 ); 336 } 337 338 return self::$preparedInsertResultRecordStatement; 339 } 340} 341