function neighbourhood(AssessmentTestSession $session, array &$average = null) { $start = microtime(); $neighbourhood = $session->getPossibleJumps(); if (is_null($average) === false) { spentTime($start, microtime(), $average); } }
/** * Persist the binary stream $stream which contains the binary equivalent of $assessmentTestSession in * the temporary directory of the file system. * * @param \qtism\runtime\tests\AssessmentTestSession $assessmentTestSession The AssessmentTestSession to be persisted. * @param \qtism\common\storage\MemoryStream $stream The MemoryStream to be stored in the temporary directory of the host file system. * @throws \RuntimeException If the binary stream cannot be persisted. */ protected function persistStream(AssessmentTestSession $assessmentTestSession, MemoryStream $stream) { $sessionId = $assessmentTestSession->getSessionId(); $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . md5($sessionId) . '.bin'; $written = @file_put_contents($path, $stream->getBinary()); if ($written === false || $written === 0) { $msg = "An error occured while persisting the binary stream at '{$path}'."; throw new RuntimeException($msg); } }
/** * Save session metadata. * * @param array $metaData Meta data array to be saved. * @param RouteItem $routeItem item for which data will be saved * @param string $assessmentSectionId section id for which data will be saved * Example: * array( * 'TEST' => array('TEST_EXIT_CODE' => 'IC'), * 'SECTION' => array('SECTION_EXIT_CODE' => 701), * ) */ public function save(array $metaData, RouteItem $routeItem = null, $assessmentSectionId = null) { $testUri = $this->session->getTest()->getUri(); $resultServer = \taoResultServer_models_classes_ResultServerStateFull::singleton(); foreach ($metaData as $type => $data) { foreach ($data as $key => $value) { $metaVariable = $this->getVariable($key, $value); if (strcasecmp($type, 'ITEM') === 0) { if ($routeItem === null) { $itemRef = $this->session->getCurrentAssessmentItemRef(); $occurence = $this->session->getCurrentAssessmentItemRefOccurence(); } else { $itemRef = $routeItem->getAssessmentItemRef(); $occurence = $routeItem->getOccurence(); } $itemUri = $this->getItemUri($itemRef); $sessionId = $this->session->getSessionId(); $transmissionId = "{$sessionId}.{$itemRef}.{$occurence}"; $resultServer->storeItemVariable($testUri, $itemUri, $metaVariable, $transmissionId); } elseif (strcasecmp($type, 'TEST') === 0) { $resultServer->storeTestVariable($testUri, $metaVariable, $this->session->getSessionId()); } elseif (strcasecmp($type, 'SECTION') === 0) { //suffix section variables with _{SECTION_IDENTIFIER} if ($assessmentSectionId === null) { $assessmentSectionId = $this->session->getCurrentAssessmentSection()->getIdentifier(); } $metaVariable->setIdentifier($key . '_' . $assessmentSectionId); $resultServer->storeTestVariable($testUri, $metaVariable, $this->session->getSessionId()); } } } }
/** * Checks if the current session can be exited * * @param AssessmentTestSession $session * @return bool */ public static function doesAllowExit(AssessmentTestSession $session) { $categories = $session->getCurrentAssessmentItemRef()->getCategories(); $config = common_ext_ExtensionsManager::singleton()->getExtensionById('taoQtiTest')->getConfig('testRunner'); $exitButton = isset($config['exitButton']) && $config['exitButton']; return $exitButton && $categories->contains('x-tao-option-exit'); }
/** * Persist an AssessmentTestSession into binary data. * * @param \qtism\runtime\tests\AssessmentTestSession $assessmentTestSession * @throws \qtism\runtime\storage\common\StorageException */ public function persist(AssessmentTestSession $assessmentTestSession) { try { $stream = new MemoryStream(); $stream->open(); $access = $this->createBinaryStreamAccess($stream); // -- Deal with intrinsic values of the Test Session. $access->writeTinyInt($assessmentTestSession->getState()); // Write the current position in the route. $route = $assessmentTestSession->getRoute(); $access->writeTinyInt($route->getPosition()); // persist time reference. $timeReference = $assessmentTestSession->getTimeReference(); if (is_null($timeReference) === true) { $access->writeBoolean(false); } else { $access->writeBoolean(true); $access->writeDateTime($timeReference); } // -- Persist the Route of the AssessmentTestSession and the related item sessions. $access->writeTinyInt($route->count()); $itemSessionStore = $assessmentTestSession->getAssessmentItemSessionStore(); $pendingResponseStore = $assessmentTestSession->getPendingResponseStore(); $oldRoutePosition = $route->getPosition(); foreach ($route as $routeItem) { $item = $routeItem->getAssessmentItemRef(); $occurence = $routeItem->getOccurence(); // Deal with RouteItem $access->writeRouteItem($this->getSeeker(), $routeItem); // Deal with ItemSession related to the previously written RouteItem. try { $itemSession = $itemSessionStore->getAssessmentItemSession($item, $occurence); $access->writeBoolean(true); $access->writeAssessmentItemSession($this->getSeeker(), $itemSession); // Deal with last occurence update. $access->writeBoolean($assessmentTestSession->isLastOccurenceUpdate($item, $occurence)); // Deal with PendingResponses if (($pendingResponses = $pendingResponseStore->getPendingResponses($item, $occurence)) !== false) { $access->writeBoolean(true); $access->writePendingResponses($this->getSeeker(), $pendingResponses); } else { $access->writeBoolean(false); } } catch (OutOfBoundsException $e) { $access->writeBoolean(false); // No assessmentItemSession for this route item. continue; } } $route->setPosition($oldRoutePosition); // Deal with test session configuration. // !!! AutoForward (not in use anymore, fake it). $access->writeBoolean(false); // Persist the test-level global scope. foreach ($assessmentTestSession->getKeys() as $outcomeIdentifier) { $outcomeVariable = $assessmentTestSession->getVariable($outcomeIdentifier); $access->writeVariableValue($outcomeVariable); } $durationStore = $assessmentTestSession->getDurationStore(); $access->writeShort(count($durationStore)); foreach ($durationStore->getKeys() as $k) { $access->writeString($k); $access->writeVariableValue($durationStore->getVariable($k)); } $this->persistStream($assessmentTestSession, $stream); $stream->close(); } catch (Exception $e) { $sessionId = $assessmentTestSession->getSessionId(); $msg = "An error occured while persisting AssessmentTestSession with ID '{$sessionId}': " . $e->getMessage(); throw new StorageException($msg, StorageException::PERSITANCE, $e); } }
/** * @inheritdoc * @param int $state */ public function setState($state) { $previousState = $this->getState(); $sessionMemento = $this->getSessionMemento(); parent::setState($state); if ($previousState !== null && $previousState !== $state) { $this->triggerStateChanged($sessionMemento); } }
/** * Extra configuration for newly instantiated AssessmentTestSession objects. This implementation * forces test results to be sent at the end of the candidate session, and get the acceptable * latency time from the taoQtiTest extension's configuration. * * @param AssessmentTestSession $assessmentTestSession */ protected function configureAssessmentTestSession(AssessmentTestSession $assessmentTestSession) { $assessmentTestSession->setTestResultsSubmission(TestResultsSubmission::END); }
protected function persistStream(AssessmentTestSession $assessmentTestSession, MemoryStream $stream) { $storageService = tao_models_classes_service_StateStorage::singleton(); $userUri = common_session_SessionManager::getSession()->getUserUri(); if (is_null($userUri) === true) { $msg = "Could not retrieve current user URI."; throw new StorageException($msg, StorageException::RETRIEVAL); } $data = $this->getLastError() . $stream->getBinary(); $storageService->set($userUri, $assessmentTestSession->getSessionId(), $data); }
/** * @param AssessmentTestSession $session * @return \taoDelivery_models_classes_execution_DeliveryExecution */ private function getDeliveryExecution(AssessmentTestSession $session) { return $this->deliveryExecutionService->getDeliveryExecution($session->getSessionId()); }
/** * Compute the the number of completed items during a given * candidate test $session. * * @param AssessmentTestSession $session * @return integer */ public static function testCompletion(AssessmentTestSession $session) { $completed = $session->numberCompleted(); if ($session->getCurrentNavigationMode() === NavigationMode::LINEAR && $completed > 0) { $completed--; } return $completed; }
/** * QTISM endTestSession method overriding. * * It consists of including an additional processing when the test ends, * in order to send the LtiOutcome * * @see http://www.imsglobal.org/lis/ Outcome Management Service * @throws taoQtiTest_helpers_TestSessionException If the session is already ended or if an error occurs whil transmitting/processing the result. */ public function endTestSession() { parent::endTestSession(); common_Logger::i('Ending test session.'); try { // Compute the LtiOutcome variable for LTI support. $this->setVariable(new OutcomeVariable('LtiOutcome', Cardinality::SINGLE, BaseType::FLOAT, new Float(0.0))); $outcomeProcessingEngine = new OutcomeProcessingEngine($this->buildLtiOutcomeProcessing(), $this); $outcomeProcessingEngine->process(); // if numberPresented returned 0, division by 0 -> null. $testUri = $this->getTest()->getUri(); $var = $this->getVariable('LtiOutcome'); $varIdentifier = $var->getIdentifier(); common_Logger::t("Submitting test result '{$varIdentifier}' related to test '{$testUri}'."); $this->getResultTransmitter()->transmitTestVariable($var, $this->getSessionId(), $testUri); $this->unsetVariable('LtiOutcome'); } catch (ProcessingException $e) { $msg = "An error occured while processing the 'LtiOutcome' outcome variable."; throw new taoQtiTest_helpers_TestSessionException($msg, taoQtiTest_helpers_TestSessionException::RESULT_SUBMISSION_ERROR, $e); } catch (taoQtiCommon_helpers_ResultTransmissionException $e) { $msg = "An error occured during test-level outcome results transmission."; throw new taoQtiTest_helpers_TestSessionException($msg, taoQtiTest_helpers_TestSessionException::RESULT_SUBMISSION_ERROR, $e); } }
/** * @param AssessmentTestSession $session */ public function persist(AssessmentTestSession $session) { $sessionId = $session->getSessionId(); $storage = $this->cache[$sessionId]['storage']; $storage->persist($session); }
/** * Persist an AssessmentTestSession into binary data. * * The QTI Binary Storage Version that will be used to persist the AssessmentTestSession * will be systematically the one defined in QtiBinaryConstants::QTI_BINARY_STORAGE_VERSION. * * @param AssessmentTestSession $assessmentTestSession * @throws StorageException */ public function persist(AssessmentTestSession $assessmentTestSession) { try { $stream = new MemoryStream(); $stream->open(); $access = $this->createBinaryStreamAccess($stream); // write the QTI Binary Storage version in use to persist the test session. $access->writeTinyInt(QtiBinaryConstants::QTI_BINARY_STORAGE_VERSION); $access->writeTinyInt($assessmentTestSession->getState()); $route = $assessmentTestSession->getRoute(); $access->writeTinyInt($route->getPosition()); // Persist the Route of the AssessmentTestSession and the related item sessions. $access->writeTinyInt($route->count()); $itemSessionStore = $assessmentTestSession->getAssessmentItemSessionStore(); $pendingResponseStore = $assessmentTestSession->getPendingResponseStore(); foreach ($route as $routeItem) { $item = $routeItem->getAssessmentItemRef(); $occurence = $routeItem->getOccurence(); // Deal with RouteItem $access->writeRouteItem($this->getSeeker(), $routeItem); // Deal with ItemSession related to the previously written RouteItem. $itemSession = $itemSessionStore->getAssessmentItemSession($item, $occurence); $access->writeAssessmentItemSession($this->getSeeker(), $itemSession); // Deal with last occurence update. $access->writeBoolean($assessmentTestSession->isLastOccurenceUpdate($item, $occurence)); // Deal with PendingResponses if (($pendingResponses = $pendingResponseStore->getPendingResponses($item, $occurence)) !== false) { $access->writeBoolean(true); $access->writePendingResponses($this->getSeeker(), $pendingResponses); } else { $access->writeBoolean(false); } } // Deal with test session configuration. // -- AutoForward (not in use anymore, fake it). $access->writeBoolean(false); // Persist the test-level global scope. foreach ($assessmentTestSession->getKeys() as $outcomeIdentifier) { $outcomeVariable = $assessmentTestSession->getVariable($outcomeIdentifier); $access->writeVariableValue($outcomeVariable); } $durationStore = $assessmentTestSession->getDurationStore(); $access->writeShort(count($durationStore)); foreach ($durationStore->getKeys() as $k) { $access->writeString($k); $access->writeVariableValue($durationStore->getVariable($k)); } $this->persistStream($assessmentTestSession, $stream); $stream->close(); } catch (Exception $e) { $sessionId = $assessmentTestSession->getSessionId(); $msg = "An error occured while persisting AssessmentTestSession with ID '{$sessionId}'."; throw new StorageException($msg, StorageException::PERSITANCE, $e); } }
/** * Get the array of available categories for the current itemRef * * @param \qtism\runtime\tests\AssessmentTestSession $session * @return array */ public static function getCategories(AssessmentTestSession $session) { return $session->getCurrentAssessmentItemRef()->getCategories()->getArrayCopy(); }