Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
71.43% covered (warning)
71.43%
35 / 49
42.86% covered (danger)
42.86%
3 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
TranslationSyncService
71.43% covered (warning)
71.43%
35 / 49
42.86% covered (danger)
42.86%
3 / 7
20.25
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 addSynchronizer
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 syncByRequest
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 syncById
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
4.01
 assertResourceExists
50.00% covered (danger)
50.00%
1 / 2
0.00% covered (danger)
0.00%
0 / 1
2.50
 assertIsOriginal
57.14% covered (warning)
57.14%
4 / 7
0.00% covered (danger)
0.00%
0 / 1
2.31
 getTranslations
55.00% covered (warning)
55.00%
11 / 20
0.00% covered (danger)
0.00%
0 / 1
5.46
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
21declare(strict_types=1);
22
23namespace oat\tao\model\Translation\Service;
24
25use core_kernel_classes_Resource;
26use oat\generis\model\data\Ontology;
27use oat\tao\model\TaoOntology;
28use oat\tao\model\Translation\Entity\ResourceTranslation;
29use oat\tao\model\Translation\Exception\ResourceTranslationException;
30use oat\tao\model\Translation\Query\ResourceTranslationQuery;
31use oat\tao\model\Translation\Repository\ResourceTranslationRepository;
32use Psr\Http\Message\ServerRequestInterface;
33use Psr\Log\LoggerInterface;
34
35class TranslationSyncService
36{
37    private Ontology $ontology;
38    private ResourceTranslationRepository $resourceTranslationRepository;
39    private LoggerInterface $logger;
40    private TranslatedIntoLanguagesSynchronizer $translatedIntoLanguagesSynchronizer;
41    private array $synchronizers;
42
43    public function __construct(
44        Ontology $ontology,
45        ResourceTranslationRepository $resourceTranslationRepository,
46        LoggerInterface $logger,
47        TranslatedIntoLanguagesSynchronizer $translatedIntoLanguagesSynchronizer
48    ) {
49        $this->ontology = $ontology;
50        $this->resourceTranslationRepository = $resourceTranslationRepository;
51        $this->logger = $logger;
52        $this->translatedIntoLanguagesSynchronizer = $translatedIntoLanguagesSynchronizer;
53    }
54
55    public function addSynchronizer(string $resourceType, callable $synchronizer): void
56    {
57        $this->synchronizers[$resourceType] ??= [];
58        $this->synchronizers[$resourceType][] = $synchronizer;
59    }
60
61    public function syncByRequest(ServerRequestInterface $request): core_kernel_classes_Resource
62    {
63        $requestParams = $request->getParsedBody();
64        $id = $requestParams['id'] ?? null;
65
66        return $this->syncById($id);
67    }
68
69    public function syncById(string $id): core_kernel_classes_Resource
70    {
71        if (empty($id)) {
72            throw new ResourceTranslationException('Resource id is required');
73        }
74
75        $resource = $this->ontology->getResource($id);
76
77        $this->assertResourceExists($resource);
78        $this->assertIsOriginal($resource);
79
80        $translations = $this->getTranslations($resource, $requestParams['languageUri'] ?? null);
81
82        foreach ($this->synchronizers[$resource->getRootId()] as $callable) {
83            foreach ($translations as $translation) {
84                $callable($translation);
85            }
86        }
87
88        $this->translatedIntoLanguagesSynchronizer->sync($resource);
89
90        return $resource;
91    }
92
93    private function assertResourceExists(core_kernel_classes_Resource $resource): void
94    {
95        if (!$resource->exists()) {
96            throw new ResourceTranslationException(sprintf('Resource %s does not exist', $resource->getUri()));
97        }
98    }
99
100    private function assertIsOriginal(core_kernel_classes_Resource $resource): void
101    {
102        $translationType = $resource->getOnePropertyValue(
103            $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_TYPE)
104        );
105
106        if ($translationType->getUri() !== TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL) {
107            throw new ResourceTranslationException(
108                sprintf('Resource %s is not the original', $resource->getUri())
109            );
110        }
111    }
112
113    /**
114     * @return core_kernel_classes_Resource[]
115     */
116    private function getTranslations(core_kernel_classes_Resource $resource, ?string $languageUri): array
117    {
118        $translations = $this->resourceTranslationRepository->find(new ResourceTranslationQuery(
119            [$resource->getUri()],
120            $languageUri
121        ));
122
123        $resources = [];
124
125        /** @var ResourceTranslation $translation */
126        foreach ($translations as $translation) {
127            $translationResource = $this->ontology->getResource($translation->getResourceUri());
128
129            if (!$translationResource->exists()) {
130                $this->logger->error('Resource %s does not exist', $translation->getResourceUri());
131
132                continue;
133            }
134
135            $resources[] = $translationResource;
136        }
137
138        if (empty($resources)) {
139            throw new ResourceTranslationException(
140                sprintf(
141                    'Translations for resource does not exist [Resource: %s, Language URI: %s]',
142                    $resource->getUri(),
143                    $languageUri
144                )
145            );
146        }
147
148        return $resources;
149    }
150}