/** * Apply the current SetCorrectResponse rule on the current state. * * A RuleProcessingException will be thrown if: * * * No variable corresponds to the given identifier in the current state. * * The target variable is not a ResponseVariable. * * The baseType and/or cardinality of the value to be set does not correspond to the baseType and/or cardinality of the target variable. * * An error occurs while processing the expression representing the value to be set. * * @throws \qtism\runtime\rules\RuleProcessingException */ public function process() { $rule = $this->getRule(); $state = $this->getState(); $variableIdentifier = $rule->getIdentifier(); $var = $state->getVariable($variableIdentifier); if (is_null($var) === true) { $msg = "No variable with identifier '{$variableIdentifier}' to be set in the current state."; throw new RuleProcessingException($msg, $this, RuleProcessingException::NONEXISTENT_VARIABLE); } elseif (!$var instanceof ResponseVariable) { $msg = "The variable to set '{$variableIdentifier}' is not an instance of 'ResponseVariable'."; throw new RuleProcessingException($msg, $this, RuleProcessingException::WRONG_VARIABLE_TYPE); } try { $expressionEngine = new ExpressionEngine($rule->getExpression(), $state); $val = $expressionEngine->process(); $var->setCorrectResponse($val); } catch (InvalidArgumentException $e) { $varBaseType = BaseType::getNameByConstant($var->getBaseType()) === false ? 'noBaseType' : BaseType::getNameByConstant($var->getBaseType()); $varCardinality = Cardinality::getNameByConstant($var->getCardinality()); // The affected value does not match the baseType of the variable $var. $msg = "Unable to set value {$val} to variable '{$variableIdentifier}' (cardinality = {$varCardinality}, baseType = {$varBaseType})."; throw new RuleProcessingException($msg, $this, RuleProcessingException::WRONG_VARIABLE_BASETYPE, $e); } catch (ExpressionProcessingException $e) { $msg = "An error occured while processing the expression bound with the 'SetCorrectResponse' rule."; throw new RuleProcessingException($msg, $this, RuleProcessingException::RUNTIME_ERROR, $e); } }
public static function asArray() { $values = BaseType::asArray(); $values['ANY'] = self::ANY; $values['SAME'] = self::SAME; return $values; }
/** * Unmarshall a DOMElement object corresponding to a QTI variableDeclaration element. * * @param \DOMElement $element A DOMElement object. * @return \qtism\data\QtiComponent A VariableDeclaration object. * @throws \qtism\data\storage\xml\marshalling\UnmarshallingException */ protected function unmarshall(DOMElement $element) { try { // identifier is a mandatory value for the variableDeclaration element. if (($identifier = static::getDOMElementAttributeAs($element, 'identifier')) !== null) { // cardinality is a mandatory value too. if (($cardinality = static::getDOMElementAttributeAs($element, 'cardinality')) !== null) { $object = new VariableDeclaration($identifier, -1, Cardinality::getConstantByName($cardinality)); // deal with baseType. $baseType = static::getDOMElementAttributeAs($element, 'baseType'); if (!empty($baseType)) { $object->setBaseType(BaseType::getConstantByName($baseType)); } // set up optional default value. $defaultValueElements = $element->getElementsByTagName('defaultValue'); if ($defaultValueElements->length == 1) { $defaultValueElement = $defaultValueElements->item(0); $defaultValueMarshaller = $this->getMarshallerFactory()->createMarshaller($defaultValueElements->item(0), array($object->getBaseType())); $object->setDefaultValue($defaultValueMarshaller->unmarshall($defaultValueElement)); } return $object; } else { $msg = "The mandatory attribute 'cardinality' is missing from element '" . $element->localName . "'."; throw new UnmarshallingException($msg, $element); } } else { $msg = "The mandatory attribute 'identifier' is missing from element '" . $element->localName . "'."; throw new UnmarshallingException($msg, $element); } } catch (InvalidArgumentException $e) { $msg = "An unexpected error occured while unmarshalling the variableDeclaration."; throw new UnmarshallingException($msg, $element, $e); } }
/** * Checks whether or not $value: * * * is an instance of OutcomeVariable * * has a 'duration' QTI baseType. * * has 'single' QTI cardinality. * * @throws \InvalidArgumentException If one or more of the conditions above are not respected. */ protected function checkType($value) { parent::checkType($value); if (!$value instanceof OutcomeVariable) { $className = get_class($value); $msg = "The DurationStore only aims at storing OutcomeVariable objects, {$className} object given."; throw new InvalidArgumentException($msg); } if (($bt = $value->getBaseType()) !== BaseType::DURATION) { $baseTypeName = BaseType::getNameByConstant($bt); $msg = "The DurationStore only aims at storing OutcomeVariable objects with a 'duration' baseType, "; $msg .= "'{$baseTypeName}' baseType given "; $id = $value->getIdentifier(); $msg .= "for variable '{$id}'."; throw new InvalidArgumentException($msg); } if (($bt = $value->getCardinality()) !== Cardinality::SINGLE) { $cardinalityName = Cardinality::getNameByConstant($bt); $msg = "The DurationStore only aims at storing OutcomeVariable objects with a 'single' cardinality, "; $msg .= "'{$cardinalityName}' cardinality given "; $id = $value->getIdentifier(); $msg .= "for variable '{$id}'."; throw new InvalidArgumentException($msg); } }
public function setBaseType($baseType = -1) { if (in_array($baseType, BaseType::asArray()) || $baseType == -1) { $this->baseType = $baseType; } else { $msg = "The baseType argument must be a value from the BaseType enumeration."; throw new InvalidArgumentException($msg); } }
/** * Set the base type of the expected targetValue. * * @param integer $baseType A value from the BaseType enumeration. * @throws InvalidArgumentException If $baseType is not a value from the BaseType enumeration. */ protected function setBaseType($baseType) { if (in_array($baseType, BaseType::asArray())) { $this->baseType = $baseType; } else { $msg = "BaseType must be a value from the BaseType enumeration."; throw new InvalidArgumentException($msg); } }
/** * Unmarshall a DOMElement object corresponding to a QTI baseValue element. * * @param \DOMElement $element A DOMElement object. * @return \qtism\data\QtiComponent A BaseValue object. * @throws \qtism\data\storage\xml\marshalling\UnmarshallingException */ protected function unmarshall(DOMElement $element) { if (($baseType = static::getDOMElementAttributeAs($element, 'baseType', 'string')) !== null) { $value = $element->nodeValue; $baseTypeCst = BaseType::getConstantByName($baseType); $object = new BaseValue($baseTypeCst, Utils::stringToDatatype($value, $baseTypeCst)); return $object; } else { $msg = "The mandatory attribute 'baseType' is missing from element '" . $element->localName . "'."; throw new UnmarshallingException($msg, $element); } }
/** * Marshall a testVariable QTI element in its TestVariable object equivalent. * * @param \DOMElement A DOMElement object. * @return \qtism\data\QtiComponent The corresponding TestVariable object. */ protected function unmarshall(DOMElement $element) { $baseComponent = parent::unmarshall($element); if (($variableIdentifier = static::getDOMElementAttributeAs($element, 'variableIdentifier')) !== null) { $object = new TestVariables($variableIdentifier); $object->setSectionIdentifier($baseComponent->getSectionIdentifier()); $object->setIncludeCategories($baseComponent->getIncludeCategories()); $object->setExcludeCategories($baseComponent->getExcludeCategories()); if (($baseType = static::getDOMElementAttributeAs($element, 'baseType')) !== null) { $object->setBaseType(BaseType::getConstantByName($baseType)); } if (($weightIdentifier = static::getDOMElementAttributeAs($element, 'weightIdentifier')) !== null) { $object->setWeightIdentifier($weightIdentifier); } return $object; } else { $msg = "The mandatory attribute 'variableIdentifier' is missing from element '" . $element->localName . "'."; throw new UnmarshallingException($msg, $element); } }
/** * Process the setOutcomeValue/setTemplateValue rule. * * A RuleProcessingException will be thrown if: * * * The variable does not exist. * * The requested variable is not an OutcomeVariable/TemplateVariable. * * The variable's baseType does not match the baseType of the affected value. * * An error occurs while processing 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 = "No variable with identifier '{$identifier}' to be set in the current state."; throw new RuleProcessingException($msg, $this, RuleProcessingException::NONEXISTENT_VARIABLE); } elseif (Reflection::isInstanceOf($var, $this->getVariableType()) === false) { $msg = "The variable to set '{$identifier}' is not an instance of '" . $this->getVariableType() . "'."; throw new RuleProcessingException($msg, $this, RuleProcessingException::WRONG_VARIABLE_TYPE); } // Process the expression. // Its result will be the value to set to the target variable. try { $expressionEngine = new ExpressionEngine($rule->getExpression(), $state); $val = $expressionEngine->process(); } catch (ExpressionProcessingException $e) { $msg = "An error occured while processing the expression bound with the '" . Reflection::shortClassName($rule) . "' rule."; throw new RuleProcessingException($msg, $this, RuleProcessingException::RUNTIME_ERROR, $e); } // The variable exists, its new value is processed. try { // juggle a little bit (int -> float, float -> int) if ($val !== null && $var->getCardinality() === Cardinality::SINGLE) { $baseType = $var->getBaseType(); if ($baseType === BaseType::INTEGER && $val instanceof Float) { $val = new Integer(intval($val->getValue())); } elseif ($baseType === BaseType::FLOAT && $val instanceof Integer) { $val = new Float(floatval($val->getValue())); } } $var->setValue($val); } catch (InvalidArgumentException $e) { $varBaseType = BaseType::getNameByConstant($var->getBaseType()) === false ? 'noBaseType' : BaseType::getNameByConstant($var->getBaseType()); $varCardinality = Cardinality::getNameByConstant($var->getCardinality()); // The affected value does not match the baseType of the variable $var. $msg = "Unable to set value {$val} to variable '{$identifier}' (cardinality = {$varCardinality}, baseType = {$varBaseType})."; throw new RuleProcessingException($msg, $this, RuleProcessingException::WRONG_VARIABLE_BASETYPE, $e); } }
/** * Unmarshall a DOMElement object corresponding to a QTI MatchTable element. * * @param DOMElement $element A DOMElement object. * @return QtiComponent A MatchTable object. * @throws UnmarshallingException If the $element to unmarshall has no matchTableEntry children. */ protected function unmarshall(DOMElement $element) { $matchTableEntryElements = $element->getElementsByTagName('matchTableEntry'); if ($matchTableEntryElements->length > 0) { $matchTableEntries = new MatchTableEntryCollection(); for ($i = 0; $i < $matchTableEntryElements->length; $i++) { $marshaller = $this->getMarshallerFactory()->createMarshaller($matchTableEntryElements->item($i), array($this->getBaseType())); $matchTableEntries[] = $marshaller->unmarshall($matchTableEntryElements->item($i)); } $object = new MatchTable($matchTableEntries); if (($defaultValue = static::getDOMElementAttributeAs($element, 'defaultValue')) !== null) { try { $defaultValue = Utils::stringToDatatype($defaultValue, $this->getBaseType()); $object->setDefaultValue($defaultValue); } catch (InvalidArgumentException $e) { $strType = BaseType::getNameByConstant($this->getBaseType()); $msg = "Unable to transform '{$defaultValue}' in a {$strType}."; throw new UnmarshallingException($msg, $element, $e); } } return $object; } else { $msg = "A QTI matchTable element must contain at least one matchTableEntry element."; throw new UnmarshallingException($msg, $element); } }
/** * Transform a PCI JSON representation of QTI data into the QTISM runtime model. * * @param string|array $json The json data to be transformed. * @throws UnmarshallingException If an error occurs while processing $json. * @return null|qtism\common\datatypes\QtiDataType|array */ public function unmarshall($json) { if (is_string($json) === true) { $tmpJson = @json_decode($json, true); if ($tmpJson === null) { // An error occured while decoding. $msg = "An error occured while decoding the following JSON data '" . mb_substr($json, 0, 30, 'UTF-8') . "...'."; $code = UnmarshallingException::JSON_DECODE; throw new UnmarshallingException($msg, $code); } $json = $tmpJson; } if (is_array($json) === false || count($json) === 0) { $msg = "The '" . get_class($this) . "::unmarshall' method only accepts a JSON string or a non-empty array as argument, '"; if (is_object($json) === true) { $msg .= get_class($json); } else { $msg .= gettype($json); } $msg .= "' given."; $code = UnmarshallingException::NOT_SUPPORTED; throw new UnmarshallingException($msg, $code); } if (Arrays::isAssoc($json) === false) { $msg = "The '" . get_class($this) . "::unmarshall' does not accepts non-associative arrays."; $code = UnmarshallingException::NOT_SUPPORTED; throw new UnmarshallingException($msg, $code); } // Check whether or not $json is a state (no 'base' nor 'list' keys found), // a base, a list or a record. $keys = array_keys($json); if (in_array('base', $keys) === true) { // This is a base. return $this->unmarshallUnit($json); } else { if (in_array('list', $keys) === true) { $keys = array_keys($json['list']); if (isset($keys[0]) === false) { $msg = "No baseType provided for list."; throw new UnmarshallingException($msg, UnmarshallingException::NOT_PCI); } $baseType = BaseType::getConstantByName($keys[0]); if ($baseType === false) { $msg = "Unknown QTI baseType '" . $keys[0] . "'."; $code = UnmarshallingException::NOT_PCI; throw new UnmarshallingException($msg, $code); } $returnValue = new MultipleContainer($baseType); // This is a list. foreach ($json['list'][$keys[0]] as $v) { try { if ($v === null) { $returnValue[] = $this->unmarshallUnit(array('base' => $v)); } else { $returnValue[] = $this->unmarshallUnit(array('base' => array($keys[0] => $v))); } } catch (InvalidArgumentException $e) { $strBaseType = BaseType::getNameByConstant($baseType); $msg = "A value is not compliant with the '{$strBaseType}' baseType."; $code = UnmarshallingException::NOT_PCI; throw new UnmarshallingException($msg, $code); } } return $returnValue; } else { if (in_array('record', $keys) === true) { // This is a record. $returnValue = new RecordContainer(); if (count($json['record']) === 0) { return $returnValue; } foreach ($json['record'] as $v) { if (isset($v['name']) === false) { $msg = "No 'name' key found in record field."; $code = UnmarshallingException::NOT_PCI; throw new UnmarshallingException($msg, $code); } if (isset($v['base']) === true || array_key_exists('base', $v) && $v['base'] === null) { $unit = array('base' => $v['base']); } else { // No value found, let's go for a null value. $unit = array('base' => null); } $returnValue[$v['name']] = $this->unmarshallUnit($unit); } return $returnValue; } else { // This is a state. $state = array(); foreach ($json as $k => $j) { $state[$k] = $this->unmarshall($j); } return $state; } } } }
/** * Process the MapResponsePoint Expression. * * An ExpressionProcessingException is throw if: * * * The expression's identifier attribute does not point a variable in the current State object. * * The targeted variable is not a ResponseVariable object. * * The targeted variable has no areaMapping. * * The target variable has the RECORD cardinality. * * @return float A transformed float value according to the areaMapping of the target variable. * @throws \qtism\runtime\expressions\ExpressionProcessingException */ public function process() { $expr = $this->getExpression(); $identifier = $expr->getIdentifier(); $state = $this->getState(); $var = $state->getVariable($identifier); if (!is_null($var)) { if ($var instanceof ResponseVariable) { $areaMapping = $var->getAreaMapping(); if (!is_null($areaMapping)) { // Correct cardinality ? if ($var->getBaseType() === BaseType::POINT && ($var->isSingle() || $var->isMultiple())) { // We can begin! // -- Null value, nothing will match if ($var->isNull()) { return new Float($areaMapping->getDefaultValue()); } if ($var->isSingle()) { $val = new MultipleContainer(BaseType::POINT, array($state[$identifier])); } else { $val = $state[$identifier]; } $result = 0; $mapped = array(); foreach ($val as $point) { foreach ($areaMapping->getAreaMapEntries() as $areaMapEntry) { $coords = $areaMapEntry->getCoords(); if (!in_array($coords, $mapped) && $coords->inside($point)) { $mapped[] = $coords; $result += $areaMapEntry->getMappedValue(); } } } // If no relevant mapping found, return the default. if (count($mapped) === 0) { return new Float($areaMapping->getDefaultValue()); } else { // Check upper and lower bound. if ($areaMapping->hasLowerBound() && $result < $areaMapping->getLowerBound()) { return new Float($areaMapping->getLowerBound()); } elseif ($areaMapping->hasUpperBound() && $result > $areaMapping->getUpperBound()) { return new Float($areaMapping->getUpperBound()); } else { return new Float(floatval($result)); } } } else { if ($var->isRecord()) { $msg = "The MapResponsePoint expression cannot be applied to RECORD variables."; throw new ExpressionProcessingException($msg, $this, ExpressionProcessingException::WRONG_VARIABLE_CARDINALITY); } else { $strBaseType = BaseType::getNameByConstant($var->getBaseType()); $msg = "The MapResponsePoint expression applies only on variables with baseType 'point', baseType '{$strBaseType}' given."; throw new ExpressionProcessingException($msg, $this, ExpressionProcessingException::WRONG_VARIABLE_BASETYPE); } } } else { $msg = "Variable with identifier '{$identifier}' has no areaMapping."; throw new ExpressionProcessingException($msg, $this, ExpressionProcessingException::INCONSISTENT_VARIABLE); } } else { $msg = "The variable with identifier '{$identifier}' is not a ResponseVariable."; throw new ExpressionProcessingException($msg, $this, ExpressionProcessingException::WRONG_VARIABLE_TYPE); } } else { $msg = "No variable with identifier '{$identifier}' could be found in the current State object."; throw new ExpressionProcessingException($msg, $this, ExpressionProcessingException::NONEXISTENT_VARIABLE); } }
/** * Transmit a test-level QtiSm Runtime Variable to the target Result Server as a test result. * * @param mixed $variable An OutcomeVariable object to be transmitted to the target Result Server. * @param string $transmissionId A unique identifier that identifies uniquely the visited test. * @param string $testUri An optional URL that identifies uniquely the test the $variable comes from. */ public function transmitTestVariable($variable, $transmissionId, $testUri = '') { $resultVariable = new taoResultServer_models_classes_OutcomeVariable(); $resultVariable->setIdentifier($variable->getIdentifier()); $resultVariable->setBaseType(BaseType::getNameByConstant($variable->getBaseType())); $resultVariable->setCardinality(Cardinality::getNameByConstant($variable->getCardinality())); $value = $variable->getValue(); $resultVariable->setValue(self::transformValue($value)); try { $this->getResultServer()->storeTestVariable($testUri, $resultVariable, $transmissionId); } catch (Exception $e) { $msg = "An error occured while transmitting a Response Variable to the target result server."; $code = taoQtiCommon_helpers_ResultTransmissionException::OUTCOME; throw new taoQtiCommon_helpers_ResultTransmissionException($msg, $code); } }
/** * Unmarshall a DOMElement object corresponding to a QTI Value element. * * @param \DOMElement $element A DOMElement object. * @return \qtism\data\QtiComponent A Value object. * @throws \qtism\data\storage\xml\marshalling\UnmarshallingException If the 'baseType' attribute is not a valid QTI baseType. */ protected function unmarshall(DOMElement $element) { $object = null; if (($baseType = static::getDOMElementAttributeAs($element, 'baseType', 'string')) !== null) { // baseType attribute is set -> part of a record. $baseTypeCst = BaseType::getConstantByName($baseType); if ($baseTypeCst !== false) { $object = new Value(Utils::stringToDatatype(trim($element->nodeValue), $baseTypeCst), $baseTypeCst); $object->setPartOfRecord(true); } else { $msg = "The 'baseType' attribute value ('{$value}') is not a valid QTI baseType in element '" . $element->localName . "'."; throw new UnmarshallingException($msg, $element); } } else { // baseType attribute not set -> not part of a record. $nodeValue = trim($element->nodeValue); if ($nodeValue !== '') { // Try to use the marshaller as parametric to know how to unserialize the value. if ($this->getBaseType() != -1) { $object = new Value(Utils::stringToDatatype($nodeValue, $this->getBaseType()), $this->getBaseType()); } else { // value used as plain string (at your own risks). $object = new Value($nodeValue); } } else { $msg = "The element '" . $element->localName . "' has no value."; throw new UnmarshallingException($msg, $element); } } if (($value = static::getDOMElementAttributeAs($element, 'fieldIdentifier', 'string')) !== null) { $object->setFieldIdentifier($value); } return $object; }
/** * Transform a TAO serialized result value to its QtiDatatype equivalent. * * This method transforms a TAO serialized result $value to a the equivalent QtiDatatype depending * on result's $cardinality and $baseType. * * Note: at the present time, this implementation only supports 'single', 'multiple', and 'ordered' cardinality in conjunction * with the 'identifier', 'boolean', 'pair' or 'directedPair' baseType. * * @param string $cardinality i.e. 'ordered', 'multiple' or 'single'. * @param string $basetype i.e. 'identifier' * @param string $value A TAO serialized result value e.g. '<choice1 choice2 choice3>' * @return mixed A QtiDatatype object or null in case of no possibility to transform $value in the appropriate target $cardinality and $basetype. */ public static function toQtiDatatype($cardinality, $basetype, $value) { // @todo support all baseTypes $datatype = null; if (is_string($value) && empty($value) === false && $cardinality !== 'record' && ($basetype === 'identifier' || $basetype === 'pair' || $basetype === 'directedPair' || $basetype === 'boolean')) { if ($cardinality !== 'simple') { $value = trim($value, "<>[]"); $value = explode(';', $value); } else { $value = array($value); } if (count($value) === 1 && empty($value[0]) === true) { $value = array(); } $value = array_map(function ($val) { return trim($val); }, $value); $qtiBasetype = BaseType::getConstantByName($basetype); $datatype = $cardinality === 'ordered' ? new OrderedContainer($qtiBasetype) : new MultipleContainer($qtiBasetype); foreach ($value as $val) { try { switch ($basetype) { case 'identifier': $datatype[] = new QtiIdentifier($val); break; case 'pair': $pair = explode(" ", $val); if (count($pair) === 2) { $datatype[] = new QtiPair($pair[0], $pair[1]); } break; case 'directedPair': $pair = explode(" ", $val); if (count($pair) === 2) { $datatype[] = new QtiDirectedPair($pair[0], $pair[1]); } break; case 'boolean': if ($val === 'true') { $datatype[] = new QtiBoolean(true); } elseif ($val === 'false') { $datatype[] = new QtiBoolean(false); } else { $datatype[] = new QtiBoolean($val); } break; } } catch (InvalidArgumentException $e) { $datatype = null; break; } } $datatype = $cardinality === 'single' ? isset($datatype[0]) ? $datatype[0] : null : $datatype; } return $datatype; }
/** * Marshall a single unit of QTI data. * * @param \qtism\runtime\common\State|\qtism\common\datatypes\QtiDatatype|null $unit * @return array An array representing the JSON data to be encoded later on. */ protected function marshallUnit($unit) { if (is_null($unit) === true) { $json = array('base' => null); } elseif ($unit instanceof QtiScalar) { $json = $this->marshallScalar($unit); } elseif ($unit instanceof MultipleContainer) { $json = array(); $strBaseType = BaseType::getNameByConstant($unit->getBaseType()); $json['list'] = array($strBaseType => array()); foreach ($unit as $u) { $data = $this->marshallUnit($u); $json['list'][$strBaseType][] = $data['base'][$strBaseType]; } } elseif ($unit instanceof RecordContainer) { $json = array(); $json['record'] = array(); foreach ($unit as $k => $u) { $data = $this->marshallUnit($u); $jsonEntry = array(); $jsonEntry['name'] = $k; if (isset($data['base']) === true || $data['base'] === null) { // Primitive base type. $jsonEntry['base'] = $data['base']; } else { // A nested list. $jsonEntry['list'] = $data['list']; } $json['record'][] = $jsonEntry; } } else { $json = $this->marshallComplex($unit); } return $json; }
/** * Transform a string representing a QTI valueType value in a * the correct datatype. * * @param string $string The QTI valueType value as a string. * @param integer $baseType The QTI baseType that defines the datatype of $string. * @return mixed A converted object/primitive type. * @throws \InvalidArgumentException If $baseType is not a value from the BaseType enumeration. * @throws \UnexpectedValueException If $string cannot be transformed in a Value expression with the given $baseType. */ public static function stringToDatatype($string, $baseType) { if (in_array($baseType, BaseType::asArray())) { $value = null; switch ($baseType) { case BaseType::BOOLEAN: if (Format::isBoolean($string)) { $value = Format::toLowerTrim($string) == 'true' ? true : false; return $value; } else { $msg = "'{$string}' cannot be transformed into boolean."; throw new UnexpectedValueException($msg); } break; case BaseType::INTEGER: if (Format::isInteger($string)) { $value = intval($string); return $value; } else { $msg = "'{$string}' cannot be transformed into integer."; throw new UnexpectedValueException($msg); } break; case BaseType::FLOAT: if (Format::isFloat($string)) { $value = floatval($string); return $value; } else { $msg = "'{$string}' cannot be transformed into float."; throw new UnexpectedValueException($msg); } break; case BaseType::URI: if (Format::isUri($string)) { return $string; } else { $msg = "'{$string}' is not a valid URI."; throw new UnexpectedValueException($msg); } break; case BaseType::IDENTIFIER: if (Format::isIdentifier($string)) { return $string; } else { $msg = "'{$string}' is not a valid QTI Identifier."; throw new UnexpectedValueException($msg); } break; case BaseType::INT_OR_IDENTIFIER: if (Format::isIdentifier($string)) { return $string; } elseif (Format::isInteger($string)) { return intval($string); } else { $msg = "'{$string}' is not a valid QTI Identifier nor a valid integer."; throw new UnexpectedValueException($msg); } break; case BaseType::PAIR: if (Format::isPair($string)) { $pair = explode(" ", $string); return new Pair($pair[0], $pair[1]); } else { $msg = "'{$string}' is not a valid pair."; throw new UnexpectedValueException($msg); } break; case BaseType::DIRECTED_PAIR: if (Format::isDirectedPair($string)) { $pair = explode(" ", $string); return new DirectedPair($pair[0], $pair[1]); } else { $msg = "'{$string}' is not a valid directed pair."; throw new UnexpectedValueException($msg); } break; case BaseType::DURATION: if (Format::isDuration($string)) { return new Duration($string); } else { $msg = "'{$string}' is not a valid duration."; throw new UnexpectedValueException($msg); } break; case BaseType::FILE: throw new \RuntimeException("Unsupported baseType: file."); break; case BaseType::STRING: return '' . $string; break; case BaseType::POINT: if (Format::isPoint($string)) { $parts = explode(" ", $string); return new Point(intval($parts[0]), intval($parts[1])); } else { $msg = "'{$string}' is not valid point."; throw new UnexpectedValueException($msg); } break; default: throw new \RuntimeException("Unknown baseType."); break; } } else { $msg = "BaseType must be a value from the BaseType enumeration."; throw new InvalidArgumentException($msg); } }
/** * Write a record field value in the current binary stream. A record field is composed of a key string and a value. * * @param array $recordField An array where index 0 is the key string, and the index 1 is the value. * @throws QtiBinaryStreamAccessException */ public function writeRecordField(array $recordField, $isNull = false) { try { $this->writeBoolean($isNull); $key = $recordField[0]; $this->writeString($key); if ($isNull === false) { $value = $recordField[1]; $baseType = Utils::inferBaseType($value); $this->writeTinyInt($baseType); $toCall = 'write' . ucfirst(BaseType::getNameByConstant($baseType)); call_user_func(array($this, $toCall), $value instanceof Scalar ? $value->getValue() : $value); } } catch (BinaryStreamAccessException $e) { $msg = "An error occured while reading a Record Field."; throw new QtiBinaryStreamAccessException($msg, $this, QtiBinaryStreamAccessException::RECORDFIELD); } }
/** * Throw an InvalidArgumentException depending on a given qti:baseType * and an in-memory PHP value. * * @param int $baseType A value from the BaseType enumeration. * @param mixed $value A given PHP primitive value. * @throws \InvalidArgumentException In any case. */ public static function throwBaseTypeTypingError($baseType, $value) { $givenValue = gettype($value) == 'object' ? get_class($value) : gettype($value) . ':' . $value; $acceptedTypes = BaseType::getNameByConstant($baseType); $msg = "The value '{$givenValue}' is not compliant with the '{$acceptedTypes}' baseType."; throw new InvalidArgumentException($msg); }
/** * @dataProvider invalidBaseTypeConstantProvider */ public function testGetNameByConstantInvalidBaseType($constant) { $this->assertFalse(BaseType::getNameByConstant($constant)); }