* @package taoQTI * @see http://www.imsglobal.org/question/qtiv2p1/imsqti_infov2p1.html#element10073 */ class ResponseDeclaration extends VariableDeclaration implements ContentVariable { /** * the QTI tag name as defined in QTI standard * * @access protected * @var string */ protected static $qtiTagName = 'responseDeclaration'; /** * Short description of attribute correctResponses * * @access protected * @var array */ protected $correctResponses = []; /** * Short description of attribute mapping * * @access protected * @var array */ protected $mapping = []; /** * Short description of attribute areaMapping * * @access protected * @var array */ protected $areaMapping = []; /** * Short description of attribute mappingDefaultValue * * @access protected * @var double */ protected $mappingDefaultValue = 0.0; /** * Short description of attribute howMatch * * @access protected * @var String */ protected $howMatch = null; protected $simpleFeedbackRules = []; protected function generateIdentifier($prefix = '') { if (empty($prefix)) { $prefix = 'RESPONSE'; //QTI standard default value } return parent::generateIdentifier($prefix); } public function toArray($filterVariableContent = false, &$filtered = []) { $data = parent::toArray($filterVariableContent, $filtered); //@todo : clean this please: do not use a class attributes to store childdren's ones. unset($data['attributes']['mapping']); unset($data['attributes']['areaMapping']); //prepare the protected data: $protectedData = [ 'mapping' => $this->mapping, 'areaMapping' => $this->areaMapping, 'howMatch' => $this->howMatch ]; $correct = []; $correctResponses = $this->getCorrectResponses(); if (is_array($correctResponses)) { foreach ($correctResponses as $correctResponseKey => $value) { //if correct response has cardinality record: if ($this->getAttribute('cardinality') == 'record') { $valueData = $value->toArray(); $correct[$valueData['fieldIdentifier']] = $valueData; } else { $correct[$correctResponseKey] = (string) $value; } } } $protectedData['correctResponses'] = $correct; $defaultValues = $this->getDefaultValue(); if (is_array($defaultValues)) { foreach ($defaultValues as $defaultValuesKey => $defaultValue) { $defaultValues[$defaultValuesKey] = (string) $defaultValue; } } $protectedData['defaultValue'] = $defaultValues; $data['defaultValue'] = $defaultValues; //add mapping attributes $mappingAttributes = ['defaultValue' => $this->mappingDefaultValue]; if (is_array($this->getAttributeValue('mapping'))) { $mappingAttributes = array_merge($mappingAttributes, $this->getAttributeValue('mapping')); } elseif (is_array($this->getAttributeValue('areaMapping'))) { $mappingAttributes = array_merge($mappingAttributes, $this->getAttributeValue('areaMapping')); } $protectedData['mappingAttributes'] = $mappingAttributes; //add simple feedbacks $protectedData['feedbackRules'] = $this->getArraySerializedElementCollection($this->getFeedbackRules(), $filterVariableContent, $filtered); if ($filterVariableContent) { $filtered[$this->getSerial()] = $protectedData; } else { $data = array_merge($data, $protectedData); } return $data; } protected function getTemplateQtiVariables() { $variables = parent::getTemplateQtiVariables(); $variables['correctResponses'] = $this->getCorrectResponses(); $variables['defaultValue'] = $this->getDefaultValue(); $variables['mapping'] = $this->mapping; $variables['areaMapping'] = $this->areaMapping; //@todo : clean this please: do not use a class attributes to store childdren's ones! unset($variables['attributes']['mapping']); unset($variables['attributes']['areaMapping']); $mappingAttributes = ['defaultValue' => $this->mappingDefaultValue]; if (is_array($this->getAttributeValue('mapping'))) { $mappingAttributes = array_merge($mappingAttributes, $this->getAttributeValue('mapping')); } elseif (is_array($this->getAttributeValue('areaMapping'))) { $mappingAttributes = array_merge($mappingAttributes, $this->getAttributeValue('areaMapping')); } $variables['mappingAttributes'] = $this->xmlizeOptions($mappingAttributes, true); $rpTemplate = ''; switch ($this->howMatch) { case Template::MATCH_CORRECT:{ $rpTemplate = 'match_correct'; break; } case Template::MAP_RESPONSE:{ $rpTemplate = 'map_response'; break; } case Template::MAP_RESPONSE_POINT:{ $rpTemplate = 'map_response_point'; break; } } $variables['howMatch'] = $this->howMatch; //the template $variables['rpTemplate'] = $rpTemplate; //the template return $variables; } /** * Short description of method getCorrectResponses * * @access public * @author Joel Bout, * @return array */ public function getCorrectResponses() { return (array) $this->correctResponses; } /** * Short description of method setCorrectResponses * * @access public * @author Joel Bout, * @param array responses * @return mixed */ public function setCorrectResponses($responses) { if (!is_array($responses)) { $responses = [$responses]; } $this->correctResponses = $responses; } /** * Short description of method getMapping * * @access public * @author Joel Bout, * @param string type * @return array */ public function getMapping($type = '') { $returnValue = []; if ($type == 'area') { $returnValue = $this->areaMapping; } else { $returnValue = $this->mapping; } return (array) $returnValue; } /** * Short description of method setMapping * * @access public * @author Joel Bout, * @param array map * @param type * @return mixed */ public function setMapping($map, $type = '') { if ($type == 'area') { $this->areaMapping = $map; } else { $this->mapping = $map; } } public function setMappingAttributes($attributes) { $this->setAttribute('mapping', $attributes); } /** * Short description of method getMappingDefaultValue * * @access public * @author Joel Bout, * @return double */ public function getMappingDefaultValue() { return $this->mappingDefaultValue; } /** * Short description of method setMappingDefaultValue * * @access public * @author Joel Bout, * @param double value * @return mixed */ public function setMappingDefaultValue($value) { $this->mappingDefaultValue = floatval($value); } /** * get the correct response in JSON format. If no correct response defined * null. * * @deprecated now use the new qtism lib for response evaluation * @access public * @author Joel Bout, */ public function correctToJSON() { $returnValue = null; try { $correctResponses = $this->getCorrectResponses(); if (count($correctResponses)) { $returnValue = taoQTI_models_classes_Matching_VariableFactory::createJSONVariableFromQTIData( $this->getIdentifier(), $this->getAttributeValue('cardinality'), $this->getAttributeValue('baseType'), $this->correctResponses ); } } catch (Exception $e) { } return $returnValue; } /** * Short description of method areaMapToJson * * @deprecated now use the new qtism lib for response evaluation * @access public * @author Joel Bout, */ public function areaMapToJson() { $returnValue = null; // Get the stored area mapping $mapping = $this->getMapping('area'); if (count($mapping)) { $returnValue = []; $returnValue['identifier'] = $this->getIdentifier(); $returnValue['defaultValue'] = $this->mappingDefaultValue; if ($this->hasAttribute('areaMapping')) { $returnValue = array_merge($returnValue, $this->getAttributeValue('areaMapping')); } $mappingValue = []; // If a mapping has been defined if (!empty($mapping)) { foreach ($mapping as $mapKey => $mappedValue) { $areaMapEntryJSON = []; $areaMapEntryJSON['value'] = (float) $mappedValue["mappedValue"]; $areaMapEntryJSON['key'] = taoQTI_models_classes_Matching_VariableFactory::createJSONShapeFromQTIData($mappedValue); array_push($mappingValue, (object) $areaMapEntryJSON); } $returnValue['value'] = $mappingValue; } $returnValue = (object) $returnValue; } return $returnValue; } /** * get the mapping in JSON format. If no mapping defined return null. * * @deprecated now use the new qtism lib for response evaluation * @access public * @author Joel Bout, */ public function mapToJSON() { $returnValue = null; $mapping = $this->getMapping(); if (count($mapping)) { $returnValue = []; $returnValue['identifier'] = $this->getIdentifier(); $returnValue['defaultValue'] = $this->mappingDefaultValue; if ($this->hasAttribute('areaMapping')) { $returnValue = array_merge($returnValue, $this->getAttributeValue('areaMapping')); } $mappingValue = []; // If a mapping has been defined if (!empty($mapping)) { foreach ($mapping as $mapKey => $mappedValue) { $mapEntryJSON = []; $mapEntryJSON['value'] = (float) $mappedValue; $mapEntryJSON['key'] = taoQTI_models_classes_Matching_VariableFactory::createJSONValueFromQTIData($mapKey, $this->getAttributeValue('baseType')); array_push($mappingValue, (object) $mapEntryJSON); } $returnValue['value'] = $mappingValue; } $returnValue = (object) $returnValue; } return $returnValue; } /** * get the base type of the response declaration * * @access public * @author Joel Bout, * @return string */ public function getBaseType() { return (string) $this->getAttributeValue('baseType'); } /** * Short description of method getHowMatch * * @access public * @author Joel Bout, * @return string */ public function getHowMatch() { return (string) $this->howMatch; } /** * Short description of method setHowMatch * * @access public * @author Joel Bout, * @param string howMatch * @return mixed */ public function setHowMatch($howMatch) { $this->howMatch = $howMatch; } public function getAssociatedInteraction() { $returnValue = null; $item = $this->getRelatedItem(); if (!is_null($item)) { $interactions = $item->getInteractions(); foreach ($interactions as $interaction) { if ($interaction->getAttributeValue('responseIdentifier') == $this->getIdentifier()) { $returnValue = $interaction; break; } } } return $returnValue; } /** * Short description of method toForm * * @access public * @author Joel Bout, * @return tao_helpers_form_xhtml_Form */ public function toForm() { $returnValue = null; $interaction = $this->getAssociatedInteraction(); if ($interaction instanceof Interaction) { $responseFormClass = '\\oat\\taoQtiItem\\controller\\QTIform\\response\\' . ucfirst(strtolower($interaction->getType())) . 'Interaction'; if (class_exists($responseFormClass)) { $formContainer = new $responseFormClass($this); $myForm = $formContainer->getForm(); $returnValue = $myForm; } } else { throw new Exception('cannot find the parent interaction of the current response'); } return $returnValue; } public function addFeedbackRule(SimpleFeedbackRule $simpleFeedbackRule) { $this->simpleFeedbackRules[$simpleFeedbackRule->getSerial()] = $simpleFeedbackRule; $simpleFeedbackRule->setRelatedItem($this->getRelatedItem()); } public function getFeedbackRules() { return $this->simpleFeedbackRules; } public function getFeedbackRule($serial) { return isset($this->simpleFeedbackRules[$serial]) ? $this->simpleFeedbackRules[$serial] : null; } public function removeFeedbackRule($serial) { unset($this->simpleFeedbackRules[$serial]); return true; } public function toFilteredArray() { return $this->toArray(true); } }