/**
  * @dataProvider sequencedIdentifiersProvider
  * 
  * @param string $identifier
  * @param string $expectedPrefix
  * @param string $expectedSequence
  * @param string $expectedVariableName
  */
 public function testSequencedIdentifiers($identifier, $expectedPrefix, $expectedSequence, $expectedVariableName)
 {
     $v = new VariableIdentifier($identifier);
     $this->assertEquals($identifier, $v->getIdentifier());
     $this->assertTrue($v->hasPrefix());
     $this->assertTrue($v->hasSequenceNumber());
     $this->assertEquals($expectedPrefix, $v->getPrefix());
     $this->assertEquals($expectedVariableName, $v->getVariableName());
     $this->assertEquals($expectedSequence, $v->getSequenceNumber());
 }
 /**
  * Get the item sessions held by the test session by item reference $identifier.
  * 
  * @param string $identifier An item reference $identifier e.g. Q04. Prefixed or sequenced identifiers e.g. Q04.1.X are considered to be malformed.
  * @return AssessmentItemSessionCollection|false A collection of AssessmentItemSession objects or false if no item session could be found for $identifier.
  * @throws InvalidArgumentException If the given $identifier is malformed.
  */
 public function getAssessmentItemSessions($identifier)
 {
     try {
         $v = new VariableIdentifier($identifier);
         if ($v->hasPrefix() === true || $v->hasSequenceNumber() === true) {
             $msg = "'{$identifier}' is not a valid item reference identifier.";
             throw new InvalidArgumentException($msg, 0);
         }
         $itemRefs = $this->getAssessmentItemRefs();
         if (isset($itemRefs[$identifier]) === false) {
             return false;
         }
         try {
             return $this->getAssessmentItemSessionStore()->getAssessmentItemSessions($itemRefs[$identifier]);
         } catch (OutOfBoundsException $e) {
             return false;
         }
     } catch (InvalidArgumentException $e) {
         $msg = "'{$identifier}' is not a valid item reference identifier.";
         throw new InvalidArgumentException($msg, 0, $e);
     }
 }
 /**
  * Check if a given variable identified by $offset exists in the global scope
  * of the AssessmentTestSession.
  *
  * @return boolean Whether the variable identified by $offset exists in the current context.
  * @throws \OutOfRangeException If $offset is not a simple variable identifier (no prefix, no sequence number).
  */
 public function offsetExists($offset)
 {
     try {
         $v = new VariableIdentifier($offset);
         if ($v->hasPrefix() === true) {
             $msg = "Test existence of a variable in an AssessmentTestSession may only be addressed with simple variable ";
             $msg = "identifiers (no prefix, no sequence number). '" . $v->__toString() . "' given.";
             throw new OutOfRangeException($msg, 0);
         }
         $data =& $this->getDataPlaceHolder();
         return isset($data[$offset]);
     } catch (InvalidArgumentException $e) {
         $msg = "'{$offset}' is not a valid variable identifier.";
         throw new OutOfRangeException($msg);
     }
 }
