*/ namespace oat\taoQtiTest\models\runner\navigation; use oat\taoQtiTest\models\event\QtiMoveEvent; use oat\taoQtiTest\models\runner\RunnerServiceContext; use oat\taoQtiTest\models\runner\QtiRunnerServiceContext; use qtism\data\ExtendedAssessmentItemRef; use qtism\runtime\tests\AssessmentItemSession; use oat\oatbox\service\ServiceManager; use oat\oatbox\event\EventManager; use qtism\runtime\tests\AssessmentTestSession; /** * Class QtiRunnerNavigation * @package oat\taoQtiTest\models\runner\navigation */ class QtiRunnerNavigation { /** * Gets a QTI runner navigator * @param string $direction * @param string $scope * @return RunnerNavigation * @throws \common_exception_InconsistentData * @throws \common_exception_NotImplemented */ public static function getNavigator($direction, $scope) { $className = __NAMESPACE__ . '\QtiRunnerNavigation' . ucfirst($direction) . ucfirst($scope); if (class_exists($className)) { $navigator = new $className(); if ($navigator instanceof RunnerNavigation) { return $navigator; } else { throw new \common_exception_InconsistentData('Navigator must be an instance of RunnerNavigation'); } } else { throw new \common_exception_NotImplemented('The action is invalid!'); } } /** * @param string $direction * @param string $scope * @param RunnerServiceContext $context * @param integer $ref * @throws \common_exception_InvalidArgumentType * @throws \common_exception_NotImplemented * @return boolean */ public static function move($direction, $scope, RunnerServiceContext $context, $ref) { $navigator = self::getNavigator($direction, $scope); if ($context instanceof QtiRunnerServiceContext) { $from = $context->getTestSession()->isRunning() === true ? $context->getTestSession()->getRoute()->current() : null; $event = new QtiMoveEvent(QtiMoveEvent::CONTEXT_BEFORE, $context->getTestSession(), $from); ServiceManager::getServiceManager()->get(EventManager::SERVICE_ID)->trigger($event); } $result = $navigator->move($context, $ref); if ($context instanceof QtiRunnerServiceContext) { $to = $context->getTestSession()->isRunning() === true ? $context->getTestSession()->getRoute()->current() : null; $event = new QtiMoveEvent(QtiMoveEvent::CONTEXT_AFTER, $context->getTestSession(), $from, $to); ServiceManager::getServiceManager()->get(EventManager::SERVICE_ID)->trigger($event); } return $result; } /** * Check if a timed section is exited * @param RunnerServiceContext $context * @param int $nextPosition */ public static function checkTimedSectionExit(RunnerServiceContext $context, $nextPosition) { $timerConfig = $context->getTestConfig()->getConfigValue('timer'); if (empty($timerConfig['keepUpToTimeout'])) { /* @var AssessmentTestSession $session */ $session = $context->getTestSession(); $route = $session->getRoute(); $section = $session->getCurrentAssessmentSection(); $limits = $section->getTimeLimits(); // As we have only one identifier for the whole adaptive section it will consider a jump of section on the first item if (!($context instanceof QtiRunnerServiceContext) || !$context->isAdaptive()) { $isJumpOutOfSection = false; if (($nextPosition >= 0) && ($nextPosition < $route->count())) { $nextSection = $route->getRouteItemAt($nextPosition); $isJumpOutOfSection = ($section->getIdentifier() !== $nextSection->getAssessmentSection()->getIdentifier()); } if ($isJumpOutOfSection && $limits != null && $limits->hasMaxTime()) { $assessmentItemRefs = $section->getComponentsByClassName('assessmentItemRef'); foreach ($assessmentItemRefs as $assessmentItemRef) { $itemSessions = $session->getAssessmentItemSessions($assessmentItemRef->getIdentifier()); if ($itemSessions !== false) { foreach ($itemSessions as $itemSession) { $itemSession->endItemSession(); } } } } } } } }