From f7875c931fefa12d8250c52b4ea03c91accc0798 Mon Sep 17 00:00:00 2001 From: Karol Stelmaczonek Date: Mon, 8 Jan 2024 14:03:51 +0100 Subject: [PATCH] Bugfix/inf 248 not send ags with outcome processing set to none (#2435) * bugfix: move event to proper delivery finish * bugfix: code review fixes * fix: code check (cherry picked from commit d87be4b6df8b7262b3ccfa7bca846a046f33871f) --- helpers/class.TestSession.php | 5 +- ...corded.php => DeliveryExecutionFinish.php} | 13 +- .../ResultTestVariablesTransmissionEvent.php | 11 +- .../ResultTransmissionEventHandler.php | 73 +- models/classes/runner/QtiRunnerService.php | 627 +++++++++--------- 5 files changed, 317 insertions(+), 412 deletions(-) rename models/classes/event/{TestVariablesRecorded.php => DeliveryExecutionFinish.php} (79%) diff --git a/helpers/class.TestSession.php b/helpers/class.TestSession.php index 79951097c1..bde2038fa5 100644 --- a/helpers/class.TestSession.php +++ b/helpers/class.TestSession.php @@ -773,12 +773,11 @@ private function triggerResultTestVariablesTransmissionEvent( $this->getSessionId(), $variables, $this->getSessionId(), - $testUri, - $this->isManualScored() + $testUri )); } - private function isManualScored(): bool + public function isManualScored(): bool { /** @var AssessmentItemRef $itemRef */ foreach ($this->getRoute()->getAssessmentItemRefs() as $itemRef) { diff --git a/models/classes/event/TestVariablesRecorded.php b/models/classes/event/DeliveryExecutionFinish.php similarity index 79% rename from models/classes/event/TestVariablesRecorded.php rename to models/classes/event/DeliveryExecutionFinish.php index 6f8c39e3cc..03afd7836e 100644 --- a/models/classes/event/TestVariablesRecorded.php +++ b/models/classes/event/DeliveryExecutionFinish.php @@ -23,19 +23,20 @@ namespace oat\taoQtiTest\models\event; use oat\oatbox\event\Event; +use oat\taoDelivery\model\execution\DeliveryExecution; -class TestVariablesRecorded implements Event +class DeliveryExecutionFinish implements Event { - private string $deliveryExecutionId; + private DeliveryExecution $deliveryExecution; private array $variables; private bool $isManualScored; public function __construct( - string $deliveryExecutionId, + DeliveryExecution $deliveryExecution, array $variables, bool $isManualScored ) { - $this->deliveryExecutionId = $deliveryExecutionId; + $this->deliveryExecution = $deliveryExecution; $this->variables = $variables; $this->isManualScored = $isManualScored; } @@ -45,9 +46,9 @@ public function getName(): string return self::class; } - public function getDeliveryExecutionId(): string + public function getDeliveryExecution(): DeliveryExecution { - return $this->deliveryExecutionId; + return $this->deliveryExecution; } public function getVariables(): array diff --git a/models/classes/event/ResultTestVariablesTransmissionEvent.php b/models/classes/event/ResultTestVariablesTransmissionEvent.php index 51ba39b1a4..315f98d340 100644 --- a/models/classes/event/ResultTestVariablesTransmissionEvent.php +++ b/models/classes/event/ResultTestVariablesTransmissionEvent.php @@ -34,21 +34,17 @@ class ResultTestVariablesTransmissionEvent implements Event private $transmissionId; /** @var string */ private $testUri; - /** @var bool */ - private bool $isManualScored; public function __construct( string $deliveryExecutionId, array $variables, string $transmissionId, - string $testUri = '', - bool $isManualScored = null, + string $testUri = '' ) { $this->deliveryExecutionId = $deliveryExecutionId; $this->variables = $variables; $this->transmissionId = $transmissionId; $this->testUri = $testUri; - $this->isManualScored = $isManualScored; } public function getName(): string @@ -75,9 +71,4 @@ public function getTestUri(): string { return $this->testUri; } - - public function isManualScored(): bool - { - return $this->isManualScored; - } } diff --git a/models/classes/eventHandler/ResultTransmissionEventHandler/ResultTransmissionEventHandler.php b/models/classes/eventHandler/ResultTransmissionEventHandler/ResultTransmissionEventHandler.php index e0264f7814..d2a59bdc32 100644 --- a/models/classes/eventHandler/ResultTransmissionEventHandler/ResultTransmissionEventHandler.php +++ b/models/classes/eventHandler/ResultTransmissionEventHandler/ResultTransmissionEventHandler.php @@ -22,19 +22,13 @@ namespace oat\taoQtiTest\models\classes\eventHandler\ResultTransmissionEventHandler; -use common_exception_Error; -use oat\oatbox\event\EventManager; -use oat\oatbox\service\ServiceManager; use oat\oatbox\service\ServiceNotFoundException; use oat\tao\model\service\InjectionAwareService; use oat\taoDelivery\model\execution\DeliveryServerService; use oat\taoQtiTest\models\classes\event\ResultTestVariablesTransmissionEvent; use oat\taoQtiTest\models\event\ResultItemVariablesTransmissionEvent; -use oat\taoQtiTest\models\event\TestVariablesRecorded; use taoQtiCommon_helpers_ResultTransmitter; use oat\oatbox\service\exception\InvalidServiceManagerException; -use oat\taoResultServer\models\classes\implementation\ResultServerService; -use taoResultServer_models_classes_ReadableResultStorage as ReadableResultStorage; class ResultTransmissionEventHandler extends InjectionAwareService implements Api\ResultTransmissionEventHandlerInterface { @@ -55,6 +49,7 @@ public function transmitResultItemVariable(ResultItemVariablesTransmissionEvent /** * @param ResultTestVariablesTransmissionEvent $event * @throws InvalidServiceManagerException + * @throws ServiceNotFoundException * @throws \taoQtiCommon_helpers_ResultTransmissionException */ public function transmitResultTestVariable(ResultTestVariablesTransmissionEvent $event): void @@ -64,14 +59,14 @@ public function transmitResultTestVariable(ResultTestVariablesTransmissionEvent $event->getTransmissionId(), $event->getTestUri() ); - - if (!$this->containsScoreTotal($event)) { - return; - } - - $this->triggerTestVariablesRecorded($event); } + /** + * @param $deliveryExecutionIdigcicd + * @return taoQtiCommon_helpers_ResultTransmitter + * @throws InvalidServiceManagerException + * @throws \oat\oatbox\service\ServiceNotFoundException + */ private function buildTransmitter($deliveryExecutionId): taoQtiCommon_helpers_ResultTransmitter { /** @var DeliveryServerService $deliveryServerService */ @@ -80,58 +75,4 @@ private function buildTransmitter($deliveryExecutionId): taoQtiCommon_helpers_Re return new taoQtiCommon_helpers_ResultTransmitter($resultStore); } - - public function getEventManager() - { - return $this->getServiceLocator()->get(EventManager::SERVICE_ID); - } - - public function getServiceLocator() - { - return ServiceManager::getServiceManager(); - } - - /** - * @return ReadableResultStorage - * @throws ServiceNotFoundException - * @throws common_exception_Error - */ - private function getResultsStorage(): ReadableResultStorage - { - $resultServerService = $this->getServiceLocator()->get(ResultServerService::SERVICE_ID); - $storage = $resultServerService->getResultStorage(); - - if (!$storage instanceof ReadableResultStorage) { - throw new common_exception_Error('Configured result storage is not writable.'); - } - - return $storage; - } - - private function containsScoreTotal(ResultTestVariablesTransmissionEvent $event): bool - { - $scoreTotal = array_filter( - $event->getVariables(), - function ($item) { - return $item->getIdentifier() === 'SCORE_TOTAL'; - } - ); - - return !empty($scoreTotal); - } - - /** - * @param ResultTestVariablesTransmissionEvent $event - * @return void - * @throws InvalidServiceManagerException - */ - private function triggerTestVariablesRecorded(ResultTestVariablesTransmissionEvent $event): void - { - $outcomeVariables = $this->getResultsStorage()->getDeliveryVariables($event->getDeliveryExecutionId()); - $this->getEventManager()->trigger(new TestVariablesRecorded( - $event->getDeliveryExecutionId(), - $outcomeVariables, - $event->isManualScored() - )); - } } diff --git a/models/classes/runner/QtiRunnerService.php b/models/classes/runner/QtiRunnerService.php index 23e141a0f5..29754ca0b3 100644 --- a/models/classes/runner/QtiRunnerService.php +++ b/models/classes/runner/QtiRunnerService.php @@ -15,31 +15,38 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Copyright (c) 2016-2022 (original work) Open Assessment Technologies SA ; - */ - -/** - * @author Jean-Sébastien Conan + * Copyright (c) 2016-2023 (original work) Open Assessment Technologies SA. */ namespace oat\taoQtiTest\models\runner; +use common_Exception; +use common_exception_Error; +use common_exception_InconsistentData; use common_exception_InvalidArgumentType as InvalidArgumentTypeException; +use common_exception_NotImplemented; +use common_ext_ExtensionException; +use common_ext_ExtensionsManager; +use common_Logger; use common_persistence_AdvKeyValuePersistence; use common_persistence_KeyValuePersistence; +use common_session_SessionManager; +use Exception; use League\Flysystem\FileNotFoundException; use oat\libCat\result\ItemResult; use oat\libCat\result\ResultVariable; use oat\oatbox\event\EventManager; use oat\oatbox\service\ConfigurableService; +use oat\oatbox\service\exception\InvalidServiceManagerException; use oat\tao\model\featureFlag\FeatureFlagChecker; use oat\tao\model\featureFlag\FeatureFlagCheckerInterface; use oat\tao\model\theme\ThemeService; use oat\taoDelivery\model\execution\Delete\DeliveryExecutionDeleteRequest; use oat\taoDelivery\model\execution\DeliveryExecution; use oat\taoDelivery\model\execution\DeliveryServerService; -use oat\taoDelivery\model\execution\ServiceProxy; +use oat\taoDelivery\model\execution\ServiceProxy as TaoDeliveryServiceProxy; use oat\taoDelivery\model\RuntimeService; +use oat\taoOutcomeRds\model\RdsResultStorage; use oat\taoQtiItem\model\portableElement\exception\PortableElementNotFoundException; use oat\taoQtiItem\model\portableElement\exception\PortableModelMissing; use oat\taoQtiItem\model\portableElement\PortableElementService; @@ -51,6 +58,7 @@ use oat\taoQtiTest\models\event\TestExitEvent; use oat\taoQtiTest\models\event\TestInitEvent; use oat\taoQtiTest\models\event\TestTimeoutEvent; +use oat\taoQtiTest\models\event\DeliveryExecutionFinish; use oat\taoQtiTest\models\ExtendedStateService; use oat\taoQtiTest\models\files\QtiFlysystemFileManager; use oat\taoQtiTest\models\render\UpdateItemContentReferencesService; @@ -62,24 +70,35 @@ use oat\taoQtiTest\models\runner\session\TestSession; use oat\taoQtiTest\models\runner\toolsStates\ToolsStateStorage; use oat\taoQtiTest\models\TestSessionService; +use oat\taoResultServer\models\classes\implementation\ResultServerService; +use qtism\common\datatypes\QtiInteger; use qtism\common\datatypes\QtiString as QtismString; use qtism\common\enums\BaseType; use qtism\common\enums\Cardinality; use qtism\data\AssessmentItemRef; use qtism\data\NavigationMode; +use qtism\data\storage\php\PhpStorageException; use qtism\data\SubmissionMode; use qtism\runtime\common\ResponseVariable; use qtism\runtime\common\State; use qtism\runtime\common\Utils; use qtism\runtime\tests\AssessmentItemSession; +use qtism\runtime\tests\AssessmentItemSessionException; use qtism\runtime\tests\AssessmentItemSessionState; use qtism\runtime\tests\AssessmentTestSession; use qtism\runtime\tests\AssessmentTestSessionException; use qtism\runtime\tests\AssessmentTestSessionState; use qtism\runtime\tests\RouteItem; use qtism\runtime\tests\SessionManager; +use tao_models_classes_FileNotFoundException; use tao_models_classes_service_StateStorage; +use taoQtiCommon_helpers_PciStateOutput; +use taoQtiCommon_helpers_PciVariableFiller; +use taoQtiCommon_helpers_ResultTransmissionException; +use taoQtiCommon_helpers_ResultTransmitter; use taoQtiTest_helpers_TestRunnerUtils as TestRunnerUtils; +use taoResultServer_models_classes_TraceVariable; +use taoResultServer_models_classes_Variable; /** * Class QtiRunnerService @@ -87,6 +106,7 @@ * QTI implementation service for the test runner * * @package oat\taoQtiTest\models + * @author Jean-Sébastien Conan */ class QtiRunnerService extends ConfigurableService implements PersistableRunnerServiceInterface, RunnerService { @@ -95,7 +115,7 @@ class QtiRunnerService extends ConfigurableService implements PersistableRunnerS /** * @deprecated use SERVICE_ID */ - public const CONFIG_ID = 'taoQtiTest/QtiRunnerService'; + public const CONFIG_ID = self::SERVICE_ID; public const TOOL_ITEM_THEME_SWITCHER = 'itemThemeSwitcher'; public const TOOL_ITEM_THEME_SWITCHER_KEY = 'taoQtiTest/runner/plugins/tools/itemThemeSwitcher/itemThemeSwitcher'; @@ -109,21 +129,19 @@ class QtiRunnerService extends ConfigurableService implements PersistableRunnerS /** * The test runner config - * @var RunnerConfig */ - protected $testConfig; + protected ?RunnerConfig $testConfig = null; /** * Use to store retrieved item data, inside the same request - * @var array */ - private $dataCache = []; + private array $dataCache = []; /** * Get the data folder from a given item definition * @param string $itemRef - formatted as itemURI|publicFolderURI|privateFolderURI * @return array the path - * @throws \common_Exception + * @throws common_Exception */ private function loadItemData($itemRef, $path) { @@ -142,22 +160,24 @@ private function loadItemData($itemRef, $path) $itemRefInfo = gettype($itemRef); } - throw new \common_exception_InconsistentData("The itemRef (value = '${itemRefInfo}') is not formatted correctly."); + throw new common_exception_InconsistentData( + "The itemRef (value = '${itemRefInfo}') is not formatted correctly." + ); } $itemUri = $directoryIds[0]; - $userDataLang = \common_session_SessionManager::getSession()->getDataLanguage(); + $userDataLang = common_session_SessionManager::getSession()->getDataLanguage(); $directory = \tao_models_classes_service_FileStorage::singleton()->getDirectoryById($directoryIds[2]); if ($directory->has($userDataLang)) { $lang = $userDataLang; } elseif ($directory->has(DEFAULT_LANG)) { - \common_Logger::d( + common_Logger::d( $userDataLang . ' is not part of compilation directory for item : ' . $itemUri . ' use ' . DEFAULT_LANG ); $lang = DEFAULT_LANG; } else { - throw new \common_Exception( + throw new common_Exception( 'item : ' . $itemUri . 'is neither compiled in ' . $userDataLang . ' nor in ' . DEFAULT_LANG ); } @@ -168,7 +188,7 @@ private function loadItemData($itemRef, $path) $this->dataCache[$cacheKey] = $jsonContent; return $this->dataCache[$cacheKey]; } catch (FileNotFoundException $e) { - throw new \tao_models_classes_FileNotFoundException( + throw new tao_models_classes_FileNotFoundException( $path . ' for item reference ' . $itemRef ); } @@ -184,7 +204,7 @@ private function loadItemData($itemRef, $path) * @param string $testExecutionUri The URI of the delivery execution * @param string $userUri User identifier. If null current user will be used * @return QtiRunnerServiceContext - * @throws \common_Exception + * @throws common_Exception */ public function getServiceContext($testDefinitionUri, $testCompilationUri, $testExecutionUri, $userUri = null) { @@ -209,7 +229,7 @@ public function getServiceContext($testDefinitionUri, $testCompilationUri, $test * Checks the created context, then initializes it. * @param RunnerServiceContext $context * @return RunnerServiceContext - * @throws \common_Exception + * @throws common_Exception */ public function initServiceContext(RunnerServiceContext $context) { @@ -231,14 +251,14 @@ public function persist(RunnerServiceContext $serviceContext): void $testSession = $serviceContext->getTestSession(); $sessionId = $testSession->getSessionId(); - \common_Logger::d("Persisting QTI Assessment Test Session '${sessionId}'..."); + $this->getLogger()->debug("Persisting QTI Assessment Test Session '${sessionId}'..."); $serviceContext->getStorage()->persist($testSession); if ($this->isTerminated($serviceContext)) { /** @var StorageManager $storageManager */ $storageManager = $this->getServiceManager()->get(StorageManager::SERVICE_ID); $storageManager->persist(); - $userId = \common_session_SessionManager::getSession()->getUser()->getIdentifier(); + $userId = common_session_SessionManager::getSession()->getUser()->getIdentifier(); $eventManager = $this->getServiceManager()->get(EventManager::SERVICE_ID); $eventManager->trigger(new AfterAssessmentTestSessionClosedEvent($testSession, $userId)); } @@ -255,19 +275,11 @@ public function persist(RunnerServiceContext $serviceContext): void * * @param RunnerServiceContext $context * @return boolean - * @throws \common_Exception + * @throws common_Exception */ public function init(RunnerServiceContext $context) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'init', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'init'); /* @var TestSession $session */ $session = $context->getTestSession(); @@ -278,10 +290,13 @@ public function init(RunnerServiceContext $context) $session->beginTestSession(); $event = new TestInitEvent($session); $this->getServiceManager()->get(EventManager::SERVICE_ID)->trigger($event); - \common_Logger::i(sprintf('Assessment Test Session begun. Session id: %s', $session->getSessionId())); + + $this->getLogger()->info( + sprintf('Assessment Test Session begun. Session id: %s', $session->getSessionId()) + ); if ($context->isAdaptive()) { - \common_Logger::t("Very first item is adaptive."); + $this->getLogger()->debug("Very first item is adaptive."); $nextCatItemId = $context->selectAdaptiveNextItem(); $context->persistCurrentCatItemId($nextCatItemId); $context->persistSeenCatItemIds($nextCatItemId); @@ -303,13 +318,14 @@ public function init(RunnerServiceContext $context) /** * Gets the test runner config * @return RunnerConfig - * @throws \common_ext_ExtensionException + * @throws common_ext_ExtensionException */ public function getTestConfig() { - if (is_null($this->testConfig)) { + if ($this->testConfig === null) { $this->testConfig = $this->getServiceManager()->get(QtiRunnerConfig::SERVICE_ID); } + return $this->testConfig; } @@ -321,19 +337,11 @@ public function getTestConfig() * * @param RunnerServiceContext $context * @return array - * @throws \common_Exception + * @throws common_Exception */ public function getTestData(RunnerServiceContext $context) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'getTestData', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'getTestData'); $testDefinition = $context->getTestDefinition(); @@ -400,19 +408,11 @@ public function getTestData(RunnerServiceContext $context) * Gets the test context object * @param RunnerServiceContext $context * @return array - * @throws \common_Exception + * @throws common_Exception */ public function getTestContext(RunnerServiceContext $context) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'getTestContext', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'getTestContext'); /* @var TestSession $session */ $session = $context->getTestSession(); @@ -435,8 +435,12 @@ public function getTestContext(RunnerServiceContext $context) $itemRef = $context->getCurrentAssessmentItemRef(); $reviewConfig = $config->getConfigValue('review'); - $displaySubsectionTitle = isset($reviewConfig['displaySubsectionTitle']) ? (bool) $reviewConfig['displaySubsectionTitle'] : true; - $partiallyAnsweredIsAnswered = isset($reviewConfig['partiallyAnsweredIsAnswered']) ? (bool) $reviewConfig['partiallyAnsweredIsAnswered'] : true; + $displaySubsectionTitle = isset($reviewConfig['displaySubsectionTitle']) + ? (bool) $reviewConfig['displaySubsectionTitle'] + : true; + $partiallyAnsweredIsAnswered = isset($reviewConfig['partiallyAnsweredIsAnswered']) + ? (bool) $reviewConfig['partiallyAnsweredIsAnswered'] + : true; if ($displaySubsectionTitle) { $currentSection = $session->getCurrentAssessmentSection(); @@ -464,7 +468,9 @@ public function getTestContext(RunnerServiceContext $context) $response['itemIdentifier'] = $itemRef->getIdentifier(); // The number of current attempt (1 for the first time ...) - $response['attempt'] = ($context->isAdaptive()) ? $context->getCatAttempts($response['itemIdentifier']) + 1 : $itemSession['numAttempts']->getValue(); + $response['attempt'] = ($context->isAdaptive()) + ? $context->getCatAttempts($response['itemIdentifier']) + 1 + : $itemSession['numAttempts']->getValue(); // The state of the current AssessmentTestSession. $response['itemSessionState'] = $itemSession->getState(); @@ -489,7 +495,12 @@ public function getTestContext(RunnerServiceContext $context) $response['itemFlagged'] = TestRunnerUtils::getItemFlag($session, $response['itemPosition'], $context); // The current item answered state - $response['itemAnswered'] = $this->isItemCompleted($context, $currentItem, $itemSession, $partiallyAnsweredIsAnswered); + $response['itemAnswered'] = $this->isItemCompleted( + $context, + $currentItem, + $itemSession, + $partiallyAnsweredIsAnswered + ); // Time constraints. $response['timeConstraints'] = $this->buildTimeConstraints($context); @@ -511,7 +522,11 @@ public function getTestContext(RunnerServiceContext $context) $response['numberPresented'] = $session->numberPresented(); // Whether or not the progress of the test can be inferred. - $response['considerProgress'] = TestRunnerUtils::considerProgress($session, $context->getTestMeta(), $config->getConfig()); + $response['considerProgress'] = TestRunnerUtils::considerProgress( + $session, + $context->getTestMeta(), + $config->getConfig() + ); // Whether or not the deepest current section is visible. $response['isDeepestSectionVisible'] = $currentSection->isVisible(); @@ -554,19 +569,11 @@ public function getTestContext(RunnerServiceContext $context) * @param RunnerServiceContext $context * @param bool $partial the full testMap or only the current section * @return array - * @throws \common_Exception + * @throws common_Exception */ public function getTestMap(RunnerServiceContext $context, $partial = false) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'getTestMap', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'getTestMap'); $mapService = $this->getServiceLocator()->get(QtiRunnerMap::SERVICE_ID); @@ -582,19 +589,11 @@ public function getTestMap(RunnerServiceContext $context, $partial = false) * @param RunnerServiceContext $context * @param AssessmentItemRef $itemRef (optional) otherwise use the current * @return mixed - * @throws \common_Exception + * @throws common_Exception */ public function getRubrics(RunnerServiceContext $context, AssessmentItemRef $itemRef = null) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'getRubrics', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'getRubrics'); $rubricHelper = $this->getServiceLocator()->get(QtiRunnerRubric::SERVICE_ID); return $rubricHelper->getRubrics($context, $itemRef); @@ -617,19 +616,11 @@ public function getItemHref(RunnerServiceContext $context, string $itemRef): str * @param RunnerServiceContext $context * @param $itemRef * @return mixed - * @throws \common_Exception + * @throws common_Exception */ public function getItemData(RunnerServiceContext $context, $itemRef) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'getItemData', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'getItemData'); return $this->loadItemData($itemRef, QtiJsonItemCompiler::ITEM_FILE_NAME); } @@ -660,29 +651,21 @@ private function buildStorageItemKey($deliveryExecutionUri, $itemRef) * @param RunnerServiceContext $context * @param string $itemRef * @return array|null - * @throws \common_Exception + * @throws common_Exception */ public function getItemState(RunnerServiceContext $context, $itemRef) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'getItemState', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'getItemState'); $serviceService = $this->getServiceManager()->get(StorageManager::SERVICE_ID); - $userUri = \common_session_SessionManager::getSession()->getUserUri(); + $userUri = common_session_SessionManager::getSession()->getUserUri(); $stateId = $this->getStateId($context, $itemRef); $state = is_null($userUri) ? null : $serviceService->get($userUri, $stateId); if ($state) { $state = json_decode($state, true); if (is_null($state)) { - throw new \common_exception_InconsistentData('Unable to decode the state for the item ' . $itemRef); + throw new common_exception_InconsistentData('Unable to decode the state for the item ' . $itemRef); } } @@ -695,22 +678,14 @@ public function getItemState(RunnerServiceContext $context, $itemRef) * @param $itemRef * @param $state * @return boolean - * @throws \common_Exception + * @throws common_Exception */ public function setItemState(RunnerServiceContext $context, $itemRef, $state) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'setItemState', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'setItemState'); $serviceService = $this->getServiceManager()->get(StorageManager::SERVICE_ID); - $userUri = \common_session_SessionManager::getSession()->getUserUri(); + $userUri = common_session_SessionManager::getSession()->getUserUri(); $stateId = $this->getStateId($context, $itemRef); if (!isset($state)) { $state = ''; @@ -722,7 +697,7 @@ public function setItemState(RunnerServiceContext $context, $itemRef, $state) /** * @param RunnerServiceContext $context * @param $toolStates - * @throws \oat\oatbox\service\exception\InvalidServiceManagerException + * @throws InvalidServiceManagerException */ public function setToolsStates(RunnerServiceContext $context, $toolStates) { @@ -737,8 +712,8 @@ public function setToolsStates(RunnerServiceContext $context, $toolStates) /** * @param RunnerServiceContext $context * @return array - * @throws \oat\oatbox\service\exception\InvalidServiceManagerException - * @throws \common_ext_ExtensionException + * @throws InvalidServiceManagerException + * @throws common_ext_ExtensionException */ public function getToolsStates(RunnerServiceContext $context) { @@ -750,6 +725,7 @@ public function getToolsStates(RunnerServiceContext $context) if (count($toolsEnabled) === 0) { return []; } + if ($context instanceof QtiRunnerServiceContext) { /** @var ToolsStateStorage $toolsStateStorage */ $toolsStateStorage = $this->getServiceLocator()->get(ToolsStateStorage::SERVICE_ID); @@ -771,19 +747,11 @@ public function getToolsStates(RunnerServiceContext $context) * @param $itemRef * @param $response * @return mixed - * @throws \common_Exception + * @throws common_Exception */ public function parsesItemResponse(RunnerServiceContext $context, $itemRef, $response) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'storeItemResponse', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'storeItemResponse'); /** @var TestSession $session */ $session = $context->getTestSession(); @@ -795,10 +763,10 @@ public function parsesItemResponse(RunnerServiceContext $context, $itemRef, $res $msg .= "Session state value: " . $session->getState() . "\n"; $msg .= "Session ID: " . $session->getSessionId() . "\n"; $msg .= "JSON Payload: " . mb_substr(json_encode($response), 0, 1000); - \common_Logger::e($msg); + $this->getLogger()->error($msg); } - $filler = new \taoQtiCommon_helpers_PciVariableFiller( + $filler = new taoQtiCommon_helpers_PciVariableFiller( $currentItem, $this->getServiceManager()->get(QtiFlysystemFileManager::SERVICE_ID) ); @@ -812,13 +780,13 @@ public function parsesItemResponse(RunnerServiceContext $context, $itemRef, $res $responses->setVariable($var); } } catch (\OutOfRangeException $e) { - \common_Logger::d("Could not convert client-side value for variable '${id}'."); + $this->getLogger()->debug("Could not convert client-side value for variable '${id}'."); } catch (\OutOfBoundsException $e) { - \common_Logger::d("Could not find variable with identifier '${id}' in current item."); + $this->getLogger()->debug("Could not find variable with identifier '${id}' in current item."); } } } else { - \common_Logger::e('Invalid json payload'); + $this->getLogger()->error('Invalid json payload'); } return $responses; @@ -829,19 +797,11 @@ public function parsesItemResponse(RunnerServiceContext $context, $itemRef, $res * @param RunnerServiceContext $context * @param $responses * @return mixed - * @throws \common_Exception + * @throws common_Exception */ public function emptyResponse(RunnerServiceContext $context, $responses) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'storeItemResponse', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'storeItemResponse'); $similar = 0; @@ -871,24 +831,19 @@ public function emptyResponse(RunnerServiceContext $context, $responses) * @param $itemRef * @param $responses * @return boolean - * @throws \common_Exception + * @throws InvalidArgumentTypeException + * @throws PhpStorageException + * @throws AssessmentItemSessionException + * @throws taoQtiCommon_helpers_ResultTransmissionException */ public function storeItemResponse(RunnerServiceContext $context, $itemRef, $responses) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'storeItemResponse', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'storeItemResponse'); $session = $this->getCurrentAssessmentSession($context); try { - \common_Logger::t('Responses sent from the client-side. The Response Processing will take place.'); + common_Logger::t('Responses sent from the client-side. The Response Processing will take place.'); if ($context->isAdaptive()) { $session->beginItemSession(); @@ -913,13 +868,18 @@ public function storeItemResponse(RunnerServiceContext $context, $itemRef, $resp microtime(true) ); } else { - \common_Logger::i("No 'SCORE' outcome variable for item '${assessmentItemIdentifier}' involved in an adaptive section."); + common_Logger::i( + "No 'SCORE' outcome variable for item '${assessmentItemIdentifier}' involved in an " + . "adaptive section." + ); } $context->persistLastCatItemOutput($output); // Send results to TAO Results. - $resultTransmitter = new \taoQtiCommon_helpers_ResultTransmitter($context->getSessionManager()->getResultServer()); + $resultTransmitter = new taoQtiCommon_helpers_ResultTransmitter( + $context->getSessionManager()->getResultServer() + ); $hrefParts = explode('|', $assessmentItem->getHref()); $sessionId = $context->getTestSession()->getSessionId(); @@ -933,7 +893,7 @@ public function storeItemResponse(RunnerServiceContext $context, $itemRef, $resp foreach ($session->getAllVariables() as $var) { if ($var->getIdentifier() === 'numAttempts') { - $var->setValue(new \qtism\common\datatypes\QtiInteger($attempt)); + $var->setValue(new QtiInteger($attempt)); } $variables[] = $var; @@ -950,7 +910,7 @@ public function storeItemResponse(RunnerServiceContext $context, $itemRef, $resp return true; } catch (AssessmentTestSessionException $e) { - \common_Logger::w($e->getMessage()); + common_Logger::w($e->getMessage()); return false; } } @@ -959,19 +919,11 @@ public function storeItemResponse(RunnerServiceContext $context, $itemRef, $resp * Should we display feedbacks * @param RunnerServiceContext $context * @return boolean - * @throws \common_exception_InvalidArgumentType + * @throws InvalidArgumentTypeException */ public function displayFeedbacks(RunnerServiceContext $context) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'displayFeedbacks', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'displayFeedbacks'); /* @var TestSession $session */ $session = $context->getTestSession(); @@ -994,8 +946,8 @@ public function displayFeedbacks(RunnerServiceContext $context) * @param RunnerServiceContext $context * @param string $itemRef the item reference * @return array the feedbacks data - * @throws \common_Exception - * @throws \common_exception_InvalidArgumentType + * @throws common_Exception + * @throws InvalidArgumentTypeException * @deprecated since version 30.7.0, to be removed in 31.0.0. Use getItemVariableElementsData() instead */ public function getFeedbacks(RunnerServiceContext $context, $itemRef) @@ -1007,8 +959,8 @@ public function getFeedbacks(RunnerServiceContext $context, $itemRef) * @param RunnerServiceContext $context * @param $itemRef * @return array - * @throws \common_Exception - * @throws \common_exception_InvalidArgumentType + * @throws common_Exception + * @throws InvalidArgumentTypeException */ public function getItemVariableElementsData(RunnerServiceContext $context, $itemRef) { @@ -1023,10 +975,10 @@ public function getItemVariableElementsData(RunnerServiceContext $context, $item * @param RunnerServiceContext $context * @param string $itemRef the item reference * @return boolean - * @throws \common_Exception - * @throws \common_exception_InconsistentData - * @throws \common_exception_InvalidArgumentType - * @throws \tao_models_classes_FileNotFoundException + * @throws common_Exception + * @throws common_exception_InconsistentData + * @throws InvalidArgumentTypeException + * @throws tao_models_classes_FileNotFoundException */ public function hasFeedbacks(RunnerServiceContext $context, $itemRef) { @@ -1043,25 +995,19 @@ public function hasFeedbacks(RunnerServiceContext $context, $itemRef) } } } + return $hasFeedbacks; } + /** * Should we display feedbacks * @param RunnerServiceContext $context * @return array the item session - * @throws \common_exception_InvalidArgumentType + * @throws InvalidArgumentTypeException */ public function getItemSession(RunnerServiceContext $context) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'getItemSession', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'getItemSession'); /* @var TestSession $session */ $session = $context->getTestSession(); @@ -1069,9 +1015,12 @@ public function getItemSession(RunnerServiceContext $context) $currentItem = $session->getCurrentAssessmentItemRef(); $currentOccurrence = $session->getCurrentAssessmentItemRefOccurence(); - $itemSession = $session->getAssessmentItemSessionStore()->getAssessmentItemSession($currentItem, $currentOccurrence); + $itemSession = $session->getAssessmentItemSessionStore()->getAssessmentItemSession( + $currentItem, + $currentOccurrence + ); - $stateOutput = new \taoQtiCommon_helpers_PciStateOutput(); + $stateOutput = new taoQtiCommon_helpers_PciStateOutput(); foreach ($itemSession->getAllVariables() as $var) { $stateOutput->addVariable($var); @@ -1084,8 +1033,15 @@ public function getItemSession(RunnerServiceContext $context) $position = $route->getPosition(); $config = $this->getTestConfig(); $reviewConfig = $config->getConfigValue('review'); - $partiallyAnsweredIsAnswered = isset($reviewConfig['partiallyAnsweredIsAnswered']) ? (bool) $reviewConfig['partiallyAnsweredIsAnswered'] : true; - $output['itemAnswered'] = TestRunnerUtils::isItemCompleted($route->getRouteItemAt($position), $itemSession, $partiallyAnsweredIsAnswered); + $partiallyAnsweredIsAnswered = isset($reviewConfig['partiallyAnsweredIsAnswered']) + ? (bool) $reviewConfig['partiallyAnsweredIsAnswered'] + : true; + + $output['itemAnswered'] = TestRunnerUtils::isItemCompleted( + $route->getRouteItemAt($position), + $itemSession, + $partiallyAnsweredIsAnswered + ); return $output; } @@ -1097,21 +1053,13 @@ public function getItemSession(RunnerServiceContext $context) * @param $scope * @param $ref * @return boolean - * @throws \common_Exception + * @throws common_Exception */ public function move(RunnerServiceContext $context, $direction, $scope, $ref) { - $result = true; + $this->assertIsQtiRunnerServiceContext($context, 'move'); - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'move', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $result = true; try { $result = QtiRunnerNavigation::move($direction, $scope, $context, $ref); @@ -1131,7 +1079,7 @@ public function move(RunnerServiceContext $context, $direction, $scope, $ref) * @param $scope * @param $ref * @return boolean - * @throws \common_Exception + * @throws common_Exception */ public function skip(RunnerServiceContext $context, $scope, $ref) { @@ -1145,24 +1093,16 @@ public function skip(RunnerServiceContext $context, $scope, $ref) * @param $ref * @param $late * @return boolean - * @throws \common_Exception + * @throws common_Exception */ public function timeout(RunnerServiceContext $context, $scope, $ref, $late = false) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'timeout', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'timeout'); /* @var TestSession $session */ $session = $context->getTestSession(); if ($context->isAdaptive()) { - \common_Logger::t("Select next item before timeout"); + $this->getLogger()->debug("Select next item before timeout"); $context->selectAdaptiveNextItem(); } try { @@ -1192,27 +1132,21 @@ public function timeout(RunnerServiceContext $context, $scope, $ref, $late = fal * Exits the test before its end * @param RunnerServiceContext $context * @return boolean - * @throws \common_Exception + * @throws common_Exception */ public function exitTest(RunnerServiceContext $context) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'exitTest', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'exitTest'); /* @var TestSession $session */ $session = $context->getTestSession(); $sessionId = $session->getSessionId(); - \common_Logger::i("The user has requested termination of the test session '{$sessionId}'"); + $this->getLogger()->info( + "The user has requested termination of the test session '{$sessionId}'" + ); if ($context->isAdaptive()) { - \common_Logger::t("Select next item before test exit"); + $this->getLogger()->debug('Select next item before test exit'); $context->selectAdaptiveNextItem(); } @@ -1226,62 +1160,67 @@ public function exitTest(RunnerServiceContext $context) return true; } - /** * Finishes the test * @param RunnerServiceContext $context * @param string $finalState * @return boolean - * @throws \common_Exception + * @throws common_Exception */ public function finish(RunnerServiceContext $context, $finalState = DeliveryExecution::STATE_FINISHED) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'finish', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'finish'); $executionUri = $context->getTestExecutionUri(); - $userUri = \common_session_SessionManager::getSession()->getUserUri(); + $userUri = common_session_SessionManager::getSession()->getUserUri(); - $executionService = ServiceProxy::singleton(); + $executionService = TaoDeliveryServiceProxy::singleton(); $deliveryExecution = $executionService->getDeliveryExecution($executionUri); if ($deliveryExecution->getUserIdentifier() == $userUri) { - \common_Logger::i("Finishing the delivery execution {$executionUri}"); + $this->getLogger()->info("Finishing the delivery execution {$executionUri}"); $result = $deliveryExecution->setState($finalState); } else { - \common_Logger::w("Non owner {$userUri} tried to finish deliveryExecution {$executionUri}"); + $this->getLogger()->warning( + "Non owner {$userUri} tried to finish deliveryExecution {$executionUri}" + ); $result = false; } $this->getServiceManager()->get(ExtendedStateService::SERVICE_ID)->clearEvents($executionUri); + /** @var TestSession $session */ + $session = $context->getTestSession(); + $this->triggerDeliveryExecutionFinish($deliveryExecution, $session->isManualScored()); return $result; } + private function getResultsStorage(): RdsResultStorage + { + return $this->getServiceLocator()->get(ResultServerService::SERVICE_ID)->getResultStorage(); + } + + private function triggerDeliveryExecutionFinish(DeliveryExecution $deliveryExecution, bool $isManualScored): void + { + $outcomeVariables = $this->getResultsStorage()->getDeliveryVariables($deliveryExecution->getIdentifier()); + $this->getServiceManager()->get(EventManager::SERVICE_ID)->trigger( + new DeliveryExecutionFinish( + $deliveryExecution, + $outcomeVariables, + $isManualScored + ) + ); + } + /** * Sets the test to paused state * @param RunnerServiceContext $context * @return boolean - * @throws \common_Exception + * @throws common_Exception */ public function pause(RunnerServiceContext $context) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'pause', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'pause'); $context->getTestSession()->suspend(); $this->persist($context); @@ -1293,19 +1232,11 @@ public function pause(RunnerServiceContext $context) * Resumes the test from paused state * @param RunnerServiceContext $context * @return boolean - * @throws \common_Exception + * @throws common_Exception */ public function resume(RunnerServiceContext $context) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - 'QtiRunnerService', - 'resume', - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, 'resume'); $context->getTestSession()->resume(); $this->persist($context); @@ -1317,7 +1248,7 @@ public function resume(RunnerServiceContext $context) * Checks if the test is still valid * @param RunnerServiceContext $context * @return boolean - * @throws \common_Exception + * @throws common_Exception * @throws QtiRunnerClosedException */ public function check(RunnerServiceContext $context) @@ -1338,7 +1269,7 @@ public function check(RunnerServiceContext $context) * @param AssessmentItemSession $itemSession * @param bool $partially (optional) Whether or not consider partially responded sessions as responded. * @return bool - * @throws \common_Exception + * @throws common_Exception */ public function isItemCompleted(RunnerServiceContext $context, $routeItem, $itemSession, $partially = true) { @@ -1358,7 +1289,10 @@ public function isItemCompleted(RunnerServiceContext $context, $routeItem, $item // fork of AssessmentItemSession::isResponded() $excludedResponseVariables = ['numAttempts', 'duration']; foreach ($responses as $var) { - if ($var instanceof ResponseVariable && in_array($var->getIdentifier(), $excludedResponseVariables) === false) { + if ( + $var instanceof ResponseVariable + && in_array($var->getIdentifier(), $excludedResponseVariables) === false + ) { $value = $var->getValue(); $defaultValue = $var->getDefaultValue(); @@ -1406,9 +1340,9 @@ public function isTerminated(RunnerServiceContext $context) * @param RunnerServiceContext $context * @param string $itemRef * @return string - * @throws \common_Exception - * @throws \common_exception_Error - * @throws \common_exception_InvalidArgumentType + * @throws common_Exception + * @throws common_exception_Error + * @throws InvalidArgumentTypeException */ public function getItemPublicUrl(RunnerServiceContext $context, string $itemRef): string { @@ -1424,7 +1358,7 @@ public function getItemPublicUrl(RunnerServiceContext $context, string $itemRef) $directoryIds = explode('|', $itemRef); - $userDataLang = \common_session_SessionManager::getSession()->getDataLanguage(); + $userDataLang = common_session_SessionManager::getSession()->getDataLanguage(); $directory = \tao_models_classes_service_FileStorage::singleton()->getDirectoryById($directoryIds[1]); // do fallback in case userlanguage is not default language @@ -1454,7 +1388,7 @@ public function comment(RunnerServiceContext $context, $comment) $deliveryServerService = $this->getServiceManager()->get(DeliveryServerService::SERVICE_ID); $resultStore = $deliveryServerService->getResultStoreWrapper($sessionId); - $transmitter = new \taoQtiCommon_helpers_ResultTransmitter($resultStore); + $transmitter = new taoQtiCommon_helpers_ResultTransmitter($resultStore); // build variable and send it. $itemUri = TestRunnerUtils::getCurrentItemUri($testSession); @@ -1495,7 +1429,8 @@ protected function continueInteraction(RunnerServiceContext $context) * times out. * * @param RunnerServiceContext $context - * @param AssessmentTestSessionException $timeOutException The AssessmentTestSessionException object thrown to indicate the timeout. + * @param AssessmentTestSessionException $timeOutException The AssessmentTestSessionException object thrown to + * indicate the timeout. */ protected function onTimeout(RunnerServiceContext $context, AssessmentTestSessionException $timeOutException) { @@ -1512,36 +1447,36 @@ protected function onTimeout(RunnerServiceContext $context, AssessmentTestSessio } switch ($timeOutException->getCode()) { case AssessmentTestSessionException::ASSESSMENT_TEST_DURATION_OVERFLOW: - \common_Logger::i('TIMEOUT: closing the assessment test session', $logContext); + $this->getLogger()->info('TIMEOUT: closing the assessment test session', $logContext); $session->moveThroughAndEndTestSession(); break; case AssessmentTestSessionException::TEST_PART_DURATION_OVERFLOW: if ($isLinear) { - \common_Logger::i('TIMEOUT: moving to the next test part', $logContext); + $this->getLogger()->info('TIMEOUT: moving to the next test part', $logContext); $session->moveNextTestPart(); } else { - \common_Logger::i('TIMEOUT: closing the assessment test part', $logContext); + $this->getLogger()->info('TIMEOUT: closing the assessment test part', $logContext); $session->closeTestPart(); } break; case AssessmentTestSessionException::ASSESSMENT_SECTION_DURATION_OVERFLOW: if ($isLinear) { - \common_Logger::i('TIMEOUT: moving to the next assessment section', $logContext); + $this->getLogger()->info('TIMEOUT: moving to the next assessment section', $logContext); $session->moveNextAssessmentSection(); } else { - \common_Logger::i('TIMEOUT: closing the assessment section session', $logContext); + $this->getLogger()->info('TIMEOUT: closing the assessment section session', $logContext); $session->closeAssessmentSection(); } break; case AssessmentTestSessionException::ASSESSMENT_ITEM_DURATION_OVERFLOW: if ($isLinear) { - \common_Logger::i('TIMEOUT: moving to the next item', $logContext); + $this->getLogger()->info('TIMEOUT: moving to the next item', $logContext); $session->moveNextAssessmentItem(); } else { - \common_Logger::i('TIMEOUT: closing the assessment item session', $logContext); + $this->getLogger()->info('TIMEOUT: closing the assessment item session', $logContext); $session->closeAssessmentItem(); } break; @@ -1557,7 +1492,8 @@ protected function onTimeout(RunnerServiceContext $context, AssessmentTestSessio * Build an array where each cell represent a time constraint (a.k.a. time limits) * in force. Each cell is actually an array with two keys: * - * * 'source': The identifier of the QTI component emitting the constraint (e.g. AssessmentTest, TestPart, AssessmentSection, AssessmentItemRef). + * * 'source': The identifier of the QTI component emitting the constraint + * (e.g. AssessmentTest, TestPart, AssessmentSection, AssessmentItemRef). * * 'seconds': The number of remaining seconds until it times out. * * @param RunnerServiceContext $context @@ -1585,7 +1521,7 @@ protected function buildTimeConstraints(RunnerServiceContext $context) * @param string $variableIdentifier * @param mixed $variableValue * @return boolean - * @throws \common_Exception + * @throws common_Exception */ public function storeTraceVariable( RunnerServiceContext $context, @@ -1605,15 +1541,16 @@ public function storeTraceVariable( * * @param $variableIdentifier * @param $variableValue - * @return \taoResultServer_models_classes_TraceVariable - * @throws \common_exception_InvalidArgumentType + * @return taoResultServer_models_classes_TraceVariable + * @throws InvalidArgumentTypeException */ public function getTraceVariable($variableIdentifier, $variableValue) { if (!is_string($variableValue) && !is_numeric($variableValue)) { $variableValue = json_encode($variableValue); } - $metaVariable = new \taoResultServer_models_classes_TraceVariable(); + + $metaVariable = new taoResultServer_models_classes_TraceVariable(); $metaVariable->setIdentifier($variableIdentifier); $metaVariable->setBaseType('string'); $metaVariable->setCardinality(Cardinality::getNameByConstant(Cardinality::SINGLE)); @@ -1630,7 +1567,7 @@ public function getTraceVariable($variableIdentifier, $variableValue) * @param $variableIdentifier * @param $variableValue * @return boolean - * @throws \common_Exception + * @throws common_Exception */ public function storeOutcomeVariable(RunnerServiceContext $context, $itemUri, $variableIdentifier, $variableValue) { @@ -1645,7 +1582,7 @@ public function storeOutcomeVariable(RunnerServiceContext $context, $itemUri, $v * @param $variableIdentifier * @param $variableValue * @return \taoResultServer_models_classes_OutcomeVariable - * @throws \common_exception_InvalidArgumentType + * @throws InvalidArgumentTypeException */ public function getOutcomeVariable($variableIdentifier, $variableValue) { @@ -1669,7 +1606,7 @@ public function getOutcomeVariable($variableIdentifier, $variableValue) * @param $variableIdentifier * @param $variableValue * @return boolean - * @throws \common_Exception + * @throws common_Exception */ public function storeResponseVariable(RunnerServiceContext $context, $itemUri, $variableIdentifier, $variableValue) { @@ -1684,7 +1621,7 @@ public function storeResponseVariable(RunnerServiceContext $context, $itemUri, $ * @param $variableIdentifier * @param $variableValue * @return \taoResultServer_models_classes_ResponseVariable - * @throws \common_exception_InvalidArgumentType + * @throws InvalidArgumentTypeException */ public function getResponseVariable($variableIdentifier, $variableValue) { @@ -1705,11 +1642,11 @@ public function getResponseVariable($variableIdentifier, $variableValue) * * @param QtiRunnerServiceContext $context * @param string $itemUri This is the item uri - * @param \taoResultServer_models_classes_Variable[] $metaVariables + * @param taoResultServer_models_classes_Variable[] $metaVariables * @param null $itemId The assessment item ref id (optional) * @return bool - * @throws \Exception - * @throws \common_exception_NotImplemented If the given $itemId is not the current assessment item ref + * @throws Exception + * @throws common_exception_NotImplemented If the given $itemId is not the current assessment item ref */ public function storeVariables( QtiRunnerServiceContext $context, @@ -1726,7 +1663,12 @@ public function storeVariables( $testUri = $context->getTestDefinitionUri(); if (!is_null($itemUri)) { - $resultStore->storeItemVariables($testUri, $itemUri, $metaVariables, $this->getTransmissionId($context, $itemId)); + $resultStore->storeItemVariables( + $testUri, + $itemUri, + $metaVariables, + $this->getTransmissionId($context, $itemId) + ); } else { $resultStore->storeTestVariables($testUri, $metaVariables, $sessionId); } @@ -1739,15 +1681,15 @@ public function storeVariables( * * @param QtiRunnerServiceContext $context * @param string $itemUri This is the item identifier - * @param \taoResultServer_models_classes_Variable $metaVariable + * @param taoResultServer_models_classes_Variable $metaVariable * @param null $itemId The assessment item ref id (optional) * @return bool - * @throws \common_exception_NotImplemented If the given $itemId is not the current assessment item ref + * @throws common_exception_NotImplemented If the given $itemId is not the current assessment item ref */ protected function storeVariable( QtiRunnerServiceContext $context, $itemUri, - \taoResultServer_models_classes_Variable $metaVariable, + taoResultServer_models_classes_Variable $metaVariable, $itemId = null ) { $sessionId = $context->getTestSession()->getSessionId(); @@ -1759,7 +1701,12 @@ protected function storeVariable( $resultStore = $deliveryServerService->getResultStoreWrapper($sessionId); if (!is_null($itemUri)) { - $resultStore->storeItemVariable($testUri, $itemUri, $metaVariable, $this->getTransmissionId($context, $itemId)); + $resultStore->storeItemVariable( + $testUri, + $itemUri, + $metaVariable, + $this->getTransmissionId($context, $itemId) + ); } else { $resultStore->storeTestVariable($testUri, $metaVariable, $sessionId); } @@ -1773,14 +1720,14 @@ protected function storeVariable( * @param QtiRunnerServiceContext $context * @param null $itemId The item ref identifier * @return string The transmission id to store item variables - * @throws \common_exception_NotImplemented If the given $itemId is not the current assessment item ref + * @throws common_exception_NotImplemented If the given $itemId is not the current assessment item ref */ protected function getTransmissionId(QtiRunnerServiceContext $context, $itemId = null) { if (is_null($itemId)) { $itemId = $context->getCurrentAssessmentItemRef(); } elseif ($itemId != $context->getCurrentAssessmentItemRef()) { - throw new \common_exception_NotImplemented('Item variables can be stored only for the current item'); + throw new common_exception_NotImplemented('Item variables can be stored only for the current item'); } $sessionId = $context->getTestSession()->getSessionId(); @@ -1793,19 +1740,11 @@ protected function getTransmissionId(QtiRunnerServiceContext $context, $itemId = * Check if the given RunnerServiceContext is a QtiRunnerServiceContext * * @param RunnerServiceContext $context - * @throws \common_exception_InvalidArgumentType + * @throws InvalidArgumentTypeException */ public function assertQtiRunnerServiceContext(RunnerServiceContext $context) { - if (!$context instanceof QtiRunnerServiceContext) { - throw new InvalidArgumentTypeException( - __CLASS__, - __FUNCTION__, - 0, - QtiRunnerServiceContext::class, - $context - ); - } + $this->assertIsQtiRunnerServiceContext($context, __FUNCTION__); } /** @@ -1813,7 +1752,7 @@ public function assertQtiRunnerServiceContext(RunnerServiceContext $context) * @param RunnerServiceContext $context * @param float|null $timestamp allow to start the timer at a specific time, or use current when it's null * @return bool - * @throws \common_exception_InvalidArgumentType + * @throws InvalidArgumentTypeException */ public function startTimer(RunnerServiceContext $context, ?float $timestamp = null): bool { @@ -1842,7 +1781,7 @@ public function startTimer(RunnerServiceContext $context, ?float $timestamp = nu * @param float|null $duration The client side duration to adjust the timer * @param float|null $timestamp allow to end the timer at a specific time, or use current when it's null * @return bool - * @throws \common_exception_InvalidArgumentType + * @throws InvalidArgumentTypeException */ public function endTimer(RunnerServiceContext $context, ?float $duration = null, ?float $timestamp = null): bool { @@ -1869,7 +1808,7 @@ public function endTimer(RunnerServiceContext $context, ?float $duration = null, * @param RunnerServiceContext $context * @param string $receivedStoreId The identifier of the client side store * @return string the identifier of the LAST saved client side store - * @throws \common_exception_InvalidArgumentType + * @throws InvalidArgumentTypeException */ public function switchClientStoreId(RunnerServiceContext $context, $receivedStoreId) { @@ -1902,7 +1841,8 @@ public function switchClientStoreId(RunnerServiceContext $context, $receivedStor * * Depending on the context (adaptive or not), it will return an appropriate Assessment Object to deal with. * - * In case of the context is not adaptive, an AssessmentTestSession corresponding to the current test $context is returned. + * In case of the context is not adaptive, an AssessmentTestSession corresponding to the current test $context + * is returned. * * Otherwise, an AssessmentItemSession to deal with is returned. * @@ -1983,12 +1923,11 @@ public function deleteDeliveryExecutionData(DeliveryExecutionDeleteRequest $requ * @param RunnerServiceContext $context * @param $itemRef * @return array|string - * @throws \common_Exception - * @throws \common_exception_InconsistentData + * @throws common_Exception + * @throws common_exception_InconsistentData */ public function getItemPortableElements(RunnerServiceContext $context, $itemRef) { - $portableElementService = new PortableElementService(); $portableElementService->setServiceLocator($this->getServiceLocator()); @@ -2001,33 +1940,45 @@ public function getItemPortableElements(RunnerServiceContext $context, $itemRef) try { $portableElementService->setBaseUrlToPortableData($portableData); } catch (PortableElementNotFoundException $e) { - \common_Logger::w('the portable element version does not exist in delivery server'); + $this->getLogger()->warning( + 'the portable element version does not exist in delivery server' + ); } catch (PortableModelMissing $e) { - \common_Logger::w('the portable element model does not exist in delivery server'); + $this->getLogger()->warning( + 'the portable element model does not exist in delivery server' + ); } } } } - } catch (\tao_models_classes_FileNotFoundException $e) { - \common_Logger::i('old delivery that does not contain the compiled portable element data in the item ' . $itemRef); + } catch (tao_models_classes_FileNotFoundException $e) { + $this->getLogger()->info( + 'old delivery that does not contain the compiled portable element data in the item ' . $itemRef + ); } + return $portableElements; } /** * @param $itemRef * @return array|mixed|string - * @throws \common_Exception + * @throws common_Exception */ public function getItemMetadataElements($itemRef) { $metadataElements = []; try { $metadataElements = $this->loadItemData($itemRef, QtiJsonItemCompiler::METADATA_FILE_NAME); - } catch (\tao_models_classes_FileNotFoundException $e) { - \common_Logger::i('Old delivery that does not contain the compiled portable element data in the item ' . $itemRef . '. Original message: ' . $e->getMessage()); - } catch (\Exception $e) { - \common_Logger::w('An exception caught during fetching item metadata elements. Original message: ' . $e->getMessage()); + } catch (tao_models_classes_FileNotFoundException $e) { + $this->getLogger()->info( + 'Old delivery that does not contain the compiled portable element data in the item ' . $itemRef + . '. Original message: ' . $e->getMessage() + ); + } catch (Exception $e) { + $this->getLogger()->warning( + 'An exception caught during fetching item metadata elements. Original message: ' . $e->getMessage() + ); } return $metadataElements; } @@ -2035,7 +1986,7 @@ public function getItemMetadataElements($itemRef) /** * @param $deUri * @param $userUri - * @param $storage + * @param StorageManager $storage * @return mixed */ protected function deleteExecutionStates($deUri, $userUri, StorageManager $storage) @@ -2066,8 +2017,12 @@ protected function deleteExecutionStates($deUri, $userUri, StorageManager $stora * @return bool * @throws \common_exception_NotFound */ - protected function deleteExecutionStatesBasedOnSession(DeliveryExecutionDeleteRequest $request, StorageManager $storage, $userUri, AssessmentTestSession $session) - { + protected function deleteExecutionStatesBasedOnSession( + DeliveryExecutionDeleteRequest $request, + StorageManager $storage, + $userUri, + AssessmentTestSession $session + ) { $itemsRefs = $this->getItemsRefs($request, $session); foreach ($itemsRefs as $itemRef) { $stateId = $this->buildStorageItemKey( @@ -2097,7 +2052,7 @@ protected function getItemsRefs(DeliveryExecutionDeleteRequest $request, Assessm $request->getDeliveryExecution(), $session ))->getItemsRefs(); - } catch (\Exception $exception) { + } catch (Exception $exception) { $itemsRefs = []; } @@ -2117,12 +2072,12 @@ protected function getStateAfterExit() * Returns that the Theme Switcher Plugin is enabled or not * * @return bool - * @throws \common_ext_ExtensionException + * @throws common_ext_ExtensionException */ private function isThemeSwitcherEnabled() { - /** @var \common_ext_ExtensionsManager $extensionsManager */ - $extensionsManager = $this->getServiceLocator()->get(\common_ext_ExtensionsManager::SERVICE_ID); + /** @var common_ext_ExtensionsManager $extensionsManager */ + $extensionsManager = $this->getServiceLocator()->get(common_ext_ExtensionsManager::SERVICE_ID); $config = $extensionsManager->getExtensionById("taoTests")->getConfig("test_runner_plugin_registry"); return array_key_exists(self::TOOL_ITEM_THEME_SWITCHER_KEY, $config) @@ -2133,7 +2088,7 @@ private function isThemeSwitcherEnabled() * Returns the ID of the current theme * * @return string - * @throws \common_exception_InconsistentData + * @throws common_exception_InconsistentData */ private function getCurrentThemeId() { @@ -2152,4 +2107,22 @@ private function getFeatureFlagChecker(): FeatureFlagCheckerInterface { return $this->getServiceLocator()->getContainer()->get(FeatureFlagChecker::class); } + + /** + * @throws InvalidArgumentTypeException + */ + private function assertIsQtiRunnerServiceContext( + RunnerServiceContext $context, + string $action + ): void { + if (!$context instanceof QtiRunnerServiceContext) { + throw new InvalidArgumentTypeException( + 'QtiRunnerService', + $action, + 0, + QtiRunnerServiceContext::class, + $context + ); + } + } }