/**
  * 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);
     }
 }
 /**
  * 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 = Cardinality::asArray();
     $values['SAME'] = self::SAME;
     $values['ANY'] = self::ANY;
     return $values;
 }
Exemple #4
0
 /**
  * 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);
     }
 }
 /**
  * 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);
     }
 }
 /**
  * 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);
     }
 }
Exemple #7
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);
         }
     }
 }
 /**
  * Get trace variable instance to save.
  * 
  * @param string $identifier
  * @param string $value
  * @return \taoResultServer_models_classes_TraceVariable variable instance to save.
  */
 private function getVariable($identifier, $value)
 {
     $metaVariable = new \taoResultServer_models_classes_TraceVariable();
     $metaVariable->setIdentifier($identifier);
     $metaVariable->setBaseType('string');
     $metaVariable->setCardinality(Cardinality::getNameByConstant(Cardinality::SINGLE));
     $metaVariable->setTrace($value);
     return $metaVariable;
 }
 /**
  * Set the cardinality of the variable.
  *
  * @param int $cardinality A value from the Cardinality enumeration.
  * @throws \InvalidArgumentException If $cardinality is not a value from the Cardinality enumeration.
  */
 public function setCardinality($cardinality)
 {
     if (in_array($cardinality, Cardinality::asArray())) {
         $this->cardinality = $cardinality;
     } else {
         $msg = "The cardinality must be a value from the Cardinality enumeration.";
         throw new InvalidArgumentException($msg);
     }
 }
 public function getQtiResultXml($deliveryId, $resultId)
 {
     $delivery = new \core_kernel_classes_Resource($deliveryId);
     $resultService = $this->getServiceLocator()->get(ResultServerService::SERVICE_ID);
     $resultServer = $resultService->getResultStorage($deliveryId);
     $crudService = new CrudResultsService();
     $dom = new \DOMDocument('1.0', 'UTF-8');
     $dom->formatOutput = true;
     $itemResults = $crudService->format($resultServer, $resultId, CrudResultsService::GROUP_BY_ITEM);
     $testResults = $crudService->format($resultServer, $resultId, CrudResultsService::GROUP_BY_TEST);
     $assessmentResultElt = $dom->createElementNS(self::QTI_NS, 'assessmentResult');
     $dom->appendChild($assessmentResultElt);
     /** Context */
     $contextElt = $dom->createElementNS(self::QTI_NS, 'context');
     $contextElt->setAttribute('sourcedId', \tao_helpers_Uri::getUniqueId($resultServer->getTestTaker($resultId)));
     $assessmentResultElt->appendChild($contextElt);
     /** Test Result */
     foreach ($testResults as $testResultIdentifier => $testResult) {
         $identifierParts = explode('.', $testResultIdentifier);
         $testIdentifier = array_pop($identifierParts);
         $testResultElement = $dom->createElementNS(self::QTI_NS, 'testResult');
         $testResultElement->setAttribute('identifier', $testIdentifier);
         $testResultElement->setAttribute('datestamp', \tao_helpers_Date::displayeDate($testResult[0]['epoch'], \tao_helpers_Date::FORMAT_ISO8601));
         /** Item Variable */
         foreach ($testResult as $itemVariable) {
             $isResponseVariable = $itemVariable['type']->getUri() === 'http://www.tao.lu/Ontologies/TAOResult.rdf#ResponseVariable';
             $testVariableElement = $dom->createElementNS(self::QTI_NS, $isResponseVariable ? 'responseVariable' : 'outcomeVariable');
             $testVariableElement->setAttribute('identifier', $itemVariable['identifier']);
             $testVariableElement->setAttribute('cardinality', $itemVariable['cardinality']);
             $testVariableElement->setAttribute('baseType', $itemVariable['basetype']);
             $valueElement = $this->createCDATANode($dom, 'value', trim($itemVariable['value']));
             if ($isResponseVariable) {
                 $candidateResponseElement = $dom->createElementNS(self::QTI_NS, 'candidateResponse');
                 $candidateResponseElement->appendChild($valueElement);
                 $testVariableElement->appendChild($candidateResponseElement);
             } else {
                 $testVariableElement->appendChild($valueElement);
             }
             $testResultElement->appendChild($testVariableElement);
         }
         $assessmentResultElt->appendChild($testResultElement);
     }
     /** Item Result */
     foreach ($itemResults as $itemResultIdentifier => $itemResult) {
         // Retrieve identifier.
         $identifierParts = explode('.', $itemResultIdentifier);
         $occurenceNumber = array_pop($identifierParts);
         $refIdentifier = array_pop($identifierParts);
         $itemElement = $dom->createElementNS(self::QTI_NS, 'itemResult');
         $itemElement->setAttribute('identifier', $refIdentifier);
         $itemElement->setAttribute('datestamp', \tao_helpers_Date::displayeDate($itemResult[0]['epoch'], \tao_helpers_Date::FORMAT_ISO8601));
         $itemElement->setAttribute('sessionStatus', 'final');
         /** Item variables */
         foreach ($itemResult as $key => $itemVariable) {
             $isResponseVariable = $itemVariable['type']->getUri() === 'http://www.tao.lu/Ontologies/TAOResult.rdf#ResponseVariable';
             if ($itemVariable['identifier'] == 'comment') {
                 /** Comment */
                 $itemVariableElement = $dom->createElementNS(self::QTI_NS, 'candidateComment', $itemVariable['value']);
             } else {
                 /** Item variable */
                 $itemVariableElement = $dom->createElementNS(self::QTI_NS, $isResponseVariable ? 'responseVariable' : 'outcomeVariable');
                 $itemVariableElement->setAttribute('identifier', $itemVariable['identifier']);
                 $itemVariableElement->setAttribute('cardinality', $itemVariable['cardinality']);
                 $itemVariableElement->setAttribute('baseType', $itemVariable['basetype']);
                 /** Split multiple response */
                 $itemVariable['value'] = trim($itemVariable['value'], '[]');
                 if ($itemVariable['cardinality'] !== Cardinality::getNameByConstant(Cardinality::SINGLE)) {
                     $values = explode(';', $itemVariable['value']);
                     $returnValue = [];
                     foreach ($values as $value) {
                         $returnValue[] = $this->createCDATANode($dom, 'value', $value);
                     }
                 } else {
                     $returnValue = $this->createCDATANode($dom, 'value', $itemVariable['value']);
                 }
                 /** Get response parent element */
                 if ($isResponseVariable) {
                     /** Response variable */
                     $responseElement = $dom->createElementNS(self::QTI_NS, 'candidateResponse');
                 } else {
                     /** Outcome variable */
                     $responseElement = $itemVariableElement;
                 }
                 /** Write a response node foreach answer  */
                 if (is_array($returnValue)) {
                     foreach ($returnValue as $valueElement) {
                         $responseElement->appendChild($valueElement);
                     }
                 } else {
                     $responseElement->appendChild($returnValue);
                 }
                 if ($isResponseVariable) {
                     $itemVariableElement->appendChild($responseElement);
                 }
             }
             $itemElement->appendChild($itemVariableElement);
         }
         $assessmentResultElt->appendChild($itemElement);
     }
     return $dom->saveXML();
 }