/**
  * Update the item content by wrapping the modalfeedback body into a new wrapper
  *
  * @param oat\taoQtiItem\modal\Item $item
  * @param string $itemFile
  * @return boolean
  */
 protected function updateItem(\oat\taoQtiItem\model\qti\Item $item, $itemFile)
 {
     $changed = false;
     $responses = $item->getResponses();
     foreach ($responses as $response) {
         $responseIdentifier = $response->attr('identifier');
         $rules = $response->getFeedbackRules();
         foreach ($rules as $rule) {
             $modalFeedbacks = array();
             if ($rule->getFeedbackThen()) {
                 $modalFeedbacks[] = $rule->getFeedbackThen();
             }
             if ($rule->getFeedbackElse()) {
                 $modalFeedbacks[] = $rule->getFeedbackElse();
             }
             foreach ($modalFeedbacks as $modalFeedback) {
                 $feedbackXml = simplexml_load_string($modalFeedback->toQti());
                 if ($feedbackXml->div[0] && $feedbackXml->div[0]['class'] && preg_match('/^x-tao-wrapper/', $feedbackXml->div[0]['class'])) {
                     //the item body has not already been wrapped by the new wrapper <div class="x-tao-wrapper w-tao-relatedOutcome-{{response.identifier}}">
                     continue;
                 }
                 $message = $modalFeedback->getBody()->getBody();
                 $modalFeedback->getBody()->edit('<div class="x-tao-wrapper x-tao-relatedOutcome-' . $responseIdentifier . '">' . $message . '</div>', true);
                 $changed = true;
             }
         }
     }
     return $changed;
 }
 /**
  * Remove unused response declaration from the items and rp template misuse
  *
  * @param oat\taoQtiItem\modal\Item $item
  * @param string $itemFile
  * @return boolean
  */
 protected function updateItem(\oat\taoQtiItem\model\qti\Item $item, $itemFile)
 {
     $changed = false;
     $responses = $item->getResponses();
     $interactions = $item->getInteractions();
     $usedResponses = [];
     foreach ($interactions as $interaction) {
         $usedResponses[] = $interaction->attr('responseIdentifier');
     }
     foreach ($responses as $response) {
         $responseIdentifier = $response->attr('identifier');
         if (!in_array($responseIdentifier, $usedResponses)) {
             $changed = true;
             $item->removeResponse($response);
         }
     }
     $xml = simplexml_load_file($itemFile);
     $rpTemplate = (string) $xml->responseProcessing['template'];
     //detect wrong usage for standard standard response declaration
     $rp = $item->getResponseProcessing();
     if ($rp instanceof \oat\taoQtiItem\model\qti\response\TemplatesDriven && $rpTemplate) {
         if (count($interactions) > 1) {
             $changed = true;
         } else {
             $interaction = reset($interactions);
             if ($interaction && $interaction->attr('responseIdentifier') != 'RESPONSE') {
                 $changed = true;
             }
         }
     }
     return $changed;
 }
 /**
  * Remove unused response declaration from the items and rp template misuse
  *
  * @param oat\taoQtiItem\modal\Item $item
  * @param string $itemFile
  * @return boolean
  */
 protected function updateItem(Item $item, $itemFile)
 {
     $changed = false;
     $requireFix = false;
     $interactions = $item->getInteractions();
     foreach ($interactions as $interaction) {
         if ($interaction instanceof PortableCustomInteraction && $interaction->getTypeIdentifier() === 'textReaderInteraction') {
             $response = $interaction->getResponse();
             $currentDefaultVal = $response->getDefaultValue();
             if (!is_array($currentDefaultVal) || empty($currentDefaultVal) || count($currentDefaultVal) !== 1) {
                 $requireFix = true;
             } else {
                 $val = $currentDefaultVal[0];
                 $requireFix = !($val instanceof Value && $val->getValue() === 'true');
             }
             if ($requireFix) {
                 $defaultValue = new Value();
                 $defaultValue->setValue('true');
                 $response->setDefaultValue([$defaultValue]);
                 $changed = true;
             }
         }
     }
     return $changed;
 }
 /**
  * Extract all assets from the current item
  * @return array the assets by type
  */
 public function extract()
 {
     foreach ($this->item->getComposingElements() as $element) {
         $this->extractImg($element);
         $this->extractObject($element);
         $this->extractStyleSheet($element);
         $this->extractCustomElement($element);
     }
     return $this->assets;
 }
 public function testModel()
 {
     $myItem = new Item();
     $myItem->setAttribute('title', 'My Coolest Item');
     $myItem->getBody()->edit('sth');
     $myInteraction = new ChoiceInteraction();
     $myInteraction->getPrompt()->edit('Prompt you');
     $myChoice1 = $myInteraction->createChoice(array('fixed' => true), 'This is correct');
     $myChoice2 = $myInteraction->createChoice(array('fixed' => true), 'This is not correct');
     $this->assertInstanceOf('\\oat\\taoQtiItem\\model\\qti\\choice\\SimpleChoice', $myChoice2);
     $this->assertEquals(count($myInteraction->getChoices()), 2);
     $myChoice1->setContent('answer #1');
     $myChoice2->setContent('answer #2');
     $myInteraction->removeChoice($myChoice1);
     $this->assertEquals(count($myInteraction->getChoices()), 1);
     $myItem->addInteraction($myInteraction, "Adding my interaction here {$myInteraction->getPlaceholder()}. And not there.");
     $this->assertNotNull($myInteraction->getRelatedItem());
     $this->assertEquals($myInteraction->getRelatedItem()->getSerial(), $myItem->getSerial());
     $myResponse = new ResponseDeclaration();
     $myItem->addResponse($myResponse);
     $this->assertNotNull($myResponse->getRelatedItem());
     $this->assertEquals($myResponse->getRelatedItem()->getSerial(), $myItem->getSerial());
     $myItem->removeResponse($myResponse);
     $responses = $myItem->getResponses();
     $this->assertTrue(empty($responses));
 }
 public function extractPortableAssetElements()
 {
     foreach ($this->item->getComposingElements() as $element) {
         $this->extractCustomElement($element);
     }
     return $this->assets;
 }
 /**
  * @param core_kernel_classes_Resource $item the item to pack
  * @param string $lang
  * @param Item $qtiItem
  * @param \oat\oatbox\filesystem\Directory $directory
  * @return ItemPack $itemPack
  * @throws common_Exception
  */
 public function packQtiItem($item, $lang, $qtiItem, Directory $directory)
 {
     //use the QtiParser to transform the QTI XML into an assoc array representation
     try {
         //build the ItemPack from the parsed data
         if ($this->replaceXinclude) {
             $resolver = new ItemMediaResolver($item, $lang);
             $xincludeLoader = new XIncludeLoader($qtiItem, $resolver);
             $xincludeLoader->load(true);
         }
         $itemPack = new ItemPack(self::$itemType, $qtiItem->toArray());
         $itemPack->setAssetEncoders($this->getAssetEncoders());
         $assetParser = new AssetParser($qtiItem, $directory);
         $assetParser->setDeepParsing($this->isNestedResourcesInclusion());
         $assetParser->setGetXinclude(!$this->replaceXinclude);
         $storageDirectory = new \tao_models_classes_service_StorageDirectory($item->getUri(), $directory->getFileSystemId(), $directory->getPrefix() . '/' . $lang);
         $storageDirectory->setServiceLocator($directory->getServiceLocator());
         foreach ($assetParser->extract($itemPack) as $type => $assets) {
             $resolver = new ItemMediaResolver($item, $lang);
             foreach ($assets as &$asset) {
                 $mediaAsset = $resolver->resolve($asset);
                 $mediaSource = $mediaAsset->getMediaSource();
                 $asset = $mediaSource->getBaseName($mediaAsset->getMediaIdentifier());
             }
             $itemPack->setAssets($type, $assets, $storageDirectory);
         }
     } catch (common_Exception $e) {
         throw new common_Exception('Unable to pack item ' . $item->getUri() . ' : ' . $e->getMessage());
     }
     return $itemPack;
 }
 protected function getResponse($identifier)
 {
     foreach ($this->item->getResponses() as $response) {
         if ($response->getIdentifier() == $identifier) {
             return $response;
         }
     }
     throw new ParsingException('cannot found the response with identifier ' . $identifier);
 }
 /**
  * Short description of method takeOverFrom
  *
  * @access public
  * @author Joel Bout, <*****@*****.**>
  * @param  ResponseProcessing responseProcessing
  * @param  Item item
  * @return oat\taoQtiItem\model\qti\response\Composite
  */
 public static function takeOverFrom(ResponseProcessing $responseProcessing, Item $item)
 {
     $returnValue = null;
     if ($responseProcessing instanceof static) {
         // already good
         $returnValue = $responseProcessing;
     } elseif ($responseProcessing instanceof Template) {
         // IMS Template
         $rp = new Summation($item, 'SCORE');
         foreach ($item->getInteractions() as $interaction) {
             $response = $interaction->getResponse();
             try {
                 $irp = IrpTemplate::createByTemplate($responseProcessing->getUri(), $response, $item);
             } catch (Exception $e) {
                 throw new TakeoverFailedException();
             }
             $rp->add($irp, $item);
         }
         $returnValue = $rp;
     } elseif ($responseProcessing instanceof TemplatesDriven) {
         // TemplateDriven
         $rp = new Summation($item, 'SCORE');
         foreach ($item->getInteractions() as $interaction) {
             $response = $interaction->getResponse();
             try {
                 $irp = IrpTemplate::createByTemplate($responseProcessing->getTemplate($response), $response, $item);
             } catch (Exception $e) {
                 throw new TakeoverFailedException();
             }
             $rp->add($irp, $item);
         }
         $returnValue = $rp;
     } else {
         common_Logger::d('Composite ResponseProcessing can not takeover from ' . get_class($responseProcessing) . ' yet');
         throw new TakeoverFailedException();
     }
     common_Logger::i('Converted to Composite', array('TAOITEMS', 'QTI'));
     return $returnValue;
 }
 /**
  * Short description of method buildRule
  *
  * @deprecated
  * @access public
  * @author Joel Bout, <*****@*****.**>
  * @param  Item item
  * @return string
  */
 public function buildRule(Item $item)
 {
     $returnValue = (string) '';
     foreach ($item->getInteractions() as $interaction) {
         $response = $interaction->getResponse();
         $uri = $response->getHowMatch();
         $templateName = substr($uri, strrpos($uri, '/') + 1);
         $matchingTemplate = dirname(__FILE__) . '/rpTemplate/rule.' . $templateName . '.tpl.php';
         $tplRenderer = new taoItems_models_classes_TemplateRenderer($matchingTemplate, array('responseIdentifier' => $response->getIdentifier(), 'outcomeIdentifier' => 'SCORE'));
         $returnValue .= $tplRenderer->render();
     }
     return (string) $returnValue;
 }
