Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 97 |
|
0.00% |
0 / 8 |
CRAP | |
0.00% |
0 / 1 |
ImportAndCompile | |
0.00% |
0 / 97 |
|
0.00% |
0 / 8 |
870 | |
0.00% |
0 / 1 |
__invoke | |
0.00% |
0 / 49 |
|
0.00% |
0 / 1 |
182 | |||
createTask | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
2 | |||
jsonSerialize | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
checkParams | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
20 | |||
checkSubClasses | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
determineParentClass | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
30 | |||
getImporter | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getQtiTestService | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
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) 2017-2020 (original work) Open Assessment Technologies SA; |
19 | */ |
20 | |
21 | namespace oat\taoDeliveryRdf\model\tasks; |
22 | |
23 | use Exception; |
24 | use JsonSerializable; |
25 | use common_Logger as Logger; |
26 | use common_report_Report as Report; |
27 | use common_exception_Error as Error; |
28 | use oat\oatbox\service\ServiceManager; |
29 | use oat\oatbox\task\AbstractTaskAction; |
30 | use common_Exception as CommonException; |
31 | use oat\generis\model\OntologyAwareTrait; |
32 | use oat\tao\model\import\ImportersService; |
33 | use core_kernel_classes_Class as CoreClass; |
34 | use oat\tao\model\taskQueue\QueueDispatcher; |
35 | use core_kernel_classes_Resource as Resource; |
36 | use oat\taoDeliveryRdf\model\DeliveryFactory; |
37 | use oat\taoTests\models\import\AbstractTestImporter; |
38 | use oat\taoDeliveryRdf\model\DeliveryAssemblyService; |
39 | use oat\tao\model\taskQueue\Task\CallbackTaskInterface; |
40 | use oat\oatbox\service\exception\InvalidServiceManagerException; |
41 | use common_exception_InconsistentData as InconsistentDataException; |
42 | use common_exception_MissingParameter as MissingParameterException; |
43 | use taoQtiTest_models_classes_QtiTestService as QtiTestService; |
44 | use Throwable; |
45 | |
46 | /** |
47 | * Class ImportAndCompile |
48 | * Action to import test and compile it into delivery |
49 | * |
50 | * @package oat\taoDeliveryRdf\model\tasks |
51 | * |
52 | * @author Aleh Hutnikau, <hutnikau@1pt.com> |
53 | */ |
54 | class ImportAndCompile extends AbstractTaskAction implements JsonSerializable |
55 | { |
56 | use OntologyAwareTrait; |
57 | |
58 | public const FILE_DIR = 'ImportAndCompileTask'; |
59 | private const OPTION_FILE = 'file'; |
60 | private const OPTION_IMPORTER = 'importer'; |
61 | private const OPTION_CUSTOM = 'custom'; |
62 | private const OPTION_DELIVERY_LABELS = 'delivery-class-labels'; |
63 | |
64 | /** |
65 | * @param array $params |
66 | * |
67 | * @throws Error |
68 | * @throws InconsistentDataException |
69 | * @throws MissingParameterException |
70 | * |
71 | * @return Report |
72 | */ |
73 | public function __invoke($params) |
74 | { |
75 | $this->checkParams($params); |
76 | |
77 | /** @var string[] $customParams */ |
78 | $customParams = $params[self::OPTION_CUSTOM]; |
79 | |
80 | $file = $this->getFileReferenceSerializer()->unserializeFile($params[self::OPTION_FILE]); |
81 | $report = null; |
82 | $test = null; |
83 | $importer = $this->getImporter($params[self::OPTION_IMPORTER]); |
84 | |
85 | try { |
86 | /** @var Report $report */ |
87 | $report = $importer->import($file); |
88 | |
89 | if ($report->getType() === Report::TYPE_SUCCESS) { |
90 | foreach ($report as $r) { |
91 | /** @var Resource $test */ |
92 | $test = $r->getData()->rdfsResource; |
93 | } |
94 | } else { |
95 | throw new CommonException( |
96 | $file->getBasename() . ' Unable to import test with message ' . $report->getMessage() |
97 | ); |
98 | } |
99 | |
100 | $label = 'Delivery of ' . $test->getLabel(); |
101 | $parent = $this->checkSubClasses($params[self::OPTION_DELIVERY_LABELS]); |
102 | $deliveryFactory = $this->getServiceManager()->get(DeliveryFactory::SERVICE_ID); |
103 | $compilationReport = $deliveryFactory->create($parent, $test, $label, null, $customParams); |
104 | |
105 | if ($compilationReport->getType() == Report::TYPE_ERROR) { |
106 | Logger::i( |
107 | 'Unable to generate delivery execution into taoDeliveryRdf::RestDelivery for test uri ' |
108 | . $test->getUri() |
109 | ); |
110 | } |
111 | /** @var Resource $delivery */ |
112 | $delivery = $compilationReport->getData(); |
113 | |
114 | if ($delivery instanceof Resource && is_array($customParams)) { |
115 | foreach ($customParams as $rdfKey => $rdfValue) { |
116 | $property = $this->getProperty($rdfKey); |
117 | $delivery->editPropertyValues($property, $rdfValue); |
118 | } |
119 | } |
120 | |
121 | $report->add($compilationReport); |
122 | $report->setData(['delivery-uri' => $delivery->getUri()]); |
123 | |
124 | return $report; |
125 | } catch (Exception $e) { |
126 | Logger::singleton()->handleException($e); |
127 | } catch (Throwable $e) { |
128 | Logger::f($e->getMessage(), [ |
129 | Logger::CONTEXT_EXCEPTION => get_class($e), |
130 | Logger::CONTEXT_ERROR_FILE => $e->getFile(), |
131 | Logger::CONTEXT_ERROR_LINE => $e->getLine(), |
132 | Logger::CONTEXT_TRACE => $e->getTrace() |
133 | ]); |
134 | } finally { |
135 | if (!isset($e)) { |
136 | return $report; |
137 | } |
138 | |
139 | if (null !== $report) { |
140 | $this->getQtiTestService()->clearRelatedResources($report); |
141 | } |
142 | |
143 | $detailedErrorReport = Report::createFailure($e->getMessage()); |
144 | |
145 | if ($report) { |
146 | $errors = $report->getErrors(); |
147 | |
148 | foreach ($errors as $error) { |
149 | $detailedErrorReport->add($error->getErrors()); |
150 | } |
151 | } |
152 | |
153 | return $detailedErrorReport; |
154 | } |
155 | } |
156 | |
157 | /** |
158 | * Create task in queue |
159 | * |
160 | * @param string $importerId test importer identifier |
161 | * @param array $file uploaded file @see \tao_helpers_Http::getUploadedFile() |
162 | * @param array $customParams |
163 | * @param array $deliveryClassLabels |
164 | * |
165 | * @return CallbackTaskInterface |
166 | */ |
167 | public static function createTask( |
168 | string $importerId, |
169 | array $file, |
170 | array $customParams = [], |
171 | array $deliveryClassLabels = [] |
172 | ): CallbackTaskInterface { |
173 | $serviceManager = ServiceManager::getServiceManager(); |
174 | $action = new self(); |
175 | $action->setServiceLocator($serviceManager); |
176 | |
177 | $importersService = $serviceManager->get(ImportersService::SERVICE_ID); |
178 | $importersService->getImporter($importerId); |
179 | |
180 | $fileUri = $action->saveFile($file['tmp_name'], $file['name']); |
181 | /** @var QueueDispatcher $queueDispatcher */ |
182 | $queueDispatcher = ServiceManager::getServiceManager()->get(QueueDispatcher::SERVICE_ID); |
183 | $taskParameters = [ |
184 | self::OPTION_FILE => $fileUri, |
185 | self::OPTION_IMPORTER => $importerId, |
186 | self::OPTION_CUSTOM => $customParams, |
187 | self::OPTION_DELIVERY_LABELS => $deliveryClassLabels, |
188 | ]; |
189 | $taskTitle = __('Import QTI test and create delivery.'); |
190 | |
191 | return $queueDispatcher->createTask($action, $taskParameters, $taskTitle, null, true); |
192 | } |
193 | |
194 | /** |
195 | * @return string |
196 | */ |
197 | public function jsonSerialize() |
198 | { |
199 | return __CLASS__; |
200 | } |
201 | |
202 | /** |
203 | * @param array $params |
204 | * |
205 | * @throws InvalidServiceManagerException |
206 | * @throws InconsistentDataException |
207 | * @throws MissingParameterException |
208 | */ |
209 | private function checkParams(array $params): void |
210 | { |
211 | foreach ([self::OPTION_FILE, self::OPTION_IMPORTER] as $param) { |
212 | if (!isset($params[$param])) { |
213 | throw new MissingParameterException(sprintf( |
214 | 'Missing parameter `%s` in %s', |
215 | $param, |
216 | self::class |
217 | )); |
218 | } |
219 | } |
220 | |
221 | $importer = $this->getImporter($params[self::OPTION_IMPORTER]); |
222 | |
223 | if (!$importer instanceof AbstractTestImporter) { |
224 | throw new InconsistentDataException(sprintf( |
225 | 'Wrong importer `%s`', |
226 | $params[self::OPTION_IMPORTER] |
227 | )); |
228 | } |
229 | } |
230 | |
231 | /** |
232 | * @param array $classLabels |
233 | * |
234 | * @return CoreClass |
235 | */ |
236 | private function checkSubClasses(array $classLabels = []): CoreClass |
237 | { |
238 | $parent = $this->determineParentClass(new CoreClass(DeliveryAssemblyService::CLASS_URI), $classLabels); |
239 | |
240 | if (!empty($classLabels)) { |
241 | foreach ($classLabels as $classLabel) { |
242 | $parent = $parent->createSubClass($classLabel); |
243 | } |
244 | } |
245 | |
246 | return $parent; |
247 | } |
248 | |
249 | /** |
250 | * @param CoreClass $parent |
251 | * @param array $classLabels |
252 | * @param int $level |
253 | * |
254 | * @return CoreClass |
255 | */ |
256 | private function determineParentClass(CoreClass $parent, array &$classLabels): CoreClass |
257 | { |
258 | if (empty($classLabels)) { |
259 | return $parent; |
260 | } |
261 | |
262 | foreach ($parent->getSubClasses(true) as $deliveryClass) { |
263 | if (isset($classLabels[0]) && $classLabels[0] === $deliveryClass->getLabel()) { |
264 | $classLabels = array_slice($classLabels, 1); |
265 | $parent = $this->determineParentClass($deliveryClass, $classLabels) ?? $parent; |
266 | |
267 | break; |
268 | } |
269 | } |
270 | |
271 | return $parent; |
272 | } |
273 | |
274 | /** |
275 | * @param string $id |
276 | * |
277 | * @throws InvalidServiceManagerException |
278 | * |
279 | * @return mixed |
280 | */ |
281 | private function getImporter(string $id) |
282 | { |
283 | $importersService = $this->getServiceManager()->get(ImportersService::SERVICE_ID); |
284 | |
285 | return $importersService->getImporter($id); |
286 | } |
287 | |
288 | private function getQtiTestService(): QtiTestService |
289 | { |
290 | return $this->getServiceLocator()->get(QtiTestService::class); |
291 | } |
292 | } |