*/ class ImportAndCompile extends AbstractTaskAction implements JsonSerializable { use OntologyAwareTrait; public const FILE_DIR = 'ImportAndCompileTask'; private const OPTION_FILE = 'file'; private const OPTION_IMPORTER = 'importer'; private const OPTION_CUSTOM = 'custom'; private const OPTION_DELIVERY_LABELS = 'delivery-class-labels'; /** * @param array $params * * @throws Error * @throws InconsistentDataException * @throws MissingParameterException * * @return Report */ public function __invoke($params) { $this->checkParams($params); /** @var string[] $customParams */ $customParams = $params[self::OPTION_CUSTOM]; $file = $this->getFileReferenceSerializer()->unserializeFile($params[self::OPTION_FILE]); $report = null; $test = null; $importer = $this->getImporter($params[self::OPTION_IMPORTER]); try { /** @var Report $report */ $report = $importer->import($file); if ($report->getType() === Report::TYPE_SUCCESS) { foreach ($report as $r) { /** @var Resource $test */ $test = $r->getData()->rdfsResource; } } else { throw new CommonException( $file->getBasename() . ' Unable to import test with message ' . $report->getMessage() ); } $label = 'Delivery of ' . $test->getLabel(); $parent = $this->checkSubClasses($params[self::OPTION_DELIVERY_LABELS]); $deliveryFactory = $this->getServiceManager()->get(DeliveryFactory::SERVICE_ID); $compilationReport = $deliveryFactory->create($parent, $test, $label, null, $customParams); if ($compilationReport->getType() == Report::TYPE_ERROR) { Logger::i( 'Unable to generate delivery execution into taoDeliveryRdf::RestDelivery for test uri ' . $test->getUri() ); } /** @var Resource $delivery */ $delivery = $compilationReport->getData(); if ($delivery instanceof Resource && is_array($customParams)) { foreach ($customParams as $rdfKey => $rdfValue) { $property = $this->getProperty($rdfKey); $delivery->editPropertyValues($property, $rdfValue); } } $report->add($compilationReport); $report->setData(['delivery-uri' => $delivery->getUri()]); return $report; } catch (Exception $e) { if (null !== $report) { $this->getQtiTestService()->clearRelatedResources($report); } $detailedErrorReport = Report::createFailure($e->getMessage()); if ($report) { $errors = $report->getErrors(); foreach ($errors as $error) { $detailedErrorReport->add($error->getErrors()); } } return $detailedErrorReport; } } /** * Create task in queue * * @param string $importerId test importer identifier * @param array $file uploaded file @see \tao_helpers_Http::getUploadedFile() * @param array $customParams * @param array $deliveryClassLabels * * @return CallbackTaskInterface */ public static function createTask( string $importerId, array $file, array $customParams = [], array $deliveryClassLabels = [] ): CallbackTaskInterface { $serviceManager = ServiceManager::getServiceManager(); $action = new self(); $action->setServiceLocator($serviceManager); $importersService = $serviceManager->get(ImportersService::SERVICE_ID); $importersService->getImporter($importerId); $fileUri = $action->saveFile($file['tmp_name'], $file['name']); /** @var QueueDispatcher $queueDispatcher */ $queueDispatcher = ServiceManager::getServiceManager()->get(QueueDispatcher::SERVICE_ID); $taskParameters = [ self::OPTION_FILE => $fileUri, self::OPTION_IMPORTER => $importerId, self::OPTION_CUSTOM => $customParams, self::OPTION_DELIVERY_LABELS => $deliveryClassLabels, ]; $taskTitle = __('Import QTI test and create delivery.');; return $queueDispatcher->createTask($action, $taskParameters, $taskTitle, null, true); } /** * @return string */ public function jsonSerialize() { return __CLASS__; } /** * @param array $params * * @throws InvalidServiceManagerException * @throws InconsistentDataException * @throws MissingParameterException */ private function checkParams(array $params): void { foreach ([self::OPTION_FILE, self::OPTION_IMPORTER] as $param) { if (!isset($params[$param])) { throw new MissingParameterException(sprintf( 'Missing parameter `%s` in %s', $param, self::class )); } } $importer = $this->getImporter($params[self::OPTION_IMPORTER]); if (!$importer instanceof AbstractTestImporter) { throw new InconsistentDataException(sprintf( 'Wrong importer `%s`', $params[self::OPTION_IMPORTER] )); } } /** * @param array $classLabels * * @return CoreClass */ private function checkSubClasses(array $classLabels = []): CoreClass { $parent = $this->determineParentClass(new CoreClass(DeliveryAssemblyService::CLASS_URI), $classLabels); if (!empty($classLabels)) { foreach ($classLabels as $classLabel) { $parent = $parent->createSubClass($classLabel); } } return $parent; } /** * @param CoreClass $parent * @param array $classLabels * @param int $level * * @return CoreClass */ private function determineParentClass(CoreClass $parent, array &$classLabels): CoreClass { if (empty($classLabels)) { return $parent; } foreach ($parent->getSubClasses(true) as $deliveryClass) { if (isset($classLabels[0]) && $classLabels[0] === $deliveryClass->getLabel()) { $classLabels = array_slice($classLabels, 1); $parent = $this->determineParentClass($deliveryClass, $classLabels) ?? $parent; break; } } return $parent; } /** * @param string $id * * @throws InvalidServiceManagerException * * @return mixed */ private function getImporter(string $id) { $importersService = $this->getServiceManager()->get(ImportersService::SERVICE_ID); return $importersService->getImporter($id); } private function getQtiTestService(): QtiTestService { return $this->getServiceLocator()->get(QtiTestService::class); } }