Example #11
0
 public function getVariableElements(Item $item)
 {
     $allData = $item->getDataForDelivery();
     return $allData['variable'];
 }
 protected function getModalFeedbacks(Item $qtiItem)
 {
     $returnValue = array();
     $feedbacks = $qtiItem->getModalFeedbacks();
     foreach ($feedbacks as $feedback) {
         $returnValue[$feedback->getSerial()] = $feedback->toArray();
     }
     return $returnValue;
 }
 /**
  * Short description of method create
  *
  * @access public
  * @author Joel Bout, <*****@*****.**>
  * @param  int classID
  * @param  Response response
  * @param  Item item
  * @return oat\taoQtiItem\model\qti\response\interactionResponseProcessing\InteractionResponseProcessing
  */
 public static function create($classID, ResponseDeclaration $response, Item $item)
 {
     switch ($classID) {
         case None::CLASS_ID:
             $className = 'oat\\taoQtiItem\\model\\qti\\response\\interactionResponseProcessing\\None';
             break;
         case MatchCorrectTemplate::CLASS_ID:
             $className = 'oat\\taoQtiItem\\model\\qti\\response\\interactionResponseProcessing\\MatchCorrectTemplate';
             break;
         case MapResponseTemplate::CLASS_ID:
             $className = 'oat\\taoQtiItem\\model\\qti\\response\\interactionResponseProcessing\\MapResponseTemplate';
             break;
         case MapResponsePointTemplate::CLASS_ID:
             $className = 'oat\\taoQtiItem\\model\\qti\\response\\interactionResponseProcessing\\MapResponsePointTemplate';
             break;
         case Custom::CLASS_ID:
             $className = 'oat\\taoQtiItem\\model\\qti\\response\\interactionResponseProcessing\\Custom';
             break;
         default:
             throw new common_exception_Error('Unknown InteractionResponseProcessing Class ID "' . $classID . '"');
     }
     $outcome = self::generateOutcomeDefinition();
     $outcomes = $item->getOutcomes();
     $outcomes[] = $outcome;
     $item->setOutcomes($outcomes);
     $returnValue = new $className($response, $outcome);
     return $returnValue;
 }
 /**
  * Set the item the current Qti Element belongs to.
  * The related item assignment is propagated to all containing Qti Element of the current one.
  * The "force" option allows changing the associated item (even if it has already been defined)
  * 
  * @param oat\taoQtiItem\model\qti\Item $item
  * @param boolean $force
  * @return boolean
  * @throws oat\taoQtiItem\model\qti\exception\QtiModelException
  */
 public function setRelatedItem(Item $item, $force = false)
 {
     $returnValue = false;
     if (!is_null($this->relatedItem) && $this->relatedItem->getSerial() == $item->getSerial()) {
         $returnValue = true;
         // identical
     } elseif (!$force && !is_null($this->relatedItem)) {
         throw new QtiModelException('attempt to change item reference for a QTI element');
     } else {
         // propagate the assignation of item to all included objects
         $reflection = new ReflectionClass($this);
         foreach ($reflection->getProperties() as $property) {
             if (!$property->isStatic() && !$property->isPrivate()) {
                 $propertyName = $property->getName();
                 $value = $this->{$propertyName};
                 if (is_array($value)) {
                     foreach ($value as $subvalue) {
                         if (is_object($subvalue) && $subvalue instanceof Element) {
                             $subvalue->setRelatedItem($item);
                         } elseif (is_object($subvalue) && $subvalue instanceof ResponseIdentifier) {
                             // manage the reference of identifier
                             $idenfierBaseType = $subvalue->getValue(true);
                             if (!is_null($idenfierBaseType)) {
                                 $idenfierBaseType->getReferencedObject()->setRelatedItem($item);
                             }
                         }
                     }
                 } elseif (is_object($value) && $value instanceof Element) {
                     $value->setRelatedItem($item);
                 }
             }
         }
         // set item reference to current object
         $this->relatedItem = $item;
         $returnValue = true;
     }
     return $returnValue;
 }
 /**
  * Short description of method buildCompositeResponseProcessing
  *
  * @access public
  * @author Joel Bout, <*****@*****.**>
  * @param  DOMElement data
  * @param  Item item
  * @return oat\taoQtiItem\model\qti\response\ResponseProcessing
  */
 protected function buildCompositeResponseProcessing(DOMElement $data, Item $item)
 {
     $returnValue = null;
     // STRONGLY simplified summation detection
     $patternCorrectTAO = '/responseCondition [count(./*) = 1 ] [name(./*[1]) = "responseIf" ] [count(./responseIf/*) = 2 ] [name(./responseIf/*[1]) = "match" ] [name(./responseIf/match/*[1]) = "variable" ] [name(./responseIf/match/*[2]) = "correct" ] [name(./responseIf/*[2]) = "setOutcomeValue" ] [count(./responseIf/setOutcomeValue/*) = 1 ] [name(./responseIf/setOutcomeValue/*[1]) = "baseValue"]';
     $patternMapTAO = '/responseCondition [count(./*) = 1 ] [name(./*[1]) = "responseIf" ] [count(./responseIf/*) = 2 ] [name(./responseIf/*[1]) = "not" ] [count(./responseIf/not/*) = 1 ] [name(./responseIf/not/*[1]) = "isNull" ] [count(./responseIf/not/isNull/*) = 1 ] [name(./responseIf/not/isNull/*[1]) = "variable" ] [name(./responseIf/*[2]) = "setOutcomeValue" ] [count(./responseIf/setOutcomeValue/*) = 1 ] [name(./responseIf/setOutcomeValue/*[1]) = "mapResponse"]';
     $patternMapPointTAO = '/responseCondition [count(./*) = 1 ] [name(./*[1]) = "responseIf" ] [count(./responseIf/*) = 2 ] [name(./responseIf/*[1]) = "not" ] [count(./responseIf/not/*) = 1 ] [name(./responseIf/not/*[1]) = "isNull" ] [count(./responseIf/not/isNull/*) = 1 ] [name(./responseIf/not/isNull/*[1]) = "variable" ] [name(./responseIf/*[2]) = "setOutcomeValue" ] [count(./responseIf/setOutcomeValue/*) = 1 ] [name(./responseIf/setOutcomeValue/*[1]) = "mapResponsePoint"]';
     $patternNoneTAO = '/responseCondition [count(./*) = 1 ] [name(./*[1]) = "responseIf" ] [count(./responseIf/*) = 2 ] [name(./responseIf/*[1]) = "isNull" ] [count(./responseIf/isNull/*) = 1 ] [name(./responseIf/isNull/*[1]) = "variable" ] [name(./responseIf/*[2]) = "setOutcomeValue" ] [count(./responseIf/setOutcomeValue/*) = 1 ] [name(./responseIf/setOutcomeValue/*[1]) = "baseValue"]';
     $possibleSummation = '/setOutcomeValue [count(./*) = 1 ] [name(./*[1]) = "sum" ]';
     $irps = array();
     $composition = null;
     $data = simplexml_import_dom($data);
     foreach ($data as $responseRule) {
         if (!is_null($composition)) {
             throw new UnexpectedResponseProcessing('Not composite, rules after composition');
         }
         $subtree = new SimpleXMLElement($responseRule->asXML());
         if (count($subtree->xpath($patternCorrectTAO)) > 0) {
             $responseIdentifier = (string) $subtree->responseIf->match->variable[0]['identifier'];
             $irps[$responseIdentifier] = array('class' => 'MatchCorrectTemplate', 'outcome' => (string) $subtree->responseIf->setOutcomeValue[0]['identifier']);
         } elseif (count($subtree->xpath($patternMapTAO)) > 0) {
             $responseIdentifier = (string) $subtree->responseIf->not->isNull->variable[0]['identifier'];
             $irps[$responseIdentifier] = array('class' => 'MapResponseTemplate', 'outcome' => (string) $subtree->responseIf->setOutcomeValue[0]['identifier']);
         } elseif (count($subtree->xpath($patternMapPointTAO)) > 0) {
             $responseIdentifier = (string) $subtree->responseIf->not->isNull->variable[0]['identifier'];
             $irps[$responseIdentifier] = array('class' => 'MapResponsePointTemplate', 'outcome' => (string) $subtree->responseIf->setOutcomeValue[0]['identifier']);
         } elseif (count($subtree->xpath($patternNoneTAO)) > 0) {
             $responseIdentifier = (string) $subtree->responseIf->isNull->variable[0]['identifier'];
             $irps[$responseIdentifier] = array('class' => 'None', 'outcome' => (string) $subtree->responseIf->setOutcomeValue[0]['identifier'], 'default' => (string) $subtree->responseIf->setOutcomeValue[0]->baseValue[0]);
         } elseif (count($subtree->xpath($possibleSummation)) > 0) {
             $composition = 'Summation';
             $outcomesUsed = array();
             foreach ($subtree->xpath('/setOutcomeValue/sum/variable') as $var) {
                 $outcomesUsed[] = (string) $var[0]['identifier'];
             }
         } else {
             throw new UnexpectedResponseProcessing('Not composite, unknown rule');
         }
     }
     if (is_null($composition)) {
         throw new UnexpectedResponseProcessing('Not composit, Composition rule missing');
     }
     $responses = array();
     foreach ($item->getInteractions() as $interaction) {
         $responses[$interaction->getResponse()->getIdentifier()] = $interaction->getResponse();
     }
     if (count(array_diff(array_keys($irps), array_keys($responses))) > 0) {
         throw new UnexpectedResponseProcessing('Not composit, no responses for rules: ' . implode(',', array_diff(array_keys($irps), array_keys($responses))));
     }
     if (count(array_diff(array_keys($responses), array_keys($irps))) > 0) {
         common_Logger::w('Some responses have no processing');
         throw new UnexpectedResponseProcessing('Not composit, no support for unmatched variables yet');
     }
     //assuming sum is correct
     $compositonRP = new Summation($item);
     foreach ($responses as $id => $response) {
         $outcome = null;
         foreach ($item->getOutcomes() as $possibleOutcome) {
             if ($possibleOutcome->getIdentifier() == $irps[$id]['outcome']) {
                 $outcome = $possibleOutcome;
                 break;
             }
         }
         if (is_null($outcome)) {
             throw new ParsingException('Undeclared Outcome in ResponseProcessing');
         }
         $classname = '\\oat\\taoQtiItem\\model\\qti\\response\\interactionResponseProcessing\\' . $irps[$id]['class'];
         $irp = new $classname($response, $outcome);
         if ($irp instanceof \oat\taoQtiItem\model\qti\response\interactionResponseProcessing\None && isset($irps[$id]['default'])) {
             $irp->setDefaultValue($irps[$id]['default']);
         }
         $compositonRP->add($irp);
     }
     $returnValue = $compositonRP;
     return $returnValue;
 }
 /**
  *
  * @param core_kernel_classes_Class $itemClass
  * @param oat\taoQtiItem\model\qti\Item $qtiModel
  * @throws common_exception_Error
  * @throws \common_Exception
  * @return core_kernel_classes_Resource
  */
 protected function createRdfItem(core_kernel_classes_Class $itemClass, Item $qtiModel)
 {
     $itemService = taoItems_models_classes_ItemsService::singleton();
     $qtiService = Service::singleton();
     if (!$itemService->isItemClass($itemClass)) {
         throw new common_exception_Error('provided non Itemclass for ' . __FUNCTION__);
     }
     $rdfItem = $itemService->createInstance($itemClass);
     //set the QTI type
     $itemService->setItemModel($rdfItem, new core_kernel_classes_Resource(ItemModel::MODEL_URI));
     //set the label
     $label = '';
     if ($qtiModel->hasAttribute('label')) {
         $label = $qtiModel->getAttributeValue('label');
     }
     if (empty($label)) {
         $label = $qtiModel->getAttributeValue('title');
     }
     $rdfItem->setLabel($label);
     //save itemcontent
     if (!$qtiService->saveDataItemToRdfItem($qtiModel, $rdfItem)) {
         throw new \common_Exception('Unable to save item');
     }
     return $rdfItem;
 }
 /**
  * Feed the instance with portable related data extracted from the item
  *
  * @param Item $item
  * @throws \common_Exception
  */
 protected function feedRequiredFiles(Item $item)
 {
     $this->requiredFiles = [];
     $this->portableObjects = [];
     $this->picModels = [];
     $models = $this->getPortableFactory()->getModels();
     foreach ($models as $model) {
         $className = $model->getQtiElementClassName();
         $portableElementsXml = $item->getComposingElements($className);
         foreach ($portableElementsXml as $portableElementXml) {
             $this->parsePortableElement($model, $portableElementXml);
         }
     }
 }