From 7d3f4242baa1a4b8d73f62b2b4d5831053f63016 Mon Sep 17 00:00:00 2001 From: bheyser Date: Fri, 21 Aug 2015 09:24:50 +0200 Subject: [PATCH] lok3 #8 --- .../Test/classes/class.ilTestOutputGUI.php | 30 ++- Modules/Test/classes/class.ilTestSequence.php | 7 +- .../class.ilAssQuestionProcessLocker.php | 10 + .../class.ilAssQuestionProcessLockerDb.php | 23 +- .../class.ilAssQuestionProcessLockerFile.php | 16 +- ...class.ilAssQuestionUserSolutionAdopter.php | 241 ++++++++++++++++++ 6 files changed, 316 insertions(+), 11 deletions(-) create mode 100644 Modules/TestQuestionPool/classes/class.ilAssQuestionUserSolutionAdopter.php diff --git a/Modules/Test/classes/class.ilTestOutputGUI.php b/Modules/Test/classes/class.ilTestOutputGUI.php index 1f1bb56963d0..6cb5cd1df3be 100755 --- a/Modules/Test/classes/class.ilTestOutputGUI.php +++ b/Modules/Test/classes/class.ilTestOutputGUI.php @@ -324,10 +324,12 @@ protected function redirectQuestionCmd() $objectivesAdapter->notifyTestStart($this->testSession, $this->object->getId()); $objectivesAdapter->prepareTestPass($this->testSession, $this->testSequence); - - $objectivesAdapter->buildQuestionRelatedObjectiveList( - $this->questionRelatedObjectivesList - ); + $objectivesAdapter->buildQuestionRelatedObjectiveList($this->questionRelatedObjectivesList); + + if( $this->testSequence->hasOptionalQuestions() ) + { + $this->adoptUserSolutionsFromPreviousPass(); + } } $active_time_id = $this->object->startWorkingTime($this->testSession->getActiveId(), $this->testSession->getPass()); @@ -974,4 +976,24 @@ protected function performCustomRedirect() ilUtil::redirect($redirectTarget); } + + protected function adoptUserSolutionsFromPreviousPass() + { + global $ilDB, $ilUser; + + $assSettings = new ilSetting('assessment'); + + include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php"); + $isAssessmentLogEnabled = ilObjAssessmentFolder::_enabledAssessmentLogging(); + + require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionUserSolutionAdopter.php'; + $userSolutionAdopter = new ilAssQuestionUserSolutionAdopter($ilDB, $assSettings, $isAssessmentLogEnabled); + + $userSolutionAdopter->setUserId($ilUser->getId()); + $userSolutionAdopter->setActiveId($this->testSession->getActiveId()); + $userSolutionAdopter->setTargetPass($this->testSequence->getPass()); + $userSolutionAdopter->setQuestionIds($this->testSequence->getOptionalQuestions()); + + $userSolutionAdopter->perform(); + } } diff --git a/Modules/Test/classes/class.ilTestSequence.php b/Modules/Test/classes/class.ilTestSequence.php index ec8608bd70dd..357cb09753f1 100644 --- a/Modules/Test/classes/class.ilTestSequence.php +++ b/Modules/Test/classes/class.ilTestSequence.php @@ -707,7 +707,12 @@ public function hasOptionalQuestions() { return (bool)count($this->optionalQuestions); } - + + public function getOptionalQuestions() + { + return $this->optionalQuestions; + } + public function clearOptionalQuestions() { $this->optionalQuestions = array(); diff --git a/Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLocker.php b/Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLocker.php index af68e64a1ae7..4e2a23743874 100644 --- a/Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLocker.php +++ b/Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLocker.php @@ -58,4 +58,14 @@ public function releaseUserTestResultUpdateLock() { // overwrite method in concrete locker if something to do } + + public function requestUserSolutionAdoptLock() + { + // overwrite method in concrete locker if something to do + } + + public function releaseUserSolutionAdoptLock() + { + // overwrite method in concrete locker if something to do + } } \ No newline at end of file diff --git a/Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerDb.php b/Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerDb.php index 85ac29bbd612..0b5c67a1a013 100644 --- a/Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerDb.php +++ b/Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerDb.php @@ -46,13 +46,18 @@ private function getTablesUsedDuringAssessmentLog() array('name' => 'ass_log', 'type' => ilDB::LOCK_WRITE, 'sequence' => true) ); } - - public function requestUserSolutionUpdateLock() + + private function getTablesUsedDuringSolutionUpdate() { - $tables = array( + return array( array('name' => 'tst_solutions', 'type' => ilDB::LOCK_WRITE), array('name' => 'tst_solutions', 'type' => ilDB::LOCK_WRITE, 'sequence' => true) ); + } + + public function requestUserSolutionUpdateLock() + { + $tables = $this->getTablesUsedDuringSolutionUpdate(); if( $this->isAssessmentLogEnabled() ) { @@ -67,6 +72,18 @@ public function releaseUserSolutionUpdateLock() $this->db->unlockTables(); } + public function requestUserSolutionAdoptLock() + { + $this->db->lockTables( + $this->getTablesUsedDuringSolutionUpdate() + ); + } + + public function releaseUserSolutionAdoptLock() + { + $this->db->unlockTables(); + } + public function requestUserQuestionResultUpdateLock() { $this->db->lockTables(array( diff --git a/Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFile.php b/Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFile.php index c61503c0d33a..d97121bc7895 100644 --- a/Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFile.php +++ b/Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFile.php @@ -11,7 +11,7 @@ */ class ilAssQuestionProcessLockerFile extends ilAssQuestionProcessLocker { - const PROCESS_NAME_PERSIST_WORKING_STATE = 'persistWorkingState'; + const PROCESS_NAME_QUESTION_WORKING_STATE_UPDATE = 'questionWorkingStateUpdate'; /** * @var ilAssQuestionProcessLockFileStorage @@ -34,12 +34,22 @@ public function __construct(ilAssQuestionProcessLockFileStorage $lockFileStorage public function requestPersistWorkingStateLock() { - $this->requestLock(self::PROCESS_NAME_PERSIST_WORKING_STATE); + $this->requestLock(self::PROCESS_NAME_QUESTION_WORKING_STATE_UPDATE); } public function releasePersistWorkingStateLock() { - $this->releaseLock(self::PROCESS_NAME_PERSIST_WORKING_STATE); + $this->releaseLock(self::PROCESS_NAME_QUESTION_WORKING_STATE_UPDATE); + } + + public function requestUserSolutionAdoptLock() + { + $this->requestLock(self::PROCESS_NAME_QUESTION_WORKING_STATE_UPDATE); + } + + public function releaseUserSolutionAdoptLock() + { + $this->releaseLock(self::PROCESS_NAME_QUESTION_WORKING_STATE_UPDATE); } private function requestLock($processName) diff --git a/Modules/TestQuestionPool/classes/class.ilAssQuestionUserSolutionAdopter.php b/Modules/TestQuestionPool/classes/class.ilAssQuestionUserSolutionAdopter.php new file mode 100644 index 000000000000..79a1995659b7 --- /dev/null +++ b/Modules/TestQuestionPool/classes/class.ilAssQuestionUserSolutionAdopter.php @@ -0,0 +1,241 @@ + + * @version $Id$ + * + * @package Modules/TestQuestionPool + */ +class ilAssQuestionUserSolutionAdopter +{ + /** + * @var ressource + */ + protected static $preparedDeleteSolutionRecordsStatement = null; + + /** + * @var ressource + */ + protected static $preparedSelectSolutionRecordsStatement = null; + + /** + * @var ressource + */ + protected static $preparedInsertSolutionRecordStatement = null; + + /** + * @var ilDB + */ + protected $db; + + /** + * @var ilAssQuestionProcessLockerFactory + */ + protected $processLockerFactory; + + /** + * @var integer + */ + protected $userId; + + /** + * @var integer + */ + protected $activeId; + + /** + * @var integer + */ + protected $targetPass; + + /** + * @var array + */ + protected $questionIds; + + /** + * @param ilDB $db + * @param ilSetting $assSettings + * @param bool $isAssessmentLogEnabled + */ + public function __construct(ilDB $db, ilSetting $assSettings, $isAssessmentLogEnabled) + { + $this->db = $db; + + $this->userId = null; + $this->activeId = null; + $this->targetPass = null; + $this->questionIds = array(); + + require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php'; + $this->processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $db); + $this->processLockerFactory->setAssessmentLogEnabled($isAssessmentLogEnabled); + } + + /** + * @return int + */ + public function getUserId() + { + return $this->userId; + } + + /** + * @param int $userId + */ + public function setUserId($userId) + { + $this->userId = $userId; + } + + /** + * @return int + */ + public function getActiveId() + { + return $this->activeId; + } + + /** + * @param int $activeId + */ + public function setActiveId($activeId) + { + $this->activeId = $activeId; + } + + /** + * @return int + */ + public function getTargetPass() + { + return $this->targetPass; + } + + /** + * @param int $targetPass + */ + public function setTargetPass($targetPass) + { + $this->targetPass = $targetPass; + } + + /** + * @return array + */ + public function getQuestionIds() + { + return $this->questionIds; + } + + /** + * @param array $questionIds + */ + public function setQuestionIds($questionIds) + { + $this->questionIds = $questionIds; + } + + public function perform() + { + $this->processLockerFactory->setUserId($this->getUserId()); + + foreach($this->getQuestionIds() as $questionId) + { + $this->processLockerFactory->setQuestionId($questionId); + $processLocker = $this->processLockerFactory->getLocker(); + + $processLocker->requestUserSolutionAdoptLock(); + + $this->resetTargetSolution($questionId); + $this->adoptSourceSolution($questionId); + + $processLocker->releaseUserSolutionAdoptLock(); + } + } + + protected function resetTargetSolution($questionId) + { + $this->db->execute( + $this->getPreparedDeleteSolutionRecordsStatement(), + array($this->getActiveId(), $questionId, $this->getTargetPass()) + ); + } + + protected function adoptSourceSolution($questionId) + { + $res = $this->db->execute( + $this->getPreparedSelectSolutionRecordsStatement(), + array($this->getActiveId(), $questionId, $this->getTargetPass()) + ); + + $currentPass = null; + + while($row = $this->db->fetchAssoc($res)) + { + if($currentPass === null) + { + $currentPass = $row['pass']; + } + elseif($row['pass'] < $currentPass) + { + break; + } + + $solutionId = $this->db->nextId('tst_solutions'); + + $this->db->execute($this->getPreparedInsertSolutionRecordStatement(), array( + $solutionId, $this->getActiveId(), $questionId, $this->getTargetPass(), time(), + $row['points'], $row['value1'], $row['value2'] + )); + } + } + + protected function getPreparedDeleteSolutionRecordsStatement() + { + if( self::$preparedDeleteSolutionRecordsStatement === null ) + { + self::$preparedDeleteSolutionRecordsStatement = $this->db->prepareManip( + "DELETE FROM tst_solutions WHERE active_fi = ? AND question_fi = ? AND pass = ?", + array('integer', 'integer', 'integer') + ); + } + + return self::$preparedDeleteSolutionRecordsStatement; + } + + protected function getPreparedSelectSolutionRecordsStatement() + { + if( self::$preparedSelectSolutionRecordsStatement === null ) + { + self::$preparedSelectSolutionRecordsStatement = $this->db->prepare( + "SELECT FROM tst_solutions WHERE active_fi = ? AND question_fi = ? AND pass < ? ORDER BY pass DESC", + array('integer', 'integer', 'integer') + ); + } + + return self::$preparedSelectSolutionRecordsStatement; + } + + protected function getPreparedInsertSolutionRecordStatement() + { + if( self::$preparedInsertSolutionRecordStatement === null ) + { + $query = " + INSERT INTO tst_solutions ( + solution_id, active_fi, question_fi, pass, tstamp, points, value1, value2 + ) VALUES ( + ?, ?, ?, ?, ?, ?, ?, ? + ) + "; + + self::$preparedInsertSolutionRecordStatement = $this->db->prepareManip( + $query, array('integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'text', 'text') + ); + } + + return self::$preparedInsertSolutionRecordStatement; + } +} \ No newline at end of file