Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
84.40% |
92 / 109 |
|
33.33% |
2 / 6 |
CRAP | |
0.00% |
0 / 1 |
TranslationCreationService | |
84.40% |
92 / 109 |
|
33.33% |
2 / 6 |
19.23 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
setResourceTransfer | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addPostCreation | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
createByRequest | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
create | |
95.29% |
81 / 85 |
|
0.00% |
0 / 1 |
10 | |||
getResourceTransfer | |
50.00% |
3 / 6 |
|
0.00% |
0 / 1 |
2.50 |
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) 2024 (original work) Open Assessment Technologies SA; |
19 | */ |
20 | |
21 | declare(strict_types=1); |
22 | |
23 | namespace oat\tao\model\Translation\Service; |
24 | |
25 | use core_kernel_classes_Resource; |
26 | use oat\generis\model\data\Ontology; |
27 | use oat\oatbox\event\EventManager; |
28 | use oat\tao\model\Language\Business\Contract\LanguageRepositoryInterface; |
29 | use oat\tao\model\Language\Language; |
30 | use oat\tao\model\resources\Command\ResourceTransferCommand; |
31 | use oat\tao\model\resources\Contract\ResourceTransferInterface; |
32 | use oat\tao\model\TaoOntology; |
33 | use oat\tao\model\Translation\Command\CreateTranslationCommand; |
34 | use oat\tao\model\Translation\Entity\ResourceTranslatable; |
35 | use oat\tao\model\Translation\Event\TranslationActionEvent; |
36 | use oat\tao\model\Translation\Exception\ResourceTranslationException; |
37 | use oat\tao\model\Translation\Query\ResourceTranslatableQuery; |
38 | use oat\tao\model\Translation\Query\ResourceTranslationQuery; |
39 | use oat\tao\model\Translation\Repository\ResourceTranslatableRepository; |
40 | use oat\tao\model\Translation\Repository\ResourceTranslationRepository; |
41 | use Psr\Http\Message\ServerRequestInterface; |
42 | use Psr\Log\LoggerInterface; |
43 | use Throwable; |
44 | |
45 | class TranslationCreationService |
46 | { |
47 | private Ontology $ontology; |
48 | private ResourceTranslatableRepository $resourceTranslatableRepository; |
49 | private ResourceTranslationRepository $resourceTranslationRepository; |
50 | private LanguageRepositoryInterface $languageRepository; |
51 | private LoggerInterface $logger; |
52 | private TranslatedIntoLanguagesSynchronizer $translatedIntoLanguagesSynchronizer; |
53 | private EventManager $eventManager; |
54 | |
55 | private array $resourceTransferServices; |
56 | private array $callables; |
57 | |
58 | public function __construct( |
59 | Ontology $ontology, |
60 | ResourceTranslatableRepository $resourceTranslatableRepository, |
61 | ResourceTranslationRepository $resourceTranslationRepository, |
62 | LanguageRepositoryInterface $languageRepository, |
63 | LoggerInterface $logger, |
64 | TranslatedIntoLanguagesSynchronizer $translatedIntoLanguagesSynchronizer, |
65 | EventManager $eventManager |
66 | ) { |
67 | $this->ontology = $ontology; |
68 | $this->resourceTranslatableRepository = $resourceTranslatableRepository; |
69 | $this->resourceTranslationRepository = $resourceTranslationRepository; |
70 | $this->languageRepository = $languageRepository; |
71 | $this->logger = $logger; |
72 | $this->translatedIntoLanguagesSynchronizer = $translatedIntoLanguagesSynchronizer; |
73 | $this->eventManager = $eventManager; |
74 | } |
75 | |
76 | public function setResourceTransfer(string $resourceType, ResourceTransferInterface $resourceTransfer): void |
77 | { |
78 | $this->resourceTransferServices[$resourceType] = $resourceTransfer; |
79 | } |
80 | |
81 | public function addPostCreation(string $resourceType, callable $callable): void |
82 | { |
83 | $this->callables[$resourceType] ??= []; |
84 | $this->callables[$resourceType][] = $callable; |
85 | } |
86 | |
87 | public function createByRequest(ServerRequestInterface $request): core_kernel_classes_Resource |
88 | { |
89 | $requestParams = $request->getParsedBody(); |
90 | $id = $requestParams['id'] ?? null; |
91 | $languageUri = $requestParams['languageUri'] ?? null; |
92 | |
93 | if (empty($id)) { |
94 | throw new ResourceTranslationException('Resource id is required'); |
95 | } |
96 | |
97 | if (empty($languageUri)) { |
98 | throw new ResourceTranslationException('Parameter languageUri is mandatory'); |
99 | } |
100 | |
101 | return $this->create(new CreateTranslationCommand($id, $languageUri)); |
102 | } |
103 | |
104 | public function create(CreateTranslationCommand $command): core_kernel_classes_Resource |
105 | { |
106 | try { |
107 | $resourceUri = $command->getResourceUri(); |
108 | $languageUri = $command->getLanguageUri(); |
109 | |
110 | $translations = $this->resourceTranslationRepository->find( |
111 | new ResourceTranslationQuery([$resourceUri], $languageUri) |
112 | ); |
113 | |
114 | if ($translations->count() > 0) { |
115 | throw new ResourceTranslationException( |
116 | sprintf( |
117 | 'Translation already exists for [id=%s, locale=%s]', |
118 | $resourceUri, |
119 | $languageUri |
120 | ) |
121 | ); |
122 | } |
123 | |
124 | $resources = $this->resourceTranslatableRepository->find(new ResourceTranslatableQuery($resourceUri)); |
125 | |
126 | if ($resources->count() === 0) { |
127 | throw new ResourceTranslationException(sprintf('Resource [id=%s] is not translatable', $resourceUri)); |
128 | } |
129 | |
130 | /** @var ResourceTranslatable $resource */ |
131 | $resource = $resources->current(); |
132 | |
133 | if (!$resource->isReadyForTranslation()) { |
134 | throw new ResourceTranslationException( |
135 | sprintf( |
136 | 'Resource [id=%s] is not ready for translation', |
137 | $resourceUri |
138 | ) |
139 | ); |
140 | } |
141 | |
142 | $existingLanguages = $this->languageRepository->findAvailableLanguagesByUsage(); |
143 | $language = null; |
144 | |
145 | /** @var Language $language */ |
146 | foreach ($existingLanguages as $existingLanguage) { |
147 | if ($existingLanguage->getUri() === $languageUri) { |
148 | $language = $existingLanguage; |
149 | } |
150 | } |
151 | |
152 | if (!$language) { |
153 | throw new ResourceTranslationException(sprintf('Language %s does not exist', $languageUri)); |
154 | } |
155 | |
156 | if ($resource->getLanguageUri() === $language->getUri()) { |
157 | throw new ResourceTranslationException( |
158 | sprintf('Cannot translate to original language %s', $languageUri) |
159 | ); |
160 | } |
161 | |
162 | $instance = $this->ontology->getResource($resourceUri); |
163 | $rootId = $instance->getRootId(); |
164 | |
165 | $clonedInstanceUri = $this->getResourceTransfer($rootId)->transfer( |
166 | new ResourceTransferCommand( |
167 | $resourceUri, |
168 | $instance->getParentClassId(), |
169 | null, |
170 | null |
171 | ) |
172 | )->getDestination(); |
173 | $clonedInstance = $this->ontology->getResource($clonedInstanceUri); |
174 | $clonedInstance->setLabel(sprintf('%s (%s)', $instance->getLabel(), $language->getCode())); |
175 | |
176 | $clonedInstance->editPropertyValues( |
177 | $this->ontology->getProperty(TaoOntology::PROPERTY_LANGUAGE), |
178 | $language->getUri() |
179 | ); |
180 | |
181 | $clonedInstance->editPropertyValues( |
182 | $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_TYPE), |
183 | TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION |
184 | ); |
185 | |
186 | $clonedInstance->editPropertyValues( |
187 | $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_PROGRESS), |
188 | TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_PENDING |
189 | ); |
190 | |
191 | $clonedInstance->editPropertyValues( |
192 | $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_ORIGINAL_RESOURCE_URI), |
193 | $resourceUri |
194 | ); |
195 | |
196 | foreach ($this->callables[$rootId] ?? [] as $callable) { |
197 | $callable($clonedInstance); |
198 | } |
199 | |
200 | $this->translatedIntoLanguagesSynchronizer->sync($instance); |
201 | |
202 | $this->eventManager->trigger(new TranslationActionEvent( |
203 | TranslationActionEvent::ACTION_CREATED, |
204 | $rootId, |
205 | $resourceUri, |
206 | $clonedInstanceUri, |
207 | $language->getCode() |
208 | )); |
209 | |
210 | return $clonedInstance; |
211 | } catch (Throwable $exception) { |
212 | $this->logger->error( |
213 | sprintf( |
214 | 'Could not translate [id=%s, language=%s] (%s): %s', |
215 | $resourceUri, |
216 | $languageUri, |
217 | get_class($exception), |
218 | $exception->getMessage() |
219 | ) |
220 | ); |
221 | |
222 | throw $exception; |
223 | } |
224 | } |
225 | |
226 | private function getResourceTransfer(string $resourceType): ResourceTransferInterface |
227 | { |
228 | $service = $this->resourceTransferServices[$resourceType] ?? null; |
229 | |
230 | if ($service) { |
231 | return $service; |
232 | } |
233 | |
234 | throw new ResourceTranslationException( |
235 | sprintf('Missing ResourceTransfer for resource type %s', $resourceType) |
236 | ); |
237 | } |
238 | } |