From 2b295acf26101a62a8b8c95d077a56775622c700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Marsza=C5=82?= Date: Wed, 18 Dec 2024 10:24:50 +0100 Subject: [PATCH 1/6] feat: rename convert to more specyfic convertToQti2 --- models/classes/class.QtiTestService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/classes/class.QtiTestService.php b/models/classes/class.QtiTestService.php index d9ddd5545..89faea14d 100644 --- a/models/classes/class.QtiTestService.php +++ b/models/classes/class.QtiTestService.php @@ -399,7 +399,7 @@ public function importMultipleTests( $file = $folder . 'imsmanifest.xml'; $qtiManifestParser = new taoQtiTest_models_classes_ManifestParser($file); $this->propagate($qtiManifestParser); - $this->getManifestConverter()->convert($file, $qtiManifestParser); + $this->getManifestConverter()->convertToQti2($file, $qtiManifestParser); // We validate manifest file against QTI 3.0 $qtiManifestParser->validate(); if ($qtiManifestParser->isValid() === true) { @@ -623,7 +623,7 @@ protected function importTest( ); } else { //Convert to QTI 2.2 - $this->getTestConverter()->convert($expectedTestFile); + $this->getTestConverter()->convertToQti2($expectedTestFile); // -- Load the test in a QTISM flavour. $testDefinition = new XmlDocument(); From 6b8db8afef6ddf650278eb074d9211779ec54ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Marsza=C5=82?= Date: Wed, 18 Dec 2024 10:44:57 +0100 Subject: [PATCH 2/6] feat: update oat-sa/extension-tao-itemqti requirement --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d372dfb62..19644c40b 100644 --- a/composer.json +++ b/composer.json @@ -66,7 +66,7 @@ "oat-sa/generis": ">=16.0.0", "oat-sa/tao-core": ">=54.27.0", "oat-sa/extension-tao-item": ">=12.4.0", - "oat-sa/extension-tao-itemqti": ">=30.23.0", + "oat-sa/extension-tao-itemqti": ">=30.26.0", "oat-sa/extension-tao-test": ">=16.4.3", "oat-sa/extension-tao-delivery": ">=15.0.0", "oat-sa/extension-tao-outcome": ">=13.0.0", From 3cadb637d498d591474f82d5cbe681f2eda8d2e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Marsza=C5=82?= Date: Wed, 18 Dec 2024 10:46:42 +0100 Subject: [PATCH 3/6] feat: fix phpcs --- models/classes/class.QtiTestService.php | 1 + 1 file changed, 1 insertion(+) diff --git a/models/classes/class.QtiTestService.php b/models/classes/class.QtiTestService.php index 89faea14d..4fe493508 100644 --- a/models/classes/class.QtiTestService.php +++ b/models/classes/class.QtiTestService.php @@ -1,4 +1,5 @@ Date: Wed, 18 Dec 2024 17:15:29 +0100 Subject: [PATCH 4/6] feat: Validation Service will check converted Tag against xsd file --- models/classes/Qti/ServiceProvider/QtiServiceProvider.php | 2 ++ models/classes/class.QtiTestService.php | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/models/classes/Qti/ServiceProvider/QtiServiceProvider.php b/models/classes/Qti/ServiceProvider/QtiServiceProvider.php index 161152598..51be6d499 100644 --- a/models/classes/Qti/ServiceProvider/QtiServiceProvider.php +++ b/models/classes/Qti/ServiceProvider/QtiServiceProvider.php @@ -25,6 +25,7 @@ use oat\generis\model\DependencyInjection\ContainerServiceProviderInterface; use oat\oatbox\log\LoggerService; use oat\taoQtiItem\model\qti\converter\CaseConversionService; +use oat\taoQtiItem\model\ValidationService; use oat\taoQtiTest\models\Qti\Converter\TestConverter; use oat\taoQtiTest\models\Qti\Identifier\Service\QtiIdentifierSetter; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; @@ -48,6 +49,7 @@ public function __invoke(ContainerConfigurator $configurator): void ->set(TestConverter::class) ->args([ service(CaseConversionService::class), + service(ValidationService::SERVICE_ID) ]) ->public(); } diff --git a/models/classes/class.QtiTestService.php b/models/classes/class.QtiTestService.php index 4fe493508..2d7982e1c 100644 --- a/models/classes/class.QtiTestService.php +++ b/models/classes/class.QtiTestService.php @@ -451,7 +451,7 @@ public function importMultipleTests( } } else { $msg = __("The 'imsmanifest.xml' file found in the archive is not valid."); - $report->add(common_report_Report::createFailure($msg)); + $report->add(Report::createError($msg)); } // Cleanup the folder where the archive was extracted. @@ -618,7 +618,7 @@ protected function importTest( // -- Check if the file referenced by the test QTI resource exists. if (is_readable($expectedTestFile) === false) { $report->add( - common_report_Report::createFailure( + Report::createError( __('No file found at location "%s".', $qtiTestResource->getFile()) ) ); From 7513c197ec97aa3ce910a976e44b3203268b4adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Marsza=C5=82?= Date: Thu, 19 Dec 2024 16:25:07 +0100 Subject: [PATCH 5/6] feat: AssessmentSectionConverter included --- .../Converter/AssessmentSectionConverter.php | 35 ++++++ .../ServiceProvider/QtiServiceProvider.php | 9 ++ models/classes/class.QtiTestService.php | 111 +++++++++++------- 3 files changed, 113 insertions(+), 42 deletions(-) create mode 100644 models/classes/Qti/Converter/AssessmentSectionConverter.php diff --git a/models/classes/Qti/Converter/AssessmentSectionConverter.php b/models/classes/Qti/Converter/AssessmentSectionConverter.php new file mode 100644 index 000000000..aafecc3f3 --- /dev/null +++ b/models/classes/Qti/Converter/AssessmentSectionConverter.php @@ -0,0 +1,35 @@ +public(); + + $services + ->set(AssessmentSectionConverter::class) + ->args([ + service(CaseConversionService::class), + service(ValidationService::SERVICE_ID) + ]) + ->public(); } } diff --git a/models/classes/class.QtiTestService.php b/models/classes/class.QtiTestService.php index 2d7982e1c..452e0734c 100644 --- a/models/classes/class.QtiTestService.php +++ b/models/classes/class.QtiTestService.php @@ -46,6 +46,7 @@ use oat\taoQtiTest\models\cat\CatService; use oat\taoQtiTest\models\classes\event\TestImportedEvent; use oat\taoQtiTest\models\metadata\MetadataTestContextAware; +use oat\taoQtiTest\models\Qti\Converter\AssessmentSectionConverter; use oat\taoQtiTest\models\Qti\Converter\TestConverter; use oat\taoQtiTest\models\render\QtiPackageImportPreprocessing; use oat\taoQtiTest\models\test\AssessmentTestXmlFactory; @@ -53,6 +54,7 @@ use Psr\Container\ContainerInterface; use qtism\common\utils\Format; use qtism\data\AssessmentItemRef; +use qtism\data\AssessmentSectionRef; use qtism\data\QtiComponentCollection; use qtism\data\SectionPartCollection; use qtism\data\storage\StorageException; @@ -358,13 +360,14 @@ private function generateIdentifier(XmlDocument $doc, $qtiType, $offset = 1) */ public function importMultipleTests( core_kernel_classes_Class $targetClass, - $file, - bool $overwriteTest = false, - ?string $itemClassUri = null, - array $form = [], - ?string $overwriteTestUri = null, - ?string $packageLabel = null - ) { + $file, + bool $overwriteTest = false, + ?string $itemClassUri = null, + array $form = [], + ?string $overwriteTestUri = null, + ?string $packageLabel = null + ) + { $testClass = $targetClass; $report = new Report(Report::TYPE_INFO); $validPackage = false; @@ -549,17 +552,18 @@ public function clearRelatedResources(common_report_Report $report): void * @return common_report_Report A report about how the importation behaved. */ protected function importTest( - core_kernel_classes_Class $testClass, - Resource $qtiTestResource, + core_kernel_classes_Class $testClass, + Resource $qtiTestResource, taoQtiTest_models_classes_ManifestParser $manifestParser, - $folder, - array $ignoreQtiResources = [], - bool $overwriteTest = false, - ?string $itemClassUri = null, - bool $importMetadata = false, - ?string $overwriteTestUri = null, - ?string $packageLabel = null - ) { + $folder, + array $ignoreQtiResources = [], + bool $overwriteTest = false, + ?string $itemClassUri = null, + bool $importMetadata = false, + ?string $overwriteTestUri = null, + ?string $packageLabel = null + ) + { /** @var ImportService $itemImportService */ $itemImportService = $this->getServiceLocator()->get(ImportService::SERVICE_ID); $qtiTestResourceIdentifier = $qtiTestResource->getIdentifier(); @@ -630,7 +634,11 @@ protected function importTest( try { $testDefinition->load($expectedTestFile, true); - + $this->convertAssessmentSectionRefs( + $testDefinition->getDocumentComponent() + ->getComponentsByClassName('assessmentSectionRef'), + $folder + ); // If any, assessmentSectionRefs will be resolved and included as part of the main test definition. $testDefinition->includeAssessmentSectionRefs(true); $testLabel = $packageLabel ?? $this->getTestLabel($reportCtx->testMetadata, $testDefinition); @@ -752,9 +760,9 @@ protected function importTest( } else { if (!$itemReport->getMessage()) { $itemReport->setMessage( - // phpcs:disable Generic.Files.LineLength + // phpcs:disable Generic.Files.LineLength __('IMS QTI Item referenced as "%s" in the IMS Manifest file could not be imported.', $resourceIdentifier) - // phpcs:enable Generic.Files.LineLength + // phpcs:enable Generic.Files.LineLength ); } @@ -776,7 +784,7 @@ protected function importTest( common_report_Report::TYPE_SUCCESS, // phpcs:disable Generic.Files.LineLength __('IMS QTI Item referenced as "%s" in the IMS Manifest file successfully imported.', $resourceIdentifier) - // phpcs:enable Generic.Files.LineLength + // phpcs:enable Generic.Files.LineLength ) ); } @@ -897,7 +905,7 @@ protected function importTest( common_report_Report::TYPE_ERROR, // phpcs:disable Generic.Files.LineLength __("Items with assessmentItemRef identifiers \"%s\" are not registered in the related CAT endpoint.", implode(', ', $e->getInvalidItemIdentifiers())) - // phpcs:enable Generic.Files.LineLength + // phpcs:enable Generic.Files.LineLength ) ); } @@ -966,12 +974,13 @@ private function deleteTestsFromClassByLabel(string $testLabel, core_kernel_clas */ protected function importTestDefinition( core_kernel_classes_Resource $testResource, - XmlDocument $testDefinition, - Resource $qtiResource, - array $itemMapping, - $extractionFolder, - common_report_Report $report - ) { + XmlDocument $testDefinition, + Resource $qtiResource, + array $itemMapping, + $extractionFolder, + common_report_Report $report + ) + { foreach ($itemMapping as $itemRefId => $itemResource) { $itemRef = $testDefinition->getDocumentComponent()->getComponentByIdentifier($itemRefId); @@ -1029,11 +1038,12 @@ protected function getQtiDefinitionPath(Directory $dir) * @param common_report_Report A report about how the importation behaved. */ protected function importTestAuxiliaryFiles( - Directory $testContent, - Resource $qtiResource, - $extractionFolder, + Directory $testContent, + Resource $qtiResource, + $extractionFolder, common_report_Report $report - ) { + ) + { foreach ($qtiResource->getAuxiliaryFiles() as $aux) { try { @@ -1093,8 +1103,8 @@ public function getDoc(core_kernel_classes_Resource $test) * Get the path of the QTI XML test definition of a given $test resource. * * @param core_kernel_classes_Resource $test - * @throws Exception If no QTI-XML or multiple QTI-XML test definition were found. * @return string The absolute path to the QTI XML Test definition related to $test. + * @throws Exception If no QTI-XML or multiple QTI-XML test definition were found. */ public function getDocPath(core_kernel_classes_Resource $test) { @@ -1169,7 +1179,7 @@ private function setItemsToDoc(XmlDocument $doc, array $items, $sectionIndex = 0 * Get root qti test directory or crate if not exists * * @param core_kernel_classes_Resource $test - * @param boolean $createTestFile Whether or not create an empty QTI XML test file. Default is + * @param boolean $createTestFile Whether or not create an empty QTI XML test file. Default is * (boolean) true. * * @return Directory @@ -1230,8 +1240,8 @@ protected function searchInTestDirectory(Directory $dir) * If it doesn't exist, it will be created * * @param core_kernel_classes_Resource $test - * @throws \Exception If file is not found. * @return File + * @throws \Exception If file is not found. */ public function getQtiTestFile(core_kernel_classes_Resource $test) { @@ -1249,8 +1259,8 @@ public function getQtiTestFile(core_kernel_classes_Resource $test) /** * * @param core_kernel_classes_Resource $test - * @throws Exception * @return string + * @throws Exception */ public function getRelTestPath(core_kernel_classes_Resource $test) { @@ -1275,7 +1285,7 @@ private function saveDoc(core_kernel_classes_Resource $test, XmlDocument $doc) * Create the default content directory of a QTI test. * * @param core_kernel_classes_Resource $test - * @param boolean $createTestFile Whether or not create an empty QTI XML test file. Default is (boolean) true. + * @param boolean $createTestFile Whether or not create an empty QTI XML test file. Default is (boolean) true. * @param boolean $preventOverride Prevent data to be overriden Default is (boolean) true. * * @return Directory the content directory @@ -1413,11 +1423,11 @@ public function getQtiTestAcceptableLatency() /** * + * @return string|boolean The QTI Test template file content or false if it could not be read. * @deprecated * * Get the content of the QTI Test template file as an XML string. * - * @return string|boolean The QTI Test template file content or false if it could not be read. */ public function getQtiTestTemplateFileAsString() { @@ -1530,12 +1540,13 @@ private function getMetaMetadataImporter(): MetaMetadataImportMapper } private function getMappedProperties( - bool $importMetadata, - DOMDocument $domManifest, - stdClass $reportCtx, + bool $importMetadata, + DOMDocument $domManifest, + stdClass $reportCtx, core_kernel_classes_Class $testClass, core_kernel_classes_Class $targetItemClass - ): array { + ): array + { if ($importMetadata === true) { $metaMetadataValues = $this->getMetaMetadataExtractor()->extract($domManifest); $reportCtx->metaMetadata = $metaMetadataValues; @@ -1615,4 +1626,20 @@ private function getTestConverter(): TestConverter { return $this->getPsrContainer()->get(TestConverter::class); } + + private function getSectionConverter(): AssessmentSectionConverter + { + return $this->getPsrContainer()->get(AssessmentSectionConverter::class); + } + + /** + * @param AssessmentSectionRef[] $testDefinition + */ + private function convertAssessmentSectionRefs(QtiComponentCollection $assessmentSectionRefs, string $folder) + { + foreach ($assessmentSectionRefs as $assessmentSectionRef) { + $file = $folder . $assessmentSectionRef->getHref(); + $this->getSectionConverter()->convertToQti2($file); + } + } } From 954a75288bfe80e912e2cbe602fabeab02bba9ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Marsza=C5=82?= Date: Thu, 19 Dec 2024 16:44:10 +0100 Subject: [PATCH 6/6] feat: for taoSetup disable container usage. --- models/classes/class.QtiTestService.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/models/classes/class.QtiTestService.php b/models/classes/class.QtiTestService.php index 452e0734c..138910c4e 100644 --- a/models/classes/class.QtiTestService.php +++ b/models/classes/class.QtiTestService.php @@ -403,7 +403,12 @@ public function importMultipleTests( $file = $folder . 'imsmanifest.xml'; $qtiManifestParser = new taoQtiTest_models_classes_ManifestParser($file); $this->propagate($qtiManifestParser); - $this->getManifestConverter()->convertToQti2($file, $qtiManifestParser); + // For taoSetup PsrContainer is not available + // It is not required to perform manifest conversion in this process + // therefore we can skip it during taoSetup + if ($this->getPsrContainer()->has(ManifestConverter::class)) { + $this->getManifestConverter()->convertToQti2($file, $qtiManifestParser); + } // We validate manifest file against QTI 3.0 $qtiManifestParser->validate(); if ($qtiManifestParser->isValid() === true) { @@ -628,7 +633,9 @@ protected function importTest( ); } else { //Convert to QTI 2.2 - $this->getTestConverter()->convertToQti2($expectedTestFile); + if ($this->getPsrContainer()->has(TestConverter::class)) { + $this->getTestConverter()->convertToQti2($expectedTestFile); + } // -- Load the test in a QTISM flavour. $testDefinition = new XmlDocument(); @@ -1635,8 +1642,12 @@ private function getSectionConverter(): AssessmentSectionConverter /** * @param AssessmentSectionRef[] $testDefinition */ - private function convertAssessmentSectionRefs(QtiComponentCollection $assessmentSectionRefs, string $folder) + private function convertAssessmentSectionRefs(QtiComponentCollection $assessmentSectionRefs, string $folder): void { + if(!$this->getPsrContainer()->has(AssessmentSectionConverter::class)) { + return; + } + foreach ($assessmentSectionRefs as $assessmentSectionRef) { $file = $folder . $assessmentSectionRef->getHref(); $this->getSectionConverter()->convertToQti2($file);