private function generateLearnosityToQtiDocumentation() { $questionTypeDocumentation = []; $responsesSchemas = $this->schemasService->getResponsesSchemas(); foreach ($responsesSchemas as $questionType => $data) { if (in_array($questionType, QtiExportConstant::$supportedQuestionTypes)) { /** @var QuestionTypeDocumentationInterface $mapperClass */ $mapperClass = 'LearnosityQti\\Processors\\QtiV2\\Out\\Documentation\\QuestionTypes\\' . ucfirst($questionType) . 'Documentation'; $documentation = $mapperClass::getDocumentation(); foreach (array_keys($this->generateAtributeTable($data['attributes'])) as $flattenedAttributeName) { // TODO: Need to check new or non-existing attribute name in case our schemas change if (!in_array($flattenedAttributeName, array_keys($documentation))) { $documentation[$flattenedAttributeName] = LearnosityDoc::none(); } } // TODO: Hack here, hide all the `validation` attributes $documentationToDisplay = []; foreach ($documentation as $attributeName => $doc) { if (!StringUtil::startsWith($attributeName, 'validation')) { $documentationToDisplay[$attributeName] = $doc; } } $questionTypeDocumentation[$questionType] = ['mapping' => $documentationToDisplay, 'introduction' => $mapperClass::getIntroductionNotes()]; } } return ['questionTypes' => $questionTypeDocumentation, 'unsupportedQuestionTypes' => array_keys(array_diff_key($responsesSchemas, $questionTypeDocumentation))]; }
public function convert(Manifest $manifest, array $rules = []) { $activityReference = $manifest->getIdentifier(); $tagsWriter = new TagsWriter(); // Does not handle submanifest tyvm! if (!empty($manifest->getManifest())) { LogService::log('Does not handle sub-manifest element thus it is ignored'); } // Atm, we only have tags rules and this need to be validated and user shall be provided with a nice error message // TODO: Validation need to be done in future $tagRules = isset($rules['tags']) ? $rules['tags'] : []; // Let's map package metadatas as activity tags // We can write custom replacer or remover to fix the messy `identifier:catalog:` afterwards $activityTags = []; $metadatas = $manifest->getMetadata(); if (!empty($metadatas)) { $tags = $tagsWriter->convert($metadatas, $tagRules); if (!empty($tags)) { $activityTags = ['reference' => $activityReference, 'tags' => $tags]; } } $itemReferences = []; $itemsTags = []; // Build item reference and item tags JSON $organisations = $manifest->getOrganizations(); if (!empty($organisations)) { foreach ($organisations as $organisation) { foreach ($organisation->getItems() as $item) { $itemReferences[] = $item->getIdentifier(); } } } // Build item reference and item tags JSON $resources = $manifest->getResources(); if (!empty($resources)) { foreach ($resources as $resource) { // Just add `item` resource as items, and leave css and any other resources alone if (StringUtil::startsWith($resource->getType(), 'imsqti_item')) { /** @var Resource $resource */ $itemReference = $resource->getIdentifier(); $itemReferences[] = $itemReference; $tags = $tagsWriter->convert($resource->getMetadata(), $tagRules); if (!empty($tags)) { $itemsTags[] = ['reference' => $itemReference, 'tags' => $tags]; } } } } // Build activity JSON $activity = ['reference' => $activityReference, 'data' => ['items' => array_values(array_unique($itemReferences))], 'status' => 'published']; // Obvious here that these `items` hasn't and wouldn't be validated against // Should do it later by the function that calls this return [$activity, $activityTags, $itemsTags]; }
public function testMappingMcqQuestion() { $questionJson = $this->getFixtureFileContents('learnosityjsons/item_mcq.json'); $question = json_decode($questionJson, true); list($xmlString, $messages) = Converter::convertLearnosityToQtiItem($question); $this->assertNotNull($xmlString); $this->assertTrue(StringUtil::startsWith($xmlString, '<?xml version="1.0" encoding="UTF-8"?> <assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1"')); $document = new XmlDocument(); $document->loadFromString($xmlString); $this->assertNotNull($document); }
public static function convertQtiItemToLearnosity($xmlString, $baseAssetsUrl = '', $validate = true) { $itemMapper = AppContainer::getApplicationContainer()->get('qtiv2_item_mapper'); $itemWriter = AppContainer::getApplicationContainer()->get('learnosity_item_writer'); $questionWriter = AppContainer::getApplicationContainer()->get('learnosity_question_writer'); // Parse `em try { list($item, $questions, $exceptions) = $itemMapper->parse($xmlString, $validate); } catch (XmlStorageException $e) { // Check invalid schema error message and intercept to rethrow as known `InvalidQtiException` exception $exceptionMessage = $e->getMessage(); if (StringUtil::startsWith($exceptionMessage, 'The document could not be validated with XML Schema')) { $exceptionMessage = preg_replace('/The document could not be validated with schema(.*)/', 'The document could not be validated with standard QTI schema: ', $exceptionMessage); throw new InvalidQtiException($exceptionMessage); } else { throw $e; } } // Conversion to JSON $itemData = []; if ($item instanceof item) { $itemData = $itemWriter->convert($item); } $questionsData = []; if (is_array($questions)) { foreach ($questions as $question) { $questionsData[] = $questionWriter->convert($question); } } return [$itemData, $questionsData, $exceptions]; }
private function getFeatureReferenceFromClassName($classname) { // Parse classname, ie `learnosity-feature feature-DEMOFEATURE123` // Then, return `DEMOFEATURE123` $parts = preg_split('/\\s+/', $classname); foreach ($parts as $part) { if (StringUtil::startsWith(strtolower($part), 'feature-')) { return explode('-', $part)[1]; } } // TODO: throw exception return null; }