Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
94.44% |
34 / 36 |
|
60.00% |
3 / 5 |
CRAP | |
0.00% |
0 / 1 |
QtiXmlDataManager | |
94.44% |
34 / 36 |
|
60.00% |
3 / 5 |
12.02 | |
0.00% |
0 / 1 |
replaceItemIdentifier | |
95.00% |
19 / 20 |
|
0.00% |
0 / 1 |
5 | |||
replaceFileContent | |
92.31% |
12 / 13 |
|
0.00% |
0 / 1 |
4.01 | |||
setAppNamespacePrefix | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getFileReferenceSerializer | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getIdentifierGenerator | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | /** |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License |
6 | * as published by the Free Software Foundation; under version 2 |
7 | * of the License (non-upgradable). |
8 | * |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write to the Free Software |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | * |
18 | * Copyright (c) 2020-2024 (original work) Open Assessment Technologies SA. |
19 | */ |
20 | |
21 | declare(strict_types=1); |
22 | |
23 | namespace oat\taoQtiItem\model\qti\copyist; |
24 | |
25 | use common_Exception; |
26 | use core_kernel_classes_Resource; |
27 | use core_kernel_persistence_Exception; |
28 | use DOMDocument; |
29 | use DOMElement; |
30 | use oat\generis\model\fileReference\FileReferenceSerializer; |
31 | use oat\generis\model\OntologyAwareTrait; |
32 | use oat\oatbox\filesystem\Directory; |
33 | use oat\oatbox\log\LoggerAwareTrait; |
34 | use oat\oatbox\service\ConfigurableService; |
35 | use oat\tao\model\IdentifierGenerator\Generator\IdentifierGeneratorInterface; |
36 | use oat\tao\model\IdentifierGenerator\Generator\IdentifierGeneratorProxy; |
37 | use oat\taoQtiItem\helpers\QtiFile; |
38 | use oat\oatbox\filesystem\File; |
39 | use tao_models_classes_FileNotFoundException; |
40 | use taoItems_models_classes_ItemsService; |
41 | |
42 | class QtiXmlDataManager extends ConfigurableService |
43 | { |
44 | use OntologyAwareTrait; |
45 | use LoggerAwareTrait; |
46 | |
47 | /** |
48 | * @var string |
49 | */ |
50 | private $prefix; |
51 | |
52 | /** |
53 | * All files will be copied from the previous resource |
54 | * so our responsibility to fix everything inside these files |
55 | * |
56 | * @param string $sourceItemId |
57 | * @param string $destinationItemId |
58 | * @throws common_Exception |
59 | * @throws core_kernel_persistence_Exception |
60 | * @throws tao_models_classes_FileNotFoundException |
61 | */ |
62 | public function replaceItemIdentifier( |
63 | string $sourceItemId, |
64 | string $destinationItemId |
65 | ): void { |
66 | $destinationItem = $this->getResource($destinationItemId); |
67 | |
68 | /** @var taoItems_models_classes_ItemsService $itemService */ |
69 | $itemService = $this->getServiceLocator()->get(taoItems_models_classes_ItemsService::class); |
70 | $serializer = $this->getFileReferenceSerializer(); |
71 | |
72 | foreach ($destinationItem->getUsedLanguages($itemService->getItemContentProperty()) as $lang) { |
73 | $destinationItemDirectory = $itemService->getItemDirectory($destinationItem, $lang); |
74 | |
75 | foreach ( |
76 | $destinationItem->getPropertyValuesCollection( |
77 | $itemService->getItemContentProperty(), |
78 | ['lg' => $lang] |
79 | )->getIterator() as $propertyValue |
80 | ) { |
81 | $id = $propertyValue instanceof core_kernel_classes_Resource |
82 | ? $propertyValue->getUri() |
83 | : (string) $propertyValue; |
84 | $destinationDirectory = $serializer->unserializeDirectory($id); |
85 | $iterator = $destinationDirectory->getFlyIterator( |
86 | Directory::ITERATOR_FILE | Directory::ITERATOR_RECURSIVE |
87 | ); |
88 | |
89 | foreach ($iterator as $iteratorFile) { |
90 | $filePath = $destinationItemDirectory->getRelPath($iteratorFile); |
91 | /** @var File $newFile */ |
92 | $file = $destinationItemDirectory->getFile($filePath); |
93 | |
94 | // do replace if needed |
95 | $this->replaceFileContent($file, $sourceItemId, $destinationItemId); |
96 | } |
97 | } |
98 | } |
99 | } |
100 | |
101 | /** |
102 | * As I know that qti.xml consist of xml, and if structure is expected - just replace identifier |
103 | * @param File $file |
104 | * @param string $fromSourceId |
105 | * @param string $toSourceId |
106 | * @throws common_Exception |
107 | */ |
108 | private function replaceFileContent(File $file, string $fromSourceId, string $toSourceId): void |
109 | { |
110 | if (preg_match('/' . QtiFile::FILE . '$/', $file->getBasename()) === 1) { |
111 | $xml = $file->read(); |
112 | $dom = new DOMDocument('1.0', 'UTF-8'); |
113 | |
114 | if ($dom->loadXML($xml) === true) { |
115 | $assessmentItemNodes = $dom->getElementsByTagName('assessmentItem'); |
116 | $identifierGenerator = $this->getIdentifierGenerator(); |
117 | |
118 | /** @var DOMElement $item */ |
119 | foreach ($assessmentItemNodes as $item) { |
120 | $identifier = $identifierGenerator->generate([ |
121 | IdentifierGeneratorInterface::OPTION_RESOURCE_ID => $toSourceId |
122 | ]); |
123 | |
124 | $item->setAttribute('identifier', $identifier); |
125 | } |
126 | } else { |
127 | $this->logWarning('Qti.xml does not have a valid xml, identifier will not be replaced'); |
128 | } |
129 | |
130 | $file->put($dom->saveXML()); |
131 | } |
132 | } |
133 | |
134 | public function setAppNamespacePrefix(string $prefix): void |
135 | { |
136 | $this->prefix = $prefix; |
137 | } |
138 | |
139 | /** |
140 | * Get serializer to persist filesystem object |
141 | * |
142 | * @return FileReferenceSerializer |
143 | */ |
144 | protected function getFileReferenceSerializer(): FileReferenceSerializer |
145 | { |
146 | return $this->getServiceLocator()->get(FileReferenceSerializer::SERVICE_ID); |
147 | } |
148 | |
149 | private function getIdentifierGenerator(): IdentifierGeneratorInterface |
150 | { |
151 | return $this->getServiceManager()->getContainer()->get(IdentifierGeneratorProxy::class); |
152 | } |
153 | } |