1<?php 2 3/** 4 * When a component wants to integrate the assessment question service to present questions 5 * to users in an assessment scenario, the following use cases needs to be handled by the component. 6 * 7 * This kind consume of the assessment question service does not support the offline export presentation yet. 8 */ 9class exTestPlayerGUI 10{ 11 /** 12 * When presenting an assessment question to a user, the ilAsqQuestionPresentation provides the 13 * interface methods to either get a renerable UI coponent for a question presentation or 14 * for a solution presentation. An instance implementing the ilAsqPresentation according to 15 * the given question type is provided by a factory method within ilAsqFactory. 16 * 17 * Both methods getQuestionPresentation and getSolutionPresentation gets an instance of ilAsqSolution injected. 18 * This solution can either be an user solution or the best solution. 19 * 20 * Additional interface methods in ilAsqQuestionPresentation return renderable UI components for the generic 21 * and specific feedbacks. These methods also need to get an ilAsqSolution instance injected. 22 * 23 * In case of presenting the best solution the required ilAsqSolution instance can be retrieved 24 * from the ilAsqQuestion interface. 25 * 26 * For any existing user response that is to be presented with the question the instance 27 * implementing ilAsqSolution can be requested from the ilAsqFactory using the solutionId 28 * that is to be registered within the consuming component in relation to the user's id 29 * and additional information (like e.g. test results). 30 * 31 * Variants in usage defined by the consumer: 32 * - question can be shown writable for the examine 33 * - question can be shown readable for the examine 34 * - feedbacks can be shown if required 35 * - best solution can be shown if required 36 */ 37 public function showQuestion() 38 { 39 global $DIC; /* @var ILIAS\DI\Container $DIC */ 40 41 $questionId = 0; // initialise with id of question to be shown 42 43 /** 44 * fetch possibly existing participant solution, an empty one is required otherwise 45 */ 46 47 $participantSolution = $this->getParticipantSolution($questionId); 48 49 /** 50 * question presentation to be answered by the examine 51 */ 52 53 $questionInstance = $DIC->question()->getQuestionInstance($questionId); 54 $questionPresentationGUI = $DIC->question()->getQuestionPresentationInstance($questionInstance); 55 56 $questionNavigationAware; /* @var ilAsqQuestionNavigationAware $questionNavigationAware */ 57 $questionPresentationGUI->setQuestionNavigation($questionNavigationAware); 58 59 $questionPresentationGUI->setRenderPurpose(ilAsqQuestionPresentation::RENDER_PURPOSE_PLAYBACK); 60 61 if ($participantSolutionLocked = false) { 62 $renderer = $questionPresentationGUI->getSolutionPresentation($participantSolution); 63 } else { 64 $renderer = $questionPresentationGUI->getQuestionPresentation($participantSolution); 65 } 66 67 $playerQstPageHTML = $renderer->getContent(); 68 69 /** 70 * feedback presentation for the given 71 */ 72 73 if ($showFeedbacks = true && !$participantSolution->isEmpty()) { 74 $genericFeedbackRenderer = $questionPresentationGUI->getGenericFeedbackOutput($participantSolution); 75 $playerQstPageHTML .= $genericFeedbackRenderer->getContent(); 76 77 $specificFeedbackRenderer = $questionPresentationGUI->getSpecificFeedbackOutput($participantSolution); 78 $playerQstPageHTML .= $specificFeedbackRenderer->getContent(); 79 } 80 81 /** 82 * best solution presentation to be answered by the examine 83 */ 84 85 if ($showBestSolution = true) { 86 $renderer = $questionPresentationGUI->getSolutionPresentation( 87 $questionInstance->getBestSolution() 88 ); 89 90 $playerQstPageHTML .= $renderer->getContent(); 91 } 92 93 $playerQstPageHTML; // complete question page html 94 } 95 96 /** 97 * With the presentation of an assessment question, this question also gets submitted having any solution 98 * filled out by any user. With the first presentation there should be no previous user response available. 99 * The consuming component needs to request an empty ilAsqSolution instance for the given questionId. 100 * 101 * The ilAsqSolution interface method initFromServerRequest is to be used to initialize the object instance 102 * with the user response. With the current concept the newly introduced \Psr\Http\Message\ServerRequestInterface 103 * needs to be injected to this method, but may simply passing $_POST could be an alternative. 104 * This depends on the future strategy of abstracting the http server request in ILIAS. 105 * 106 * After having this solution saved, the consuming component needs to register the now available solutionId 107 * together with the questionId and the userId. Additionally this ilAsqSolution instance can be used 108 * with a question corresponding ilAsqResultCalculator to retrieve the information about right/wrong 109 * (used for e.g. answer status in CTM's test sequence) and reached points (used as a future ilTestResult) 110 * to be stored as any result within the consuming component. 111 * 112 * After the first submission of any user response the consuming component needs to provide the corresponsing 113 * solutionId to request the existing ilAsqSolution instance from the ilAsqFactory for every additional submit. 114 * 115 * The way harvesting and handling solution data in short: 116 * - post submit gets parsed by ilAsqSolution 117 * - ilAsqResultCalculator calculates points and right/wrong 118 * - the test object can use these information for different purposes 119 * - points can be saved as an ilTestResult referenced by the questionId and the participantId 120 * - right/wrong can be used for determining the correct feedbacks for the feedback loop 121 * - right/wrong can be used as the answer status within the CTM test sequence 122 */ 123 public function submitSolution() 124 { 125 global $DIC; /* @var ILIAS\DI\Container $DIC */ 126 127 // this can also be $_REQUEST or any other future ilias post-request handler 128 $serverRequestObject; /* @var \Psr\Http\Message\ServerRequestInterface $serverRequestObject */ 129 130 $questionId = 0; // initialise with id of question that just submits 131 132 /** 133 * fetch possibly existing participant solution, an empty one is required otherwise 134 */ 135 136 $participantSolution = $this->getParticipantSolution($questionId); 137 138 /** 139 * let the solution object instance harvest the submission post data 140 */ 141 142 $participantSolution->initFromServerRequest($serverRequestObject); 143 144 /** 145 * get results calculator to be used to retrieve calculated reached points 146 * that can be stored in a test result storage managed by the test object 147 */ 148 149 $questionInstance = $DIC->question()->getQuestionInstance($questionId); 150 $solutionInstance = $this->getParticipantSolution($questionId); 151 $resultCalculator = $DIC->question()->getResultCalculator($questionInstance, $solutionInstance); 152 153 $resultInstance = $resultCalculator->calculate(); 154 155 /** 156 * handle the calculated result in any kind 157 */ 158 159 // can be stored in any ilTestResult object managed by the test 160 $reachedPoints = $resultInstance->getPoints(); 161 162 // can be used to differ answer status in CTM's test sequence 163 $isCorrect = $resultInstance->isCorrect(); 164 } 165 166 /** 167 * this method returns either an initialised solution object instance, or and empty one, 168 * depending on self managed test results (handled by a future ilTestResult) 169 * 170 * @param integer $questionId 171 * @return ilAsqQuestionSolution 172 */ 173 public function getParticipantSolution($questionId) 174 { 175 global $DIC; /* @var ILIAS\DI\Container $DIC */ 176 177 /** 178 * when the test has any test result based on an existing participant solution, 179 * the solution id needs to be looked up. an empty solution is returned otherwise. 180 */ 181 182 $solutionId = 0; 183 184 if ($solutionId) { 185 return $DIC->question()->getQuestionSolutionInstance($questionId, $solutionId); 186 } 187 188 return $DIC->question()->getEmptyQuestionSolutionInstance($questionId); 189 } 190} 191