Пример #1
0
 /**
  * @see \qtism\runtime\common\Processable::process()
  */
 public function process()
 {
     $expression = $this->getExpression();
     return RuntimeUtils::valueToRuntime($expression->getValue(), $expression->getBaseType());
 }
Пример #2
0
 /**
  * Create a Container object from a Data Model ValueCollection object.
  *
  * @param \qtism\data\state\ValueCollection $valueCollection A collection of qtism\data\state\Value objects.
  * @return \qtism\common\collections\Container A Container object populated with the values found in $valueCollection.
  * @throws \InvalidArgumentException If a value from $valueCollection is not compliant with the QTI Runtime Model or the container type.
  */
 public static function createFromDataModel(ValueCollection $valueCollection)
 {
     $container = new static();
     foreach ($valueCollection as $value) {
         $container[] = RuntimeUtils::valueToRuntime($value->getValue(), $value->getBaseType());
     }
     return $container;
 }
Пример #3
0
 /**
  * Create a QTI Runtime value from Data Model ValueCollection
  *
  * @param \qtism\data\state\ValueCollection $valueCollection A collection of qtism\data\state\Value objects.
  * @param integer $baseType The baseType the Value objects in the ValueCollection must respect.
  * @param integer $cardinality The cardinality the Value objects in the ValueCollection must respect.
  * @throws \UnexpectedValueException If $baseType or/and $cardinality are not respected by the Value objects in the ValueCollection.
  * @return mixed The resulting QTI Runtime value (primitive or container depending on baseType/cardinality).
  */
 protected static function dataModelValuesToRuntime(ValueCollection $valueCollection, $baseType, $cardinality)
 {
     // Cardinality?
     // -> Single? Multiple? Ordered? Record?
     if ($cardinality === Cardinality::SINGLE) {
         // We should find a single value in the DefaultValue's values.
         if (count($valueCollection) == 1) {
             $dataModelValue = RuntimeUtils::valueToRuntime($valueCollection[0]->getValue(), $baseType);
             return $dataModelValue;
         } else {
             // The Data Model is in an inconsistent state.
             // This should be handled by the Data Model but
             // I prefer to be defensive.
             $msg = "A Data Model VariableDeclaration with 'single' cardinality must contain a single value, ";
             $msg .= count($valueCollection) . " value(s) found.";
             throw new UnexpectedValueException($msg);
         }
     } else {
         // Multiple|Ordered|Record, use a container.
         $container = null;
         try {
             // Create the appropriate Container object.
             $className = ucfirst(Cardinality::getNameByConstant($cardinality)) . 'Container';
             $nsClassName = 'qtism\\runtime\\common\\' . $className;
             $callback = array($nsClassName, 'createFromDataModel');
             $container = call_user_func_array($callback, array($valueCollection, $baseType));
             return $container;
             // return container.
         } catch (InvalidArgumentException $e) {
             $msg = "The default value found in the Data Model Variable Declaration is not consistent. ";
             $msg .= "The values must have a baseType compliant with the baseType of the VariableDeclaration.";
             $msg .= "If the VariableDeclaration's cardinality is 'record', make sure the values it contains have ";
             $msg .= "fieldIdentifiers.";
             throw new UnexpectedValueException($msg, 0, $e);
         }
     }
 }
 /**
  * Process the LookupOutcomeValue rule.
  *
  * A RuleProcessingException will be thrown if:
  *
  * * The outcome variable to set does not exist.
  * * The variable to set is not an OutcomeVariable
  * * The outcome variable's baseType does not match the baseType of the affected value (the result of the bound expression).
  * * The outcome variable's declaration has no associated lookup table.
  * * The variable's declaration contains a matchTable but the result of the bound expression is not an integer.
  * * The variable's declaration contains an interpolationTable but the result of the bound expression is not an integer, nor a float.
  * * There is no associated table in the variable's declaration.
  * * An error occurs during the processing of the related expression.
  *
  * @throws \qtism\runtime\rules\RuleProcessingException If one of the error described above arise.
  */
 public function process()
 {
     $state = $this->getState();
     $rule = $this->getRule();
     $identifier = $rule->getIdentifier();
     $var = $state->getVariable($identifier);
     if (is_null($var) === true) {
         $msg = "The variable to set '{$identifier}' does not exist in the current state.";
         throw new RuleProcessingException($msg, $this, RuleProcessingException::NONEXISTENT_VARIABLE);
     } elseif (!$var instanceof OutcomeVariable) {
         $msg = "The variable to set '{$identifier}' is not an OutcomeVariable.";
         throw new RuleProcessingException($msg, $this, RuleProcessingException::WRONG_VARIABLE_TYPE);
     }
     $expression = $rule->getExpression();
     $expressionEngine = new ExpressionEngine($expression, $state);
     try {
         $val = $expressionEngine->process();
         // Let's lookup the associated table.
         $table = $var->getLookupTable();
         if (is_null($table) === true) {
             $msg = "No lookupTable in declaration of variable '{$identifier}'.";
             throw new RuleProcessingException($msg, $this, RuleProcessingException::LOGIC_ERROR);
         }
         // $targetVal = The value that will be set to the target variable.
         //
         // As per specs:
         // The default outcome value to be used when no matching table
         // entry is found. If omitted, the NULL value is used.
         $targetVal = $table->getDefaultValue();
         if ($table instanceof InterpolationTable) {
             if (!$val instanceof Float && !$val instanceof Integer && !$val instanceof Duration) {
                 $msg = "The value of variable '{$identifier}' must be integer, float or duration when used with an interpolationTable";
                 throw new RuleProcessingException($msg, $this, RuleProcessingException::LOGIC_ERROR);
             }
             foreach ($table->getInterpolationTableEntries() as $entry) {
                 $lowerBound = $entry->getSourceValue();
                 $includeBoundary = $entry->doesIncludeBoundary();
                 if ($includeBoundary === true && $val->getValue() <= $lowerBound) {
                     $targetVal = $entry->getTargetValue();
                     break;
                 } elseif ($includeBoundary === false && $val->getValue() < $lowerBound) {
                     $targetVal = $entry->getTargetValue();
                     break;
                 }
             }
         } else {
             // $table instanceof MatchTable
             if (!$val instanceof Integer) {
                 $msg = "The value of the variable '{$identifier}' must be integer when used with a matchTable.";
                 throw new RuleProcessingException($msg, $this, RuleProcessingException::LOGIC_ERROR);
             }
             foreach ($table->getMatchTableEntries() as $entry) {
                 if ($entry->getSourceValue() === $val->getValue()) {
                     $targetVal = $entry->getTargetValue();
                     break;
                 }
             }
         }
         // assign target value
         try {
             $finalVal = RuntimeUtils::valueToRuntime($targetVal, $var->getBaseType());
             $state[$identifier] = $finalVal;
         } catch (InvalidArgumentException $e) {
             // $targetVal's baseType not compliant with target variable's baseType.
             $msg = "The looked up value's baseType is not compliant with the baseType of variable '{$identifier}'.";
             throw new RuleProcessingException($msg, $this, RuleProcessingException::RUNTIME_ERROR);
         }
     } catch (ExpressionProcessingException $e) {
         $msg = "An error occured while processing the expression bound to the lookupOutcomeValue rule.";
         throw new RuleProcessingException($msg, $this, RuleProcessingException::RUNTIME_ERROR, $e);
     }
 }
