/** * Add an AssessmentItemSession to the store, for a given $occurence number. * * @param \qtism\runtime\tests\AssessmentItemSession $assessmentItemSession * @param integer $occurence The occurence number of the session. */ public function addAssessmentItemSession(AssessmentItemSession $assessmentItemSession, $occurence = 0) { $assessmentItemRef = $assessmentItemSession->getAssessmentItem(); if (isset($this->shelves[$assessmentItemRef]) === false) { $this->shelves[$assessmentItemRef] = new AssessmentItemSessionCollection(); } $this->shelves[$assessmentItemRef][$occurence] = $assessmentItemSession; }
/** * Add an item session to the current assessment test session. * * @param AssessmentItemSession $session * @throws LogicException If the AssessmentItemRef object bound to $session is unknown by the AssessmentTestSession. */ protected function addItemSession(AssessmentItemSession $session, $occurence = 0) { $assessmentItemRefs = $this->getAssessmentItemRefs(); $sessionAssessmentItemRefIdentifier = $session->getAssessmentItem()->getIdentifier(); if ($this->getAssessmentItemRefs()->contains($session->getAssessmentItem()) === false) { // The session that is requested to be set is bound to an item // which is not referenced in the test. This is a pure logic error. $msg = "The item session to set is bound to an unknown AssessmentItemRef."; throw new LogicException($msg); } $this->getAssessmentItemSessionStore()->addAssessmentItemSession($session, $occurence); }
/** * AssessmentTestSession implementations must override this method in order * to submit item results from a given $assessmentItemSession to the appropriate * data source. * * This method is triggered each time response processing takes place. * * @param AssessmentItemSession $itemSession The lastly updated AssessmentItemSession. * @param integer $occurrence The occurrence number of the item bound to $assessmentItemSession. * @throws AssessmentTestSessionException With error code RESULT_SUBMISSION_ERROR if an error occurs while transmitting results. */ public function submitItemResults(AssessmentItemSession $itemSession, $occurrence = 0) { $itemRef = $itemSession->getAssessmentItem(); $identifier = $itemRef->getIdentifier(); $duration = $this->getTimerDuration($identifier); $itemDurationVar = $itemSession->getVariable('duration'); $sessionDuration = $itemDurationVar->getValue(); \common_Logger::i("Force duration of item '{$identifier}' to {$duration} instead of {$sessionDuration}"); $itemSession->getVariable('duration')->setValue($duration); parent::submitItemResults($itemSession, $occurrence); }
protected function submitItemResults(AssessmentItemSession $assessmentItemSession, $occurence = 0) { foreach ($assessmentItemSession as $id => $var) { $this->addItemResultResult($assessmentItemSession->getAssessmentItem()->getIdentifier() . '.' . $occurence . '.' . $id, $var->getValue()); } }
/** * Write an AssessmetnItemSession from the current binary stream. * * @param AssessmentTestSeeker $seeker The AssessmentTestSeeker object from where the position of components will be pulled out. * @param AssessmentItemSession $session An AssessmentItemSession object. * @throws QtiBinaryStreamAccessException */ public function writeAssessmentItemSession(AssessmentTestSeeker $seeker, AssessmentItemSession $session) { try { $this->writeShort($seeker->seekPosition($session->getAssessmentItem())); $this->writeTinyInt($session->getState()); $this->writeTinyInt($session->getNavigationMode()); $this->writeTinyInt($session->getSubmissionMode()); $this->writeBoolean($session->isAttempting()); $isItemSessionControlDefault = $session->getItemSessionControl()->isDefault(); if ($isItemSessionControlDefault === true) { $this->writeBoolean(false); } else { $this->writeBoolean(true); $this->writeShort($seeker->seekPosition($session->getItemSessionControl())); } if ($session->getState() !== AssessmentItemSessionState::NOT_SELECTED) { $this->writeTinyInt($session['numAttempts']->getValue()); $this->writeDuration($session['duration']); $this->writeString($session['completionStatus']->getValue()); if ($session['numAttempts']->getValue() > 0) { $this->writeDateTime($session->getTimeReference()); } } // minus the 3 built-in variables $varCount = count($session) - 3; $this->writeTinyInt($varCount); $itemOutcomes = $session->getAssessmentItem()->getOutcomeDeclarations(); $itemResponses = $session->getAssessmentItem()->getResponseDeclarations(); foreach ($session->getKeys() as $varId) { if (in_array($varId, array('numAttempts', 'duration', 'completionStatus')) === false) { $var = $session->getVariable($varId); $isOutcome = $var instanceof OutcomeVariable; $variableDeclaration = $isOutcome === true ? $itemOutcomes[$varId] : $itemResponses[$varId]; try { $this->writeBoolean($isOutcome); $this->writeShort($seeker->seekPosition($variableDeclaration)); $this->writeVariableValue($var); } catch (OutOfBoundsException $e) { $msg = "No variable found in the assessmentTest tree structure."; throw new QtiBinaryStreamAccessException($msg, $this, QtiBinaryStreamAccessException::ITEM_SESSION, $e); } } } } catch (BinaryStreamAccessException $e) { $msg = "An error occured while writing an assessment item session."; throw new QtiBinaryStreamAccessException($msg, $this, QtiBinaryStreamAccessException::ITEM_SESSION, $e); } catch (OutOfBoundsException $e) { $msg = "No assessmentItemRef found in the assessmentTest tree structure."; throw new QtiBinaryStreamAccessException($msg, $this, QtiBinaryStreamAccessException::ITEM_SESSION, $e); } }
/** * Write an AssessmetnItemSession from the current binary stream. * * @param \qtism\runtime\storage\common\AssessmentTestSeeker $seeker The AssessmentTestSeeker object from where the position of components will be pulled out. * @param \qtism\runtime\tests\AssessmentItemSession $session An AssessmentItemSession object. * @throws \qtism\runtime\storage\binary\QtiBinaryStreamAccessException */ public function writeAssessmentItemSession(AssessmentTestSeeker $seeker, AssessmentItemSession $session) { try { $this->writeShort($seeker->seekPosition($session->getAssessmentItem())); $this->writeTinyInt($session->getState()); $this->writeTinyInt($session->getNavigationMode()); $this->writeTinyInt($session->getSubmissionMode()); $this->writeBoolean($session->isAttempting()); $isItemSessionControlDefault = $session->getItemSessionControl()->isDefault(); if ($isItemSessionControlDefault === true) { $this->writeBoolean(false); } else { $this->writeBoolean(true); $this->writeShort($seeker->seekPosition($session->getItemSessionControl())); } $this->writeTinyInt($session['numAttempts']->getValue()); $this->writeDuration($session['duration']); $this->writeString($session['completionStatus']->getValue()); $timeReference = $session->getTimeReference(); if (is_null($timeReference) === true) { // Describe that we have no time reference for the session. $this->writeBoolean(false); } else { // Describe that we have a time reference for the session. $this->writeBoolean(true); // Write the time reference. $this->writeDateTime($timeReference); } // Write the session variables. // (minus the 3 built-in variables) $varCount = count($session) - 3; $this->writeTinyInt($varCount); $itemOutcomes = $session->getAssessmentItem()->getOutcomeDeclarations(); $itemResponses = $session->getAssessmentItem()->getResponseDeclarations(); $itemTemplates = $session->getAssessmentItem()->getTemplateDeclarations(); foreach ($session->getKeys() as $varId) { if (in_array($varId, array('numAttempts', 'duration', 'completionStatus')) === false) { $var = $session->getVariable($varId); if ($var instanceof OutcomeVariable) { $variableDeclaration = $itemOutcomes[$varId]; $variable = OutcomeVariable::createFromDataModel($variableDeclaration); $varNature = 0; } elseif ($var instanceof ResponseVariable) { $variableDeclaration = $itemResponses[$varId]; $variable = ResponseVariable::createFromDataModel($variableDeclaration); $varNature = 1; } elseif ($var instanceof TemplateVariable) { $variableDeclaration = $itemTemplates[$varId]; $variable = TemplateVariable::createFromDataModel($variableDeclaration); $varNature = 2; } try { $this->writeShort($varNature); $this->writeShort($seeker->seekPosition($variableDeclaration)); // If defaultValue or correct response is different from what's inside // the variable declaration, just write it. $hasDefaultValue = !Utils::equals($variable->getDefaultValue(), $var->getDefaultValue()); $hasCorrectResponse = false; if ($varNature === 1 && !Utils::equals($variable->getCorrectResponse(), $var->getCorrectResponse())) { $hasCorrectResponse = true; } $this->writeBoolean($hasDefaultValue); $this->writeBoolean($hasCorrectResponse); $this->writeVariableValue($var, self::RW_VALUE); if ($hasDefaultValue === true) { $this->writeVariableValue($var, self::RW_DEFAULTVALUE); } if ($hasCorrectResponse === true) { $this->writeVariableValue($var, self::RW_CORRECTRESPONSE); } } catch (OutOfBoundsException $e) { $msg = "No variable found in the assessmentTest tree structure."; throw new QtiBinaryStreamAccessException($msg, $this, QtiBinaryStreamAccessException::ITEM_SESSION, $e); } } } // Write shuffling states if any. $shufflingStates = $session->getShufflingStates(); $this->writeTinyInt(count($shufflingStates)); foreach ($shufflingStates as $shufflingState) { $this->writeShufflingState($shufflingState); } } catch (BinaryStreamAccessException $e) { $msg = "An error occured while writing an assessment item session."; throw new QtiBinaryStreamAccessException($msg, $this, QtiBinaryStreamAccessException::ITEM_SESSION, $e); } catch (OutOfBoundsException $e) { $msg = "No assessmentItemRef found in the assessmentTest tree structure."; throw new QtiBinaryStreamAccessException($msg, $this, QtiBinaryStreamAccessException::ITEM_SESSION, $e); } }
/** * Checks if an item has been completed * @param RouteItem $routeItem * @param AssessmentItemSession $itemSession * @return bool */ public static function isItemCompleted(RouteItem $routeItem, AssessmentItemSession $itemSession) { $completed = false; if ($routeItem->getTestPart()->getNavigationMode() === NavigationMode::LINEAR) { // In linear mode, we consider the item completed if it was presented. if ($itemSession->isPresented() === true) { $completed = true; } } else { // In nonlinear mode we consider: // - an adaptive item completed if it's completion status is 'completed'. // - a non-adaptive item to be completed if it is responded. $isAdaptive = $itemSession->getAssessmentItem()->isAdaptive(); if ($isAdaptive === true && $itemSession['completionStatus']->getValue() === AssessmentItemSession::COMPLETION_STATUS_COMPLETED) { $completed = true; } else { if ($isAdaptive === false && $itemSession->isResponded() === true) { $completed = true; } } } return $completed; }