Exemple #4
0
 /**
  * Perform a branching on a TestPart, AssessmentSection or AssessmentItemRef with
  * the given $identifier.
  * 
  * The target will be considered invalid if the following constraints are not fullfilled:
  * 
  * From IMS QTI:
  * In the case of an item or section, the target must refer to an item or section in the same 
  * testPart that has not yet been presented. For testParts, the target must refer to another testPart.
  *
  * @param string $identifier A QTI Identifier to be the target of the branching.
  * @throws \OutOfBoundsException If an error occurs while branching e.g. the $identifier is not referenced in the route or the target is invalid.
  * @throws \OutOfRangeException If $identifier is not a valid branching identifier.
  */
 public function branch($identifier)
 {
     try {
         $identifier = new VariableIdentifier($identifier);
         $id = $identifier->hasPrefix() === false ? $identifier->getVariableName() : $identifier->getPrefix();
         $occurence = $identifier->hasPrefix() === false ? 0 : intval($identifier->getVariableName() - 1);
     } catch (InvalidArgumentException $e) {
         $msg = "The given identifier '{$identifier}' is an invalid branching target.";
         throw new OutOfRangeException($msg);
     }
     // Check for an assessmentItemRef.
     $assessmentItemRefs = $this->getAssessmentItemRefs();
     if (isset($assessmentItemRefs[$id]) === true) {
         $assessmentItemRefMap = $this->getAssessmentItemRefMap();
         $targetRouteItems = $assessmentItemRefMap[$assessmentItemRefs[$id]];
         if ($targetRouteItems[$occurence]->getTestPart() !== $this->current()->getTestPart()) {
             // From IMS QTI:
             // In case of an item or section, the target must refer to an item or section
             // in the same testPart [...]
             $msg = "Branchings to items outside of the current testPart is forbidden by the QTI 2.1 specification.";
             throw new OutOfBoundsException($msg);
         }
         $this->setPosition($this->getRouteItemPosition($targetRouteItems[$occurence]));
         return;
     }
     // Check for an assessmentSection.
     $assessmentSectionIdentifierMap = $this->getAssessmentSectionIdentifierMap();
     if (isset($assessmentSectionIdentifierMap[$id]) === true) {
         if ($assessmentSectionIdentifierMap[$id][0]->getTestPart() !== $this->current()->getTestPart()) {
             // From IMS QTI:
             // In case of an item or section, the target must refer to an item or section
             // in the same testPart [...]
             $msg = "Branchings to assessmentSections outside of the current testPart is forbidden by the QTI 2.1 specification.";
             throw new OutOfBoundsException($msg);
         }
         // We branch to the first RouteItem belonging to the section.
         $this->setPosition($this->getRouteItemPosition($assessmentSectionIdentifierMap[$id][0]));
         return;
     }
     // Check for a testPart.
     $testPartIdentifierMap = $this->getTestPartIdentifierMap();
     if (isset($testPartIdentifierMap[$id]) === true) {
         // We branch to the first RouteItem belonging to the testPart.
         if ($testPartIdentifierMap[$id][0]->getTestPart() === $this->current()->getTestPart()) {
             // From IMS QTI:
             // For testParts, the target must refer to another testPart.
             $msg = "Cannot branch to the same testPart.";
             throw new OutOfBoundsException($msg);
         }
         // We branch to the first RouteItem belonging to the testPart.
         $this->setPosition($this->getRouteItemPosition($testPartIdentifierMap[$id][0]));
         return;
     }
     // No such identifier referenced in the route, cannot branch.
     $msg = "No such identifier '{$id}' found in the route for branching.";
     throw new OutOfBoundsException($msg);
 }
 /**
  * Process the Variable expression.
  *
  * * If the requested variable does not exist, NULL is returned.
  * * In a test context, if the requested weight does not exist, the raw value of the variable is returned.
  *
  * @returns null|mixed The value of the target variable or NULL if the variable does not exist.
  * @throws \qtism\runtime\expressions\ExpressionProcessingException
  */
 public function process()
 {
     $state = $this->getState();
     $variableIdentifier = $this->getExpression()->getIdentifier();
     $weightIdentifier = $this->getExpression()->getWeightIdentifier();
     $variable = $state->getVariable($variableIdentifier);
     if (empty($variable)) {
         return null;
     }
     $variableValue = $state[$variableIdentifier];
     if ($variable->isNull()) {
         return $variableValue;
         // Even if empty string, it is considered by QTI as null.
     }
     // We have a value for this variable, is it weighted?
     if ($state instanceof AssessmentTestSession) {
         try {
             $vIdentifier = new VariableIdentifier($variableIdentifier);
             if ($vIdentifier->hasPrefix() === true && empty($weightIdentifier) === false) {
                 $weight = $state->getWeight($vIdentifier->getPrefix() . '.' . $weightIdentifier);
                 $baseType = $variableValue->getBaseType();
                 $cardinality = $variableValue->getCardinality();
                 // From IMS QTI:
                 // Weights only apply to item variables with base types integer and float.
                 // If the item variable is of any other type the weight is ignored.
                 if (!empty($weight) && ($baseType === BaseType::INTEGER || $baseType === BaseType::FLOAT)) {
                     if ($cardinality === Cardinality::SINGLE) {
                         return new Float($variableValue->getValue() * $weight->getValue());
                     } elseif ($cardinality === Cardinality::MULTIPLE || $cardinality === Cardinality::ORDERED) {
                         // variableValue is an object, the weighting should not
                         // affect the content of the state so a new container is created.
                         $finalValue = $cardinality === Cardinality::MULTIPLE ? new MultipleContainer(BaseType::FLOAT) : new OrderedContainer(BaseType::FLOAT);
                         for ($i = 0; $i < count($variableValue); $i++) {
                             if ($variableValue[$i] !== null) {
                                 $finalValue[] = new Float($variableValue[$i]->getValue() * $weight->getValue());
                             } else {
                                 $finalValue[] = null;
                             }
                         }
                         return $finalValue;
                     }
                 } else {
                     return $variableValue;
                 }
             } else {
                 return $variableValue;
             }
         } catch (InvalidArgumentException $e) {
             // Invalid $variableIdentifier.
             $msg = "Invalid identifier '{$variableIdentifier}' given for variable identifier.";
             throw new ExpressionProcessingException($msg, $this, ExpressionProcessingException::NONEXISTENT_VARIABLE, $e);
         }
     } else {
         return $variableValue;
     }
 }