Пример #5
0
 /**
  * Create a RecordContainer object from a Data Model ValueCollection object.
  *
  * @param \qtism\data\state\ValueCollection $valueCollection A collection of qtism\data\state\Value objects.
  * @return \qtism\runtime\common\RecordContainer A Container object populated with the values found in $valueCollection.
  * @throws \InvalidArgumentException If a value from $valueCollection is not compliant with the QTI Runtime Model or the container type or if a value has no fieldIdentifier.
  */
 public static function createFromDataModel(ValueCollection $valueCollection)
 {
     $container = new static();
     foreach ($valueCollection as $value) {
         $fieldIdentifier = $value->getFieldIdentifier();
         if (!empty($fieldIdentifier)) {
             $container[$value->getFieldIdentifier()] = RuntimeUtils::valueToRuntime($value->getValue(), $value->getBaseType());
         } else {
             $msg = "Cannot include qtism\\data\\state\\Value '" . $value->getValue() . "' in the RecordContainer ";
             $msg .= "because it has no fieldIdentifier specified.";
             throw new InvalidArgumentException($msg);
         }
     }
     return $container;
 }
 /**
  * Read a record field value from the current binary stream. A record field is
  * composed of a key string and a value.
  * 
  * @return array An array where the value at index 0 is the key string and index 1 is the value.
  * @throws QtiBinaryStreamAccessException
  */
 public function readRecordField($isNull = false)
 {
     try {
         $key = $this->readString();
         if ($isNull === false) {
             $baseType = $this->readTinyInt();
             $toCall = 'read' . ucfirst(BaseType::getNameByConstant($baseType));
             $value = Utils::valueToRuntime(call_user_func(array($this, $toCall)), $baseType);
         } else {
             $value = null;
         }
         return array($key, $value);
     } catch (BinaryStreamAccessException $e) {
         $msg = "An error occured while reading a Record Field.";
         throw new QtiBinaryStreamAccessException($msg, $this, QtiBinaryStreamAccessException::RECORDFIELD, $e);
     }
 }