public function convert(item $item, array $questions) { // Make sure we clean up the log LogService::flush(); // Try to build the identifier using item `reference` // Otherwise, generate an alternative identifier and store the original reference as `label` $itemReference = $item->get_reference(); $itemIdentifier = Format::isIdentifier($itemReference, false) ? $itemReference : 'ITEM_' . StringUtil::generateRandomString(12); if ($itemReference !== $itemIdentifier) { LogService::log("The item `reference` ({$itemReference}) is not a valid identifier, thus can not be used for `assessmentItem` identifier. " . "Replaced it with randomly generated `{$itemIdentifier}` and stored the original `reference` as `label` attribute"); } $builder = new AssessmentItemBuilder(); $assessmentItem = $builder->build($itemIdentifier, $itemReference, $questions, $item->get_content()); $xml = new XmlDocument(); $xml->setDocumentComponent($assessmentItem); // Flush out all the error messages stored in this static class, also ensure they are unique $messages = array_values(array_unique(LogService::flush())); return [$xml->saveToString(true), $messages]; }
/** * Converts an assoc array to a QtiComponent using reflection * * @param array $testArray the assoc array * @param \qtism\data\QtiComponent|null $parent for recursive usage only * @param boolean $attach if we want to attach the component to it's parent or return it * @return QtiComponent|void */ private function arrayToComponent(array $testArray, QtiComponent $parent = null, $attach = true) { if (isset($testArray['qti-type']) && !empty($testArray['qti-type'])) { $compName = $this->lookupClass($testArray['qti-type']); if (!empty($compName)) { $reflector = new ReflectionClass($compName); $component = $this->createInstance($reflector, $testArray); $properties = array(); foreach ($this->getProperties($reflector) as $property) { $properties[$property->getName()] = $property; } foreach ($testArray as $key => $value) { if (array_key_exists($key, $properties)) { $class = $this->getPropertyClass($component, $properties[$key]); if (is_array($value) && array_key_exists('qti-type', $value)) { $this->arrayToComponent($value, $component, true); } else { $assignableValue = $this->componentValue($value, $class); if (!is_null($assignableValue)) { $this->setValue($component, $properties[$key], $assignableValue); } } } } if ($attach) { if (is_null($parent)) { $this->doc->setDocumentComponent($component); } else { $parentReflector = new ReflectionClass($parent); foreach ($this->getProperties($parentReflector) as $property) { if ($property->getName() === $testArray['qti-type']) { $this->setValue($parent, $property, $component); break; } } } } return $component; } } }
public function beforeSave(QtiComponent $documentComponent, $uri) { // Take care of rubricBlock explosion. Transform // actual rubricBlocks in rubricBlockRefs. if ($this->mustExplodeRubricBlocks() === true) { // Get all rubricBlock elements... $iterator = new QtiComponentIterator($documentComponent, array('rubricBlock')); $sectionCount = new SplObjectStorage(); foreach ($iterator as $rubricBlock) { // $section contains the assessmentSection the rubricBlock is related to. $section = $iterator->parent(); // determine the occurence number of the rubricBlock relative to its section. if (isset($sectionCount[$section]) === false) { $sectionCount[$section] = 0; } $sectionCount[$section] = $sectionCount[$section] + 1; $occurence = $sectionCount[$section]; // determine a suitable file name for the external rubricBlock definition. $rubricBlockRefId = 'RB_' . $section->getIdentifier() . '_' . $occurence; $href = './rubricBlock_' . $rubricBlockRefId . '.xml'; $doc = new XmlDocument(); $doc->setDocumentComponent($rubricBlock); try { $pathinfo = pathinfo($uri); $doc->save($pathinfo['dirname'] . DIRECTORY_SEPARATOR . $href); // replace the rubric block with a reference. $sectionRubricBlocks = $section->getRubricBlocks(); $sectionRubricBlocks->remove($rubricBlock); $sectionRubricBlockRefs = $section->getRubricBlockRefs(); $sectionRubricBlockRefs[] = new RubricBlockRef($rubricBlockRefId, $href); } catch (XmlStorageException $e) { $msg = "An error occured while creating external rubrickBlock definition(s)."; throw new XmlStorageException($msg, $e); } } } }
/** * Explode the rubric blocks of the test definition into separate QTI-XML files and * remove the compact XML document from the file system (useless for * the rest of the compilation process). * * @param XmlCompactDocument $compiledDoc */ protected function explodeRubricBlocks(XmlCompactDocument $compiledDoc) { $privateDir = $this->getPrivateDirectory(); $explodedRubricBlocks = $compiledDoc->explodeRubricBlocks(); foreach ($explodedRubricBlocks as $href => $rubricBlock) { $doc = new XmlDocument(); $doc->setDocumentComponent($rubricBlock); $data = $doc->saveToString(); $privateDir->write($href, $data); } }
/** * @see \qtism\data\storage\xml\XmlDocument::beforeSave() */ public function beforeSave(QtiComponent $documentComponent, $uri) { // Take care of rubricBlock explosion. Transform actual rubricBlocks in rubricBlockRefs. if ($this->mustExplodeRubricBlocks() === true) { // Get all rubricBlock elements... $iterator = new QtiComponentIterator($documentComponent, array('rubricBlock')); $sectionCount = new SplObjectStorage(); foreach ($iterator as $rubricBlock) { // $section contains the assessmentSection the rubricBlock is related to. $section = $iterator->parent(); // determine the occurence number of the rubricBlock relative to its section. if (isset($sectionCount[$section]) === false) { $sectionCount[$section] = 0; } $sectionCount[$section] = $sectionCount[$section] + 1; $occurence = $sectionCount[$section]; // determine a suitable file name for the external rubricBlock definition. $rubricBlockRefId = 'RB_' . $section->getIdentifier() . '_' . $occurence; $href = './rubricBlock_' . $rubricBlockRefId . '.xml'; $doc = new XmlDocument(); $doc->setDocumentComponent($rubricBlock); try { $pathinfo = pathinfo($uri); $doc->save($pathinfo['dirname'] . DIRECTORY_SEPARATOR . $href); // replace the rubric block with a reference. $sectionRubricBlocks = $section->getRubricBlocks(); $sectionRubricBlocks->remove($rubricBlock); $sectionRubricBlockRefs = $section->getRubricBlockRefs(); $sectionRubricBlockRefs[] = new RubricBlockRef($rubricBlockRefId, $href); } catch (XmlStorageException $e) { $msg = "An error occured while creating external rubrickBlock definition(s)."; throw new XmlStorageException($msg, XmlStorageException::UNKNOWN, $e); } } } // Take care of testFeedback explosion. Transform actual testFeedbacks in testFeedbackRefs. if ($this->mustExplodeTestFeedbacks() === true) { $iterator = new QtiComponentIterator($documentComponent, array('testFeedback')); $testPartCount = new SplObjectStorage(); $testCount = 0; foreach ($iterator as $testFeedback) { $parent = $iterator->parent(); if ($parent instanceof TestPart) { if (isset($testPartCount[$parent]) === false) { $testPartCount[$parent] = 0; } $testPartCount[$parent] = $testPartCount[$parent] + 1; $occurence = $testPartCount[$parent]; } else { // It's a testFeedback related to an assessmentTest. $testCount += 1; $occurence = $testCount; } $parentId = $parent->getIdentifier(); $href = "./testFeedback_TF_{$parentId}_{$occurence}.xml"; // Generate the document. $doc = new XmlDocument(); $doc->setDocumentComponent($testFeedback); try { $pathinfo = pathinfo($uri); $doc->save($pathinfo['dirname'] . DIRECTORY_SEPARATOR . $href); $parent->getTestFeedbacks()->remove($testFeedback); $testFeedbackRefs = $parent->getTestFeedbackRefs(); $testFeedbackRefs[] = new TestFeedbackRef($testFeedback->getIdentifier(), $testFeedback->getOutcomeIdentifier(), $testFeedback->getAccess(), $testFeedback->getShowHide(), $href); } catch (XmlStorageException $e) { $msg = "An error occured while creating external testFeedback definition(s)."; throw new XmlStorageException($msg, XmlStorageException::UNKNOWN, $e); } } } }