From 20e4c74678b33c264d24757896f6ebf57b02f1cc Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Wed, 4 Sep 2024 14:38:16 +0200 Subject: [PATCH 01/50] chore: document README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4424ca77eb..d7dd1ee4a4 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,7 @@ Here you can find the environment variables including feature flags | DATA_STORE_STATISTIC_PUB_SUB_TOPIC | Topic name for statistic metadata Pub/Sub | - | | REDIRECT_AFTER_LOGOUT_URL | Allows to configure the redirect after logout via environment variable. The fallback is the configured redirect on urlroute.conf.php | - | | PORTAL_URL | The Portal url used on the back button of Portal theme | - | +| FEATURE_TRANSLATION_ENABLED | Enable access to items/tests translations feature | - | # Routing From 48ff6bbf8e29bb0c8759578118d62c4d6b149409 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Wed, 4 Sep 2024 15:35:33 +0200 Subject: [PATCH 02/50] feat: adding base classes for translation --- actions/class.Translation.php | 107 ++++++++++++++++++ manifest.php | 4 +- .../Entity/ResourceTranslationStatus.php | 54 +++++++++ .../Query/ResourceTranslationStatusQuery.php | 40 +++++++ .../ResourceTranslationStatusService.php | 38 +++++++ .../TranslationServiceProvider.php | 42 +++++++ 6 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 actions/class.Translation.php create mode 100644 models/classes/Translation/Entity/ResourceTranslationStatus.php create mode 100644 models/classes/Translation/Query/ResourceTranslationStatusQuery.php create mode 100644 models/classes/Translation/Service/ResourceTranslationStatusService.php create mode 100644 models/classes/Translation/ServiceProvider/TranslationServiceProvider.php diff --git a/actions/class.Translation.php b/actions/class.Translation.php new file mode 100644 index 0000000000..661698a6a7 --- /dev/null +++ b/actions/class.Translation.php @@ -0,0 +1,107 @@ + + */ + +declare(strict_types=1); + +use GuzzleHttp\Psr7\ServerRequest; +use oat\generis\model\OntologyAwareTrait; +use oat\tao\model\http\HttpJsonResponseTrait; +use oat\tao\model\Lists\Business\Contract\DependsOnPropertyRepositoryInterface; +use oat\tao\model\Lists\Business\Service\ValueCollectionService; +use oat\tao\model\Lists\DataAccess\Repository\DependsOnPropertyRepository; +use oat\tao\model\Lists\DataAccess\Repository\DependentPropertiesRepository; +use oat\tao\model\Lists\Business\Domain\DependentPropertiesRepositoryContext; +use oat\tao\model\Lists\Presentation\Web\RequestHandler\ValueCollectionSearchRequestHandler; + +class tao_actions_Translation extends tao_actions_CommonModule +{ + use HttpJsonResponseTrait; + use OntologyAwareTrait; + + public function status(): void + { + $this->setSuccessJsonResponse( + [ + '' + ] + ); + } + + public function getDependOnPropertyList(): void + { + $property = $this->hasGetParameter('property_uri') + ? $this->getProperty(tao_helpers_Uri::decode($this->getGetParameter('property_uri'))) + : null; + + $class = $this->hasGetParameter('class_uri') + ? $this->getClass(tao_helpers_Uri::decode($this->getGetParameter('class_uri'))) + : null; + + $widgetUri = $this->hasGetParameter('type') + ? tao_helpers_form_GenerisFormFactory::getWidgetUriById($this->getGetParameter('type')) + : null; + + $this->setSuccessJsonResponse( + $this->getRepository()->findAll( + [ + DependsOnPropertyRepositoryInterface::FILTER_PROPERTY_WIDGET_URI => $widgetUri, + DependsOnPropertyRepositoryInterface::FILTER_PROPERTY => $property, + DependsOnPropertyRepositoryInterface::FILTER_CLASS => $class, + DependsOnPropertyRepositoryInterface::FILTER_LIST_URI => $this->getProperty( + tao_helpers_Uri::decode($this->getGetParameter('list_uri')) + )->getUri() + ] + ) + ); + } + + public function getDependentProperties(DependentPropertiesRepository $dependentPropertiesRepository): void + { + $property = $this->getProperty( + tao_helpers_Uri::decode( + $this->getGetParameter('propertyUri', '') + ) + ); + + $dependentProperties = $dependentPropertiesRepository->findAll( + new DependentPropertiesRepositoryContext([ + DependentPropertiesRepositoryContext::PARAM_PROPERTY => $property, + ]) + ); + + $this->setSuccessJsonResponse( + array_map( + static function (core_kernel_classes_Resource $property) { + return [ + 'label' => $property->getLabel(), + ]; + }, + $dependentProperties + ) + ); + } + + private function getRepository(): DependsOnPropertyRepositoryInterface + { + return $this->getPsrContainer()->get(DependsOnPropertyRepository::class); + } +} diff --git a/manifest.php b/manifest.php index a94598883d..00d6625fe1 100755 --- a/manifest.php +++ b/manifest.php @@ -57,6 +57,7 @@ use oat\tao\model\routing\ServiceProvider\RoutingServiceProvider; use oat\tao\model\search\ServiceProvider\SearchServiceProvider; use oat\tao\model\StatisticalMetadata\StatisticalMetadataServiceProvider; +use oat\tao\model\Translation\ServiceProvider\TranslationServiceProvider; use oat\tao\model\user\TaoRoles; use oat\tao\model\user\UserSettingsServiceProvider; use oat\tao\model\webhooks\WebhookServiceProvider; @@ -418,7 +419,8 @@ MenuServiceProvider::class, FormDataProviderServiceProvider::class, PropertyServiceProvider::class, - DynamicConfigServiceProvider::class + DynamicConfigServiceProvider::class, + TranslationServiceProvider::class ], 'middlewares' => [ MiddlewareConfig::class, diff --git a/models/classes/Translation/Entity/ResourceTranslationStatus.php b/models/classes/Translation/Entity/ResourceTranslationStatus.php new file mode 100644 index 0000000000..657070313c --- /dev/null +++ b/models/classes/Translation/Entity/ResourceTranslationStatus.php @@ -0,0 +1,54 @@ +translations[$locale] = [ + 'status' => $status, + 'resourceUri' => $resourceUri + ]; + } + + public function getTranslations(): array + { + return $this->translations; + } + + public function jsonSerialize(): array + { + return [ + 'translations' => $this->translations + ]; + } +} diff --git a/models/classes/Translation/Query/ResourceTranslationStatusQuery.php b/models/classes/Translation/Query/ResourceTranslationStatusQuery.php new file mode 100644 index 0000000000..de3db491ac --- /dev/null +++ b/models/classes/Translation/Query/ResourceTranslationStatusQuery.php @@ -0,0 +1,40 @@ +originResourceId = $originResourceId; + } + + public function getOriginResourceId(): string + { + return $this->originResourceId; + } +} diff --git a/models/classes/Translation/Service/ResourceTranslationStatusService.php b/models/classes/Translation/Service/ResourceTranslationStatusService.php new file mode 100644 index 0000000000..3ba2d75ac6 --- /dev/null +++ b/models/classes/Translation/Service/ResourceTranslationStatusService.php @@ -0,0 +1,38 @@ +services(); + $services->set(ResourceTranslationStatusService::class, ResourceTranslationStatusService::class) + ->public(); + } +} From 24fb95273aa3d6db6a21ad63735c9579b56a48d6 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Wed, 4 Sep 2024 15:42:41 +0200 Subject: [PATCH 03/50] chore: fix di injection --- .../Translation/ServiceProvider/TranslationServiceProvider.php | 1 + 1 file changed, 1 insertion(+) diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index 8079f40521..dcf4a8d36f 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -23,6 +23,7 @@ namespace oat\tao\model\Translation\ServiceProvider; use oat\generis\model\DependencyInjection\ContainerServiceProviderInterface; +use oat\tao\model\Translation\Service\ResourceTranslationStatusService; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use function Symfony\Component\DependencyInjection\Loader\Configurator\inline_service; From 15769eb8fc77509eb7783aa1c9d7afcbb37ce260 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Wed, 4 Sep 2024 16:21:22 +0200 Subject: [PATCH 04/50] feat: adding ACL for new endpoints and handling request --- actions/class.Translation.php | 86 +++---------------- manifest.php | 1 + migrations/Version202409040743452141_tao.php | 45 ++++++++++ .../ResourceTranslationStatusService.php | 13 +++ 4 files changed, 71 insertions(+), 74 deletions(-) create mode 100644 migrations/Version202409040743452141_tao.php diff --git a/actions/class.Translation.php b/actions/class.Translation.php index 661698a6a7..b33c76bba1 100644 --- a/actions/class.Translation.php +++ b/actions/class.Translation.php @@ -15,93 +15,31 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Copyright (c) 2020-2021 (original work) Open Assessment Technologies SA; - * - * @author Sergei Mikhailov + * Copyright (c) 2024 (original work) Open Assessment Technologies SA; */ declare(strict_types=1); -use GuzzleHttp\Psr7\ServerRequest; -use oat\generis\model\OntologyAwareTrait; use oat\tao\model\http\HttpJsonResponseTrait; -use oat\tao\model\Lists\Business\Contract\DependsOnPropertyRepositoryInterface; -use oat\tao\model\Lists\Business\Service\ValueCollectionService; -use oat\tao\model\Lists\DataAccess\Repository\DependsOnPropertyRepository; -use oat\tao\model\Lists\DataAccess\Repository\DependentPropertiesRepository; -use oat\tao\model\Lists\Business\Domain\DependentPropertiesRepositoryContext; -use oat\tao\model\Lists\Presentation\Web\RequestHandler\ValueCollectionSearchRequestHandler; +use oat\tao\model\Translation\Service\ResourceTranslationStatusService; class tao_actions_Translation extends tao_actions_CommonModule { use HttpJsonResponseTrait; - use OntologyAwareTrait; - - public function status(): void - { - $this->setSuccessJsonResponse( - [ - '' - ] - ); - } - - public function getDependOnPropertyList(): void - { - $property = $this->hasGetParameter('property_uri') - ? $this->getProperty(tao_helpers_Uri::decode($this->getGetParameter('property_uri'))) - : null; - $class = $this->hasGetParameter('class_uri') - ? $this->getClass(tao_helpers_Uri::decode($this->getGetParameter('class_uri'))) - : null; - - $widgetUri = $this->hasGetParameter('type') - ? tao_helpers_form_GenerisFormFactory::getWidgetUriById($this->getGetParameter('type')) - : null; - - $this->setSuccessJsonResponse( - $this->getRepository()->findAll( - [ - DependsOnPropertyRepositoryInterface::FILTER_PROPERTY_WIDGET_URI => $widgetUri, - DependsOnPropertyRepositoryInterface::FILTER_PROPERTY => $property, - DependsOnPropertyRepositoryInterface::FILTER_CLASS => $class, - DependsOnPropertyRepositoryInterface::FILTER_LIST_URI => $this->getProperty( - tao_helpers_Uri::decode($this->getGetParameter('list_uri')) - )->getUri() - ] - ) - ); - } - - public function getDependentProperties(DependentPropertiesRepository $dependentPropertiesRepository): void + public function status(): void { - $property = $this->getProperty( - tao_helpers_Uri::decode( - $this->getGetParameter('propertyUri', '') - ) - ); - - $dependentProperties = $dependentPropertiesRepository->findAll( - new DependentPropertiesRepositoryContext([ - DependentPropertiesRepositoryContext::PARAM_PROPERTY => $property, - ]) - ); - - $this->setSuccessJsonResponse( - array_map( - static function (core_kernel_classes_Resource $property) { - return [ - 'label' => $property->getLabel(), - ]; - }, - $dependentProperties - ) - ); + try { + $this->setSuccessJsonResponse( + $this->getResourceTranslationStatusService()->getStatusByRequest($this->getPsrRequest()) + ); + } catch (Throwable $exception) { + $this->setErrorJsonResponse($exception->getMessage()); + } } - private function getRepository(): DependsOnPropertyRepositoryInterface + private function getResourceTranslationStatusService(): ResourceTranslationStatusService { - return $this->getPsrContainer()->get(DependsOnPropertyRepository::class); + return $this->getServiceManager()->getContainer()->get(ResourceTranslationStatusService::class); } } diff --git a/manifest.php b/manifest.php index 00d6625fe1..4d92c7f509 100755 --- a/manifest.php +++ b/manifest.php @@ -309,6 +309,7 @@ [AccessRule::GRANT, TaoRoles::BASE_USER, ['ext' => 'tao', 'mod' => 'File', 'act' => 'accessFile']], [AccessRule::GRANT, TaoRoles::BASE_USER, ['ext' => 'tao', 'mod' => 'Log', 'act' => 'log']], [AccessRule::GRANT, TaoRoles::BASE_USER, ['ext' => 'tao', 'mod' => 'TaskQueueWebApi']], + [AccessRule::GRANT, TaoRoles::BACK_OFFICE, ['ext' => 'tao', 'mod' => 'Translation']], [AccessRule::GRANT, TaoRoles::BACK_OFFICE, ['ext' => 'tao', 'mod' => 'Languages', 'act' => 'index']], [AccessRule::GRANT, TaoRoles::BACK_OFFICE, ['ext' => 'tao', 'mod' => 'ResourceRelations', 'act' => 'index']], [AccessRule::GRANT, TaoRoles::BACK_OFFICE, ['ext' => 'tao', 'mod' => 'File', 'act' => 'upload']], diff --git a/migrations/Version202409040743452141_tao.php b/migrations/Version202409040743452141_tao.php new file mode 100644 index 0000000000..806e2e8441 --- /dev/null +++ b/migrations/Version202409040743452141_tao.php @@ -0,0 +1,45 @@ +getRule()); + + $this->addReport(Report::createSuccess('Applied access for role ' . TaoRoles::BACK_OFFICE)); + } + + public function down(Schema $schema): void + { + AclProxy::revokeRule($this->getRule()); + } + + private function getRule(): AccessRule + { + return new AccessRule( + AccessRule::GRANT, + TaoRoles::BACK_OFFICE, + [ + 'ext' => 'tao', + 'mod' => 'Translation' + ] + ); + } +} diff --git a/models/classes/Translation/Service/ResourceTranslationStatusService.php b/models/classes/Translation/Service/ResourceTranslationStatusService.php index 3ba2d75ac6..44ebefa3a9 100644 --- a/models/classes/Translation/Service/ResourceTranslationStatusService.php +++ b/models/classes/Translation/Service/ResourceTranslationStatusService.php @@ -22,8 +22,10 @@ namespace oat\tao\model\Translation\Service; +use InvalidArgumentException; use oat\tao\model\Translation\Entity\ResourceTranslationStatus; use oat\tao\model\Translation\Query\ResourceTranslationStatusQuery; +use Psr\Http\Message\ServerRequestInterface; class ResourceTranslationStatusService { @@ -35,4 +37,15 @@ public function getStatus(ResourceTranslationStatusQuery $query): ResourceTransl { return new ResourceTranslationStatus(); } + + public function getStatusByRequest(ServerRequestInterface $request): ResourceTranslationStatus + { + $uri = $request->getQueryParams()['resourceUri'] ?? ($request->getServerParams()['resourceUri'] ?? null); + + if (empty($uri)) { + throw new InvalidArgumentException('Param resourceUri is required'); + } + + return $this->getStatus(new ResourceTranslationStatusQuery($uri)); + } } From e752f58c750e33c21b212dd400fd9f021a3d033d Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Wed, 4 Sep 2024 17:28:05 +0200 Subject: [PATCH 05/50] chore: add unit tests and prepare code to extract data based on resource metadata --- .../Entity/ResourceTranslationStatus.php | 18 ++++- .../ResourceTranslationStatusService.php | 8 ++- .../TranslationServiceProvider.php | 6 ++ .../Entity/ResourceTranslationStatusTest.php | 70 +++++++++++++++++++ .../ResourceTranslationStatusServiceTest.php | 60 ++++++++++++++++ 5 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 test/unit/models/classes/Translation/Entity/ResourceTranslationStatusTest.php create mode 100644 test/unit/models/classes/Translation/Service/ResourceTranslationStatusServiceTest.php diff --git a/models/classes/Translation/Entity/ResourceTranslationStatus.php b/models/classes/Translation/Entity/ResourceTranslationStatus.php index 657070313c..5f22b6eea2 100644 --- a/models/classes/Translation/Entity/ResourceTranslationStatus.php +++ b/models/classes/Translation/Entity/ResourceTranslationStatus.php @@ -26,16 +26,24 @@ class ResourceTranslationStatus implements JsonSerializable { + public const STATUS_PENDING = 'pending'; + public const STATUS_TRANSLATING = 'translating'; + public const STATUS_TRANSLATED = 'translated'; + private array $translations = []; + private string $originResourceUri; + - public function __construct() + public function __construct(string $originResourceUri) { + $this->originResourceUri = $originResourceUri; } public function addTranslation(string $locale, string $status, string $resourceUri): void { - $this->translations[$locale] = [ + $this->translations[] = [ 'status' => $status, + 'locale' => $locale, 'resourceUri' => $resourceUri ]; } @@ -45,9 +53,15 @@ public function getTranslations(): array return $this->translations; } + public function getOriginResourceUri(): string + { + return $this->originResourceUri; + } + public function jsonSerialize(): array { return [ + 'originResourceUri' => $this->originResourceUri, 'translations' => $this->translations ]; } diff --git a/models/classes/Translation/Service/ResourceTranslationStatusService.php b/models/classes/Translation/Service/ResourceTranslationStatusService.php index 44ebefa3a9..457a4f7a1a 100644 --- a/models/classes/Translation/Service/ResourceTranslationStatusService.php +++ b/models/classes/Translation/Service/ResourceTranslationStatusService.php @@ -23,19 +23,23 @@ namespace oat\tao\model\Translation\Service; use InvalidArgumentException; +use oat\generis\model\data\Ontology; use oat\tao\model\Translation\Entity\ResourceTranslationStatus; use oat\tao\model\Translation\Query\ResourceTranslationStatusQuery; use Psr\Http\Message\ServerRequestInterface; class ResourceTranslationStatusService { - public function __construct() + private Ontology $ontology; + + public function __construct(Ontology $ontology) { + $this->ontology = $ontology; } public function getStatus(ResourceTranslationStatusQuery $query): ResourceTranslationStatus { - return new ResourceTranslationStatus(); + return new ResourceTranslationStatus($query->getOriginResourceId()); } public function getStatusByRequest(ServerRequestInterface $request): ResourceTranslationStatus diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index dcf4a8d36f..4686a52759 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -22,6 +22,7 @@ namespace oat\tao\model\Translation\ServiceProvider; +use oat\generis\model\data\Ontology; use oat\generis\model\DependencyInjection\ContainerServiceProviderInterface; use oat\tao\model\Translation\Service\ResourceTranslationStatusService; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; @@ -38,6 +39,11 @@ public function __invoke(ContainerConfigurator $configurator): void { $services = $configurator->services(); $services->set(ResourceTranslationStatusService::class, ResourceTranslationStatusService::class) + ->args( + [ + service(Ontology::SERVICE_ID), + ] + ) ->public(); } } diff --git a/test/unit/models/classes/Translation/Entity/ResourceTranslationStatusTest.php b/test/unit/models/classes/Translation/Entity/ResourceTranslationStatusTest.php new file mode 100644 index 0000000000..298ce9b23e --- /dev/null +++ b/test/unit/models/classes/Translation/Entity/ResourceTranslationStatusTest.php @@ -0,0 +1,70 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Entity; + +use oat\tao\model\Translation\Entity\ResourceTranslationStatus; +use PHPUnit\Framework\TestCase; + +class ResourceTranslationStatusTest extends TestCase +{ + /** @var ResourceTranslationStatus */ + private $sut; + + public function setUp(): void + { + $this->sut = new ResourceTranslationStatus('myResourceUri'); + } + + public function testGetStatus(): void + { + $this->sut->addTranslation('en-US', ResourceTranslationStatus::STATUS_PENDING, 'uri1'); + $this->sut->addTranslation('fr-FR', ResourceTranslationStatus::STATUS_TRANSLATING, 'uri2'); + $this->sut->addTranslation('de-DE', ResourceTranslationStatus::STATUS_TRANSLATED, 'uri3'); + + $this->assertSame( + [ + 'originResourceUri' => 'myResourceUri', + 'translations' => [ + [ + 'status' => 'pending', + 'locale' => 'en-US', + 'resourceUri' => 'uri1', + ], + [ + 'status' => 'translating', + 'locale' => 'fr-FR', + 'resourceUri' => 'uri2' + ], + [ + 'status' => 'translated', + 'locale' => 'de-DE', + 'resourceUri' => 'uri3' + ] + ], + ], + $this->sut->jsonSerialize() + ); + } +} diff --git a/test/unit/models/classes/Translation/Service/ResourceTranslationStatusServiceTest.php b/test/unit/models/classes/Translation/Service/ResourceTranslationStatusServiceTest.php new file mode 100644 index 0000000000..3f4f8979e4 --- /dev/null +++ b/test/unit/models/classes/Translation/Service/ResourceTranslationStatusServiceTest.php @@ -0,0 +1,60 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Service; + +use oat\generis\model\data\Ontology; +use oat\tao\model\Translation\Query\ResourceTranslationStatusQuery; +use oat\tao\model\Translation\Service\ResourceTranslationStatusService; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class ResourceTranslationStatusServiceTest extends TestCase +{ + /** @var ResourceTranslationStatusService */ + private $sut; + + /** @var Ontology|MockObject */ + private $ontology; + + public function setUp(): void + { + $this->ontology = $this->createMock(Ontology::class); + + $this->sut = new ResourceTranslationStatusService($this->ontology); + } + + public function testGetStatus(): void + { + $status = $this->sut->getStatus(new ResourceTranslationStatusQuery('abc123')); + + $this->assertSame( + [ + 'originResourceUri' => 'abc123', + 'translations' => [], + ], + $status->jsonSerialize() + ); + } +} From 7fbbf13b319af3704588d2049041726405f5dd32 Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Thu, 5 Sep 2024 10:21:15 +0300 Subject: [PATCH 06/50] chore: add list of translation types --- migrations/Version202409040743452141_tao.php | 4 +++- models/ontology/tao.rdf | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/migrations/Version202409040743452141_tao.php b/migrations/Version202409040743452141_tao.php index 806e2e8441..d5e5de6283 100644 --- a/migrations/Version202409040743452141_tao.php +++ b/migrations/Version202409040743452141_tao.php @@ -21,8 +21,10 @@ public function getDescription(): string public function up(Schema $schema): void { - AclProxy::applyRule($this->getRule()); + OntologyUpdater::syncModels(); + $this->addReport(Report::createSuccess('Ontology models successfully synchronized')); + AclProxy::applyRule($this->getRule()); $this->addReport(Report::createSuccess('Applied access for role ' . TaoRoles::BACK_OFFICE)); } diff --git a/models/ontology/tao.rdf b/models/ontology/tao.rdf index 912b1cba41..77d4c3e5e5 100644 --- a/models/ontology/tao.rdf +++ b/models/ontology/tao.rdf @@ -340,4 +340,19 @@ + + + + + + + + + + + + + + + From f9a2eca87b069a2631f976f547e0224181bf3d58 Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Thu, 5 Sep 2024 12:15:45 +0300 Subject: [PATCH 07/50] chore: move props to tao-core --- models/ontology/tao.rdf | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/models/ontology/tao.rdf b/models/ontology/tao.rdf index 77d4c3e5e5..e177a09dc0 100644 --- a/models/ontology/tao.rdf +++ b/models/ontology/tao.rdf @@ -355,4 +355,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 6e1dc20e7a765fab2fcb8e86828d4543ca99ef85 Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Thu, 5 Sep 2024 15:14:29 +0300 Subject: [PATCH 08/50] chore: change property values ID --- models/ontology/tao.rdf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/ontology/tao.rdf b/models/ontology/tao.rdf index e177a09dc0..149e661f7a 100644 --- a/models/ontology/tao.rdf +++ b/models/ontology/tao.rdf @@ -345,12 +345,12 @@ - + - + From 75ec984ad14690ba6519e9ac3010e05dd1c5c601 Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Thu, 5 Sep 2024 15:15:38 +0300 Subject: [PATCH 09/50] chore: rename property --- models/ontology/tao.rdf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/models/ontology/tao.rdf b/models/ontology/tao.rdf index 149e661f7a..25956ca113 100644 --- a/models/ontology/tao.rdf +++ b/models/ontology/tao.rdf @@ -356,11 +356,11 @@ - + - - + + From 01d50c270bea22faadd6bbc96193c763564b959e Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Thu, 5 Sep 2024 15:59:45 +0300 Subject: [PATCH 10/50] chore: move domains to their extensions --- models/ontology/tao.rdf | 59 ++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/models/ontology/tao.rdf b/models/ontology/tao.rdf index 25956ca113..43faf8a5ff 100644 --- a/models/ontology/tao.rdf +++ b/models/ontology/tao.rdf @@ -356,9 +356,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -366,7 +402,6 @@ - @@ -375,20 +410,26 @@ - - + - - - - - + + + + + + + + + + + + From 12761141c6e46f1be5876d8645deb91a182fd14c Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 5 Sep 2024 15:36:10 +0200 Subject: [PATCH 11/50] chore: document translation process metadata --- models/ontology/tao.rdf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/models/ontology/tao.rdf b/models/ontology/tao.rdf index 43faf8a5ff..955a63d7d7 100644 --- a/models/ontology/tao.rdf +++ b/models/ontology/tao.rdf @@ -340,6 +340,12 @@ + From 086cc22eb81b7fd482f347b2441ddd9ed11ba6d1 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 5 Sep 2024 16:19:19 +0200 Subject: [PATCH 12/50] chore: document translation metadata --- .../Entity/ResourceTranslation.php | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 models/classes/Translation/Entity/ResourceTranslation.php diff --git a/models/classes/Translation/Entity/ResourceTranslation.php b/models/classes/Translation/Entity/ResourceTranslation.php new file mode 100644 index 0000000000..e7439900e0 --- /dev/null +++ b/models/classes/Translation/Entity/ResourceTranslation.php @@ -0,0 +1,42 @@ + Date: Thu, 5 Sep 2024 17:40:24 +0200 Subject: [PATCH 13/50] feat: add all translation status in response based on metadata --- .../Entity/ResourceTranslation.php | 10 +++ .../Entity/ResourceTranslationStatus.php | 4 -- .../ResourceTranslationStatusService.php | 64 ++++++++++++++++++- .../TranslationServiceProvider.php | 2 + 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/models/classes/Translation/Entity/ResourceTranslation.php b/models/classes/Translation/Entity/ResourceTranslation.php index e7439900e0..1f1a884f68 100644 --- a/models/classes/Translation/Entity/ResourceTranslation.php +++ b/models/classes/Translation/Entity/ResourceTranslation.php @@ -39,4 +39,14 @@ interface ResourceTranslation public const PROPERTY_UNIQUE_IDENTIFIER = 'http://www.tao.lu/Ontologies/TAO.rdf#UniqueIdentifier'; public const PROPERTY_LANGUAGE = 'http://www.tao.lu/Ontologies/TAO.rdf#Language'; + + public const PROGRESS_PENDING = 'pending'; + public const PROGRESS_TRANSLATING = 'translating'; + public const PROGRESS_TRANSLATED = 'translated'; + + public const PROGRESS_MAPPING = [ + self::PROPERTY_VALUE_TRANSLATION_PROGRESS_PENDING => self::PROGRESS_PENDING, + self::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATING => self::PROGRESS_TRANSLATING, + self::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED => self::PROGRESS_TRANSLATED, + ]; } diff --git a/models/classes/Translation/Entity/ResourceTranslationStatus.php b/models/classes/Translation/Entity/ResourceTranslationStatus.php index 5f22b6eea2..daa80711fc 100644 --- a/models/classes/Translation/Entity/ResourceTranslationStatus.php +++ b/models/classes/Translation/Entity/ResourceTranslationStatus.php @@ -26,10 +26,6 @@ class ResourceTranslationStatus implements JsonSerializable { - public const STATUS_PENDING = 'pending'; - public const STATUS_TRANSLATING = 'translating'; - public const STATUS_TRANSLATED = 'translated'; - private array $translations = []; private string $originResourceUri; diff --git a/models/classes/Translation/Service/ResourceTranslationStatusService.php b/models/classes/Translation/Service/ResourceTranslationStatusService.php index 457a4f7a1a..f183aadc1a 100644 --- a/models/classes/Translation/Service/ResourceTranslationStatusService.php +++ b/models/classes/Translation/Service/ResourceTranslationStatusService.php @@ -22,8 +22,13 @@ namespace oat\tao\model\Translation\Service; +use core_kernel_classes_Resource; +use Exception; use InvalidArgumentException; use oat\generis\model\data\Ontology; +use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; +use oat\search\helper\SupportedOperatorHelper; +use oat\tao\model\Translation\Entity\ResourceTranslation; use oat\tao\model\Translation\Entity\ResourceTranslationStatus; use oat\tao\model\Translation\Query\ResourceTranslationStatusQuery; use Psr\Http\Message\ServerRequestInterface; @@ -31,15 +36,70 @@ class ResourceTranslationStatusService { private Ontology $ontology; + private ComplexSearchService $complexSearch; - public function __construct(Ontology $ontology) + public function __construct(Ontology $ontology, ComplexSearchService $complexSearch) { $this->ontology = $ontology; + $this->complexSearch = $complexSearch; } public function getStatus(ResourceTranslationStatusQuery $query): ResourceTranslationStatus { - return new ResourceTranslationStatus($query->getOriginResourceId()); + $originResourceId = $query->getOriginResourceId(); + $output = new ResourceTranslationStatus($originResourceId); + $resource = $this->ontology->getResource($originResourceId); + + if (!$resource->exists()) { + throw new Exception(sprintf('Resource %s does not exist', $originResourceId)); + } + + $uniqueId = $resource->getUniquePropertyValue( + $this->ontology->getProperty(ResourceTranslation::PROPERTY_UNIQUE_IDENTIFIER) + ); + + $queryBuilder = $this->complexSearch->query(); + $query = $this->complexSearch->searchType( + $queryBuilder, + 'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject', + true + ); + $query->addCriterion( + ResourceTranslation::PROPERTY_TRANSLATION_TYPE, + SupportedOperatorHelper::EQUAL, + ResourceTranslation::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION + ); + $query->addCriterion( + ResourceTranslation::PROPERTY_UNIQUE_IDENTIFIER, + SupportedOperatorHelper::EQUAL, + $uniqueId + + ); + $queryBuilder->setCriteria($query); + + $result = $this->complexSearch->getGateway()->search($queryBuilder); + + $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); + $progressProperty = $this->ontology->getProperty(ResourceTranslation::PROPERTY_TRANSLATION_PROGRESS); + $languageProperty = $this->ontology->getProperty(ResourceTranslation::PROPERTY_LANGUAGE); + + /** @var core_kernel_classes_Resource $resource */ + foreach ($result as $resource) { + /** @var core_kernel_classes_Resource $language */ + $language = $resource->getUniquePropertyValue($languageProperty); + $languageCode = $language->getUniquePropertyValue($valueProperty); + + /** @var core_kernel_classes_Resource $progress */ + $progress = $resource->getUniquePropertyValue($progressProperty); + + $output->addTranslation( + (string)$languageCode, + ResourceTranslation::PROGRESS_MAPPING[$progress->getUri()], + $resource->getUri() + ); + } + + return $output; } public function getStatusByRequest(ServerRequestInterface $request): ResourceTranslationStatus diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index 4686a52759..c6f35eeaff 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -24,6 +24,7 @@ use oat\generis\model\data\Ontology; use oat\generis\model\DependencyInjection\ContainerServiceProviderInterface; +use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; use oat\tao\model\Translation\Service\ResourceTranslationStatusService; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; @@ -42,6 +43,7 @@ public function __invoke(ContainerConfigurator $configurator): void ->args( [ service(Ontology::SERVICE_ID), + service(ComplexSearchService::SERVICE_ID), ] ) ->public(); From 5820d20b280a3f5440b6abd31d2f3ae84cdc912f Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Fri, 6 Sep 2024 11:47:34 +0200 Subject: [PATCH 14/50] chore: move classes to proper namespaces --- actions/class.Translation.php | 10 +- .../Entity/ResourceTranslation.php | 78 ++++++++++- ....php => ResourceTranslationCollection.php} | 14 +- .../ResourceTranslationException.php | 29 ++++ .../Factory/ResourceTranslationFactory.php | 63 +++++++++ ...Query.php => ResourceTranslationQuery.php} | 13 +- .../ResourceTranslationRepository.php | 128 ++++++++++++++++++ .../Service/ResourceTranslationRetriever.php | 52 +++++++ .../ResourceTranslationStatusService.php | 115 ---------------- .../TranslationServiceProvider.php | 23 +++- .../Entity/ResourceTranslationStatusTest.php | 12 +- .../ResourceTranslationStatusServiceTest.php | 10 +- 12 files changed, 400 insertions(+), 147 deletions(-) rename models/classes/Translation/Entity/{ResourceTranslationStatus.php => ResourceTranslationCollection.php} (76%) create mode 100644 models/classes/Translation/Exception/ResourceTranslationException.php create mode 100644 models/classes/Translation/Factory/ResourceTranslationFactory.php rename models/classes/Translation/Query/{ResourceTranslationStatusQuery.php => ResourceTranslationQuery.php} (78%) create mode 100644 models/classes/Translation/Repository/ResourceTranslationRepository.php create mode 100644 models/classes/Translation/Service/ResourceTranslationRetriever.php delete mode 100644 models/classes/Translation/Service/ResourceTranslationStatusService.php diff --git a/actions/class.Translation.php b/actions/class.Translation.php index b33c76bba1..37a78aada1 100644 --- a/actions/class.Translation.php +++ b/actions/class.Translation.php @@ -21,25 +21,25 @@ declare(strict_types=1); use oat\tao\model\http\HttpJsonResponseTrait; -use oat\tao\model\Translation\Service\ResourceTranslationStatusService; +use oat\tao\model\Translation\Service\ResourceTranslationRetriever; class tao_actions_Translation extends tao_actions_CommonModule { use HttpJsonResponseTrait; - public function status(): void + public function translations(): void { try { $this->setSuccessJsonResponse( - $this->getResourceTranslationStatusService()->getStatusByRequest($this->getPsrRequest()) + $this->getResourceTranslationRetriever()->getByRequest($this->getPsrRequest()) ); } catch (Throwable $exception) { $this->setErrorJsonResponse($exception->getMessage()); } } - private function getResourceTranslationStatusService(): ResourceTranslationStatusService + private function getResourceTranslationRetriever(): ResourceTranslationRetriever { - return $this->getServiceManager()->getContainer()->get(ResourceTranslationStatusService::class); + return $this->getServiceManager()->getContainer()->get(ResourceTranslationRetriever::class); } } diff --git a/models/classes/Translation/Entity/ResourceTranslation.php b/models/classes/Translation/Entity/ResourceTranslation.php index 1f1a884f68..40aa62b2f2 100644 --- a/models/classes/Translation/Entity/ResourceTranslation.php +++ b/models/classes/Translation/Entity/ResourceTranslation.php @@ -22,7 +22,9 @@ namespace oat\tao\model\Translation\Entity; -interface ResourceTranslation +use JsonSerializable; + +class ResourceTranslation implements JsonSerializable { public const PROPERTY_TRANSLATION_TYPE = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationType'; public const PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationTypeOriginal'; @@ -49,4 +51,78 @@ interface ResourceTranslation self::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATING => self::PROGRESS_TRANSLATING, self::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED => self::PROGRESS_TRANSLATED, ]; + + private string $originResourceUri; + private string $resourceUri; + private string $resourceLabel; + private string $progress; + private string $progressUri; + private string $languageCode; + private string $languageUri; + + public function __construct( + string $originResourceUri, + string $resourceUri, + string $resourceLabel, + string $progress, + string $progressUri, + string $languageCode, + string $languageUri + ) { + $this->originResourceUri = $originResourceUri; + $this->resourceUri = $resourceUri; + $this->resourceLabel = $resourceLabel; + $this->progress = $progress; + $this->progressUri = $progressUri; + $this->languageCode = $languageCode; + $this->languageUri = $languageUri; + } + + public function getOriginResourceUri(): string + { + return $this->originResourceUri; + } + + public function getResourceUri(): string + { + return $this->resourceUri; + } + + public function getResourceLabel(): string + { + return $this->resourceLabel; + } + + public function getProgress(): string + { + return $this->progress; + } + + public function getProgressUri(): string + { + return $this->progressUri; + } + + public function getLanguageCode(): string + { + return $this->languageCode; + } + + public function getLanguageUri(): string + { + return $this->languageUri; + } + + public function jsonSerialize(): array + { + return [ + 'originResourceUri' => $this->getOriginResourceUri(), + 'resourceUri' => $this->getResourceUri(), + 'resourceLabel' => $this->getResourceLabel(), + 'languageCode' => $this->getLanguageCode(), + 'languageUri' => $this->getLanguageUri(), + 'progress' => $this->getProgress(), + 'progressUri' => $this->getProgressUri(), + ]; + } } diff --git a/models/classes/Translation/Entity/ResourceTranslationStatus.php b/models/classes/Translation/Entity/ResourceTranslationCollection.php similarity index 76% rename from models/classes/Translation/Entity/ResourceTranslationStatus.php rename to models/classes/Translation/Entity/ResourceTranslationCollection.php index daa80711fc..7bfc3c9a30 100644 --- a/models/classes/Translation/Entity/ResourceTranslationStatus.php +++ b/models/classes/Translation/Entity/ResourceTranslationCollection.php @@ -24,7 +24,7 @@ use JsonSerializable; -class ResourceTranslationStatus implements JsonSerializable +class ResourceTranslationCollection implements JsonSerializable { private array $translations = []; private string $originResourceUri; @@ -35,13 +35,9 @@ public function __construct(string $originResourceUri) $this->originResourceUri = $originResourceUri; } - public function addTranslation(string $locale, string $status, string $resourceUri): void + public function addTranslation(ResourceTranslation $resourceTranslation): void { - $this->translations[] = [ - 'status' => $status, - 'locale' => $locale, - 'resourceUri' => $resourceUri - ]; + $this->translations[] = $resourceTranslation; } public function getTranslations(): array @@ -57,8 +53,8 @@ public function getOriginResourceUri(): string public function jsonSerialize(): array { return [ - 'originResourceUri' => $this->originResourceUri, - 'translations' => $this->translations + 'originResourceUri' => $this->getOriginResourceUri(), + 'translations' => $this->getTranslations() ]; } } diff --git a/models/classes/Translation/Exception/ResourceTranslationException.php b/models/classes/Translation/Exception/ResourceTranslationException.php new file mode 100644 index 0000000000..4dd7935c6d --- /dev/null +++ b/models/classes/Translation/Exception/ResourceTranslationException.php @@ -0,0 +1,29 @@ +ontology = $ontology; + } + + public function create( + core_kernel_classes_Resource $originResource, + core_kernel_classes_Resource $translationResource, + ): ResourceTranslation { + $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); + $progressProperty = $this->ontology->getProperty(ResourceTranslation::PROPERTY_TRANSLATION_PROGRESS); + $languageProperty = $this->ontology->getProperty(ResourceTranslation::PROPERTY_LANGUAGE); + + /** @var core_kernel_classes_Resource $language */ + $language = $translationResource->getUniquePropertyValue($languageProperty); + $languageCode = $language->getUniquePropertyValue($valueProperty); + + /** @var core_kernel_classes_Resource $progress */ + $progress = $translationResource->getUniquePropertyValue($progressProperty); + + return new ResourceTranslation( + $originResource->getUri(), + $translationResource->getUri(), + $translationResource->getLabel(), + ResourceTranslation::PROGRESS_MAPPING[$progress->getUri()], + $progress->getUri(), + (string)$languageCode, + $language->getUri() + ); + } +} diff --git a/models/classes/Translation/Query/ResourceTranslationStatusQuery.php b/models/classes/Translation/Query/ResourceTranslationQuery.php similarity index 78% rename from models/classes/Translation/Query/ResourceTranslationStatusQuery.php rename to models/classes/Translation/Query/ResourceTranslationQuery.php index de3db491ac..c1f53c1fad 100644 --- a/models/classes/Translation/Query/ResourceTranslationStatusQuery.php +++ b/models/classes/Translation/Query/ResourceTranslationQuery.php @@ -22,19 +22,24 @@ namespace oat\tao\model\Translation\Query; -use JsonSerializable; - -class ResourceTranslationStatusQuery +class ResourceTranslationQuery { private string $originResourceId; + private ?string $languageUri; - public function __construct(string $originResourceId) + public function __construct(string $originResourceId, string $languageUri = null) { $this->originResourceId = $originResourceId; + $this->languageUri = $languageUri; } public function getOriginResourceId(): string { return $this->originResourceId; } + + public function getLanguageUri(): ?string + { + return $this->languageUri; + } } diff --git a/models/classes/Translation/Repository/ResourceTranslationRepository.php b/models/classes/Translation/Repository/ResourceTranslationRepository.php new file mode 100644 index 0000000000..e5d30c9c23 --- /dev/null +++ b/models/classes/Translation/Repository/ResourceTranslationRepository.php @@ -0,0 +1,128 @@ +ontology = $ontology; + $this->complexSearch = $complexSearch; + $this->factory = $resourceTranslationFactory; + $this->logger = $logger; + } + + public function find(ResourceTranslationQuery $query): ResourceTranslationCollection + { + $originResourceId = $query->getOriginResourceId(); + $originResource = $this->ontology->getResource($originResourceId); + + if (!$originResource->exists()) { + throw new Exception(sprintf('Translation Origin Resource %s does not exist', $originResourceId)); + } + + /** @var core_kernel_classes_Resource $translationType */ + $translationType = $originResource->getUniquePropertyValue($this->ontology->getProperty(ResourceTranslation::PROPERTY_TRANSLATION_TYPE)); + + if ($translationType->getUri() !== ResourceTranslation::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL) { + throw new ResourceTranslationException( + sprintf('Translation Origin Resource %s it not the original', $originResourceId) + ); + } + + $output = new ResourceTranslationCollection($originResourceId); + $uniqueId = $originResource->getUniquePropertyValue( + $this->ontology->getProperty(ResourceTranslation::PROPERTY_UNIQUE_IDENTIFIER) + ); + + $queryBuilder = $this->complexSearch->query(); + $searchQuery = $this->complexSearch->searchType( + $queryBuilder, + 'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject', + true + ); + $searchQuery->addCriterion( + ResourceTranslation::PROPERTY_TRANSLATION_TYPE, + SupportedOperatorHelper::EQUAL, + ResourceTranslation::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION + ); + $searchQuery->addCriterion( + ResourceTranslation::PROPERTY_UNIQUE_IDENTIFIER, + SupportedOperatorHelper::EQUAL, + $uniqueId + ); + + if ($query->getLanguageUri()) { + $searchQuery->addCriterion( + ResourceTranslation::PROPERTY_LANGUAGE, + SupportedOperatorHelper::EQUAL, + $query->getLanguageUri() + ); + } + + $queryBuilder->setCriteria($searchQuery); + + $result = $this->complexSearch->getGateway()->search($queryBuilder); + + /** @var core_kernel_classes_Resource $resource */ + foreach ($result as $translationResource) { + try { + $output->addTranslation($this->factory->create($originResource, $translationResource)); + } catch (Throwable $exception) { + $this->logger->warning( + sprintf( + 'Cannot read translation status for [originResourceId=%s, translationResourceId=%s]: %s - %s', + $originResourceId, + $resource->getUri(), + $exception->getMessage(), + $exception->getTraceAsString() + ) + ); + } + } + + return $output; + } +} diff --git a/models/classes/Translation/Service/ResourceTranslationRetriever.php b/models/classes/Translation/Service/ResourceTranslationRetriever.php new file mode 100644 index 0000000000..7f59dd2a2a --- /dev/null +++ b/models/classes/Translation/Service/ResourceTranslationRetriever.php @@ -0,0 +1,52 @@ +resourceTranslationRepository = $resourceTranslationRepository; + } + + public function getByRequest(ServerRequestInterface $request): ResourceTranslationCollection + { + $queryParams = $request->getQueryParams(); + $resourceUri = $queryParams['resourceUri'] ?? null; + $languageUri = $queryParams['languageUri'] ?? null; + + if (empty($resourceUri)) { + throw new InvalidArgumentException('Param resourceUri is required'); + } + + return $this->resourceTranslationRepository->find(new ResourceTranslationQuery($resourceUri, $languageUri)); + } +} diff --git a/models/classes/Translation/Service/ResourceTranslationStatusService.php b/models/classes/Translation/Service/ResourceTranslationStatusService.php deleted file mode 100644 index f183aadc1a..0000000000 --- a/models/classes/Translation/Service/ResourceTranslationStatusService.php +++ /dev/null @@ -1,115 +0,0 @@ -ontology = $ontology; - $this->complexSearch = $complexSearch; - } - - public function getStatus(ResourceTranslationStatusQuery $query): ResourceTranslationStatus - { - $originResourceId = $query->getOriginResourceId(); - $output = new ResourceTranslationStatus($originResourceId); - $resource = $this->ontology->getResource($originResourceId); - - if (!$resource->exists()) { - throw new Exception(sprintf('Resource %s does not exist', $originResourceId)); - } - - $uniqueId = $resource->getUniquePropertyValue( - $this->ontology->getProperty(ResourceTranslation::PROPERTY_UNIQUE_IDENTIFIER) - ); - - $queryBuilder = $this->complexSearch->query(); - $query = $this->complexSearch->searchType( - $queryBuilder, - 'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject', - true - ); - $query->addCriterion( - ResourceTranslation::PROPERTY_TRANSLATION_TYPE, - SupportedOperatorHelper::EQUAL, - ResourceTranslation::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION - ); - $query->addCriterion( - ResourceTranslation::PROPERTY_UNIQUE_IDENTIFIER, - SupportedOperatorHelper::EQUAL, - $uniqueId - - ); - $queryBuilder->setCriteria($query); - - $result = $this->complexSearch->getGateway()->search($queryBuilder); - - $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); - $progressProperty = $this->ontology->getProperty(ResourceTranslation::PROPERTY_TRANSLATION_PROGRESS); - $languageProperty = $this->ontology->getProperty(ResourceTranslation::PROPERTY_LANGUAGE); - - /** @var core_kernel_classes_Resource $resource */ - foreach ($result as $resource) { - /** @var core_kernel_classes_Resource $language */ - $language = $resource->getUniquePropertyValue($languageProperty); - $languageCode = $language->getUniquePropertyValue($valueProperty); - - /** @var core_kernel_classes_Resource $progress */ - $progress = $resource->getUniquePropertyValue($progressProperty); - - $output->addTranslation( - (string)$languageCode, - ResourceTranslation::PROGRESS_MAPPING[$progress->getUri()], - $resource->getUri() - ); - } - - return $output; - } - - public function getStatusByRequest(ServerRequestInterface $request): ResourceTranslationStatus - { - $uri = $request->getQueryParams()['resourceUri'] ?? ($request->getServerParams()['resourceUri'] ?? null); - - if (empty($uri)) { - throw new InvalidArgumentException('Param resourceUri is required'); - } - - return $this->getStatus(new ResourceTranslationStatusQuery($uri)); - } -} diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index c6f35eeaff..dc275e61ca 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -25,7 +25,10 @@ use oat\generis\model\data\Ontology; use oat\generis\model\DependencyInjection\ContainerServiceProviderInterface; use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; -use oat\tao\model\Translation\Service\ResourceTranslationStatusService; +use oat\oatbox\log\LoggerService; +use oat\tao\model\Translation\Factory\ResourceTranslationFactory; +use oat\tao\model\Translation\Repository\ResourceTranslationRepository; +use oat\tao\model\Translation\Service\ResourceTranslationRetriever; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use function Symfony\Component\DependencyInjection\Loader\Configurator\inline_service; @@ -39,11 +42,27 @@ class TranslationServiceProvider implements ContainerServiceProviderInterface public function __invoke(ContainerConfigurator $configurator): void { $services = $configurator->services(); - $services->set(ResourceTranslationStatusService::class, ResourceTranslationStatusService::class) + $services->set(ResourceTranslationRepository::class, ResourceTranslationRepository::class) ->args( [ service(Ontology::SERVICE_ID), service(ComplexSearchService::SERVICE_ID), + service(ResourceTranslationFactory::class), + service(LoggerService::SERVICE_ID), + ] + ); + + $services->set(ResourceTranslationFactory::class, ResourceTranslationFactory::class) + ->args( + [ + service(Ontology::SERVICE_ID) + ] + ); + + $services->set(ResourceTranslationRetriever::class, ResourceTranslationRetriever::class) + ->args( + [ + service(ResourceTranslationRepository::class) ] ) ->public(); diff --git a/test/unit/models/classes/Translation/Entity/ResourceTranslationStatusTest.php b/test/unit/models/classes/Translation/Entity/ResourceTranslationStatusTest.php index 298ce9b23e..f974efaf0f 100644 --- a/test/unit/models/classes/Translation/Entity/ResourceTranslationStatusTest.php +++ b/test/unit/models/classes/Translation/Entity/ResourceTranslationStatusTest.php @@ -24,24 +24,24 @@ namespace oat\tao\test\unit\model\Translation\Entity; -use oat\tao\model\Translation\Entity\ResourceTranslationStatus; +use oat\tao\model\Translation\Entity\ResourceTranslation; use PHPUnit\Framework\TestCase; class ResourceTranslationStatusTest extends TestCase { - /** @var ResourceTranslationStatus */ + /** @var ResourceTranslation */ private $sut; public function setUp(): void { - $this->sut = new ResourceTranslationStatus('myResourceUri'); + $this->sut = new ResourceTranslation('myResourceUri'); } public function testGetStatus(): void { - $this->sut->addTranslation('en-US', ResourceTranslationStatus::STATUS_PENDING, 'uri1'); - $this->sut->addTranslation('fr-FR', ResourceTranslationStatus::STATUS_TRANSLATING, 'uri2'); - $this->sut->addTranslation('de-DE', ResourceTranslationStatus::STATUS_TRANSLATED, 'uri3'); + $this->sut->addTranslation('en-US', ResourceTranslation::STATUS_PENDING, 'uri1'); + $this->sut->addTranslation('fr-FR', ResourceTranslation::STATUS_TRANSLATING, 'uri2'); + $this->sut->addTranslation('de-DE', ResourceTranslation::STATUS_TRANSLATED, 'uri3'); $this->assertSame( [ diff --git a/test/unit/models/classes/Translation/Service/ResourceTranslationStatusServiceTest.php b/test/unit/models/classes/Translation/Service/ResourceTranslationStatusServiceTest.php index 3f4f8979e4..2ead75189e 100644 --- a/test/unit/models/classes/Translation/Service/ResourceTranslationStatusServiceTest.php +++ b/test/unit/models/classes/Translation/Service/ResourceTranslationStatusServiceTest.php @@ -25,14 +25,14 @@ namespace oat\tao\test\unit\model\Translation\Service; use oat\generis\model\data\Ontology; -use oat\tao\model\Translation\Query\ResourceTranslationStatusQuery; -use oat\tao\model\Translation\Service\ResourceTranslationStatusService; +use oat\tao\model\Translation\Query\ResourceTranslationQuery; +use oat\tao\model\Translation\Service\ResourceTranslationRepository; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class ResourceTranslationStatusServiceTest extends TestCase { - /** @var ResourceTranslationStatusService */ + /** @var ResourceTranslationRepository */ private $sut; /** @var Ontology|MockObject */ @@ -42,12 +42,12 @@ public function setUp(): void { $this->ontology = $this->createMock(Ontology::class); - $this->sut = new ResourceTranslationStatusService($this->ontology); + $this->sut = new ResourceTranslationRepository($this->ontology); } public function testGetStatus(): void { - $status = $this->sut->getStatus(new ResourceTranslationStatusQuery('abc123')); + $status = $this->sut->find(new ResourceTranslationQuery('abc123')); $this->assertSame( [ From 17388706b85cf8850d2f893f5b552c41400739e2 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Fri, 6 Sep 2024 12:00:09 +0200 Subject: [PATCH 15/50] chore: move constants to ontology --- models/classes/TaoOntology.php | 16 +++++++++++++ .../Entity/ResourceTranslation.php | 23 ++++--------------- .../Factory/ResourceTranslationFactory.php | 5 ++-- .../ResourceTranslationRepository.php | 15 ++++++------ 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/models/classes/TaoOntology.php b/models/classes/TaoOntology.php index a25702de43..5f420cb0da 100644 --- a/models/classes/TaoOntology.php +++ b/models/classes/TaoOntology.php @@ -117,4 +117,20 @@ interface TaoOntology public const PROPERTY_STANCE_LANGUAGE_USAGE_DATA = 'http://www.tao.lu/Ontologies/TAO.rdf#LanguageUsageData'; /** @deprecated use tao_models_classes_LanguageService::CLASS_URI_LANGUAGES */ public const LANGUAGES_CLASS_URI = 'http://www.tao.lu/Ontologies/TAO.rdf#Languages'; + + public const PROPERTY_TRANSLATION_TYPE = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationType'; + public const PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationTypeOriginal'; + public const PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationTypeTranslation'; + + public const PROPERTY_TRANSLATION_PROGRESS = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgress'; + public const PROPERTY_VALUE_TRANSLATION_PROGRESS_PENDING = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgressStatusPending'; + public const PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATING = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgressStatusTranslating'; + public const PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgressStatusTranslated'; + + public const PROPERTY_TRANSLATION_STATUS = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationStatus'; + public const PROPERTY_VALUE_TRANSLATION_STATUS_READY = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationStatusReadyForTranslation'; + public const PROPERTY_VALUE_TRANSLATION_STATUS_NOT_READY = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationStatusNotReadyForTranslation'; + + public const PROPERTY_UNIQUE_IDENTIFIER = 'http://www.tao.lu/Ontologies/TAO.rdf#UniqueIdentifier'; + public const PROPERTY_LANGUAGE = 'http://www.tao.lu/Ontologies/TAO.rdf#Language'; } diff --git a/models/classes/Translation/Entity/ResourceTranslation.php b/models/classes/Translation/Entity/ResourceTranslation.php index 40aa62b2f2..b1a1b021f2 100644 --- a/models/classes/Translation/Entity/ResourceTranslation.php +++ b/models/classes/Translation/Entity/ResourceTranslation.php @@ -23,33 +23,18 @@ namespace oat\tao\model\Translation\Entity; use JsonSerializable; +use oat\tao\model\TaoOntology; class ResourceTranslation implements JsonSerializable { - public const PROPERTY_TRANSLATION_TYPE = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationType'; - public const PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationTypeOriginal'; - public const PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationTypeTranslation'; - - public const PROPERTY_TRANSLATION_PROGRESS = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgress'; - public const PROPERTY_VALUE_TRANSLATION_PROGRESS_PENDING = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgressStatusPending'; - public const PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATING = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgressStatusTranslating'; - public const PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgressStatusTranslated'; - - public const PROPERTY_TRANSLATION_STATUS = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationStatus'; - public const PROPERTY_VALUE_TRANSLATION_STATUS_READY = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationStatusReadyForTranslation'; - public const PROPERTY_VALUE_TRANSLATION_STATUS_NOT_READY = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationStatusNotReadyForTranslation'; - - public const PROPERTY_UNIQUE_IDENTIFIER = 'http://www.tao.lu/Ontologies/TAO.rdf#UniqueIdentifier'; - public const PROPERTY_LANGUAGE = 'http://www.tao.lu/Ontologies/TAO.rdf#Language'; - public const PROGRESS_PENDING = 'pending'; public const PROGRESS_TRANSLATING = 'translating'; public const PROGRESS_TRANSLATED = 'translated'; public const PROGRESS_MAPPING = [ - self::PROPERTY_VALUE_TRANSLATION_PROGRESS_PENDING => self::PROGRESS_PENDING, - self::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATING => self::PROGRESS_TRANSLATING, - self::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED => self::PROGRESS_TRANSLATED, + TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_PENDING => self::PROGRESS_PENDING, + TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATING => self::PROGRESS_TRANSLATING, + TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED => self::PROGRESS_TRANSLATED, ]; private string $originResourceUri; diff --git a/models/classes/Translation/Factory/ResourceTranslationFactory.php b/models/classes/Translation/Factory/ResourceTranslationFactory.php index a238a6b9be..231908c20f 100644 --- a/models/classes/Translation/Factory/ResourceTranslationFactory.php +++ b/models/classes/Translation/Factory/ResourceTranslationFactory.php @@ -24,6 +24,7 @@ use core_kernel_classes_Resource; use oat\generis\model\data\Ontology; +use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceTranslation; class ResourceTranslationFactory @@ -40,8 +41,8 @@ public function create( core_kernel_classes_Resource $translationResource, ): ResourceTranslation { $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); - $progressProperty = $this->ontology->getProperty(ResourceTranslation::PROPERTY_TRANSLATION_PROGRESS); - $languageProperty = $this->ontology->getProperty(ResourceTranslation::PROPERTY_LANGUAGE); + $progressProperty = $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_PROGRESS); + $languageProperty = $this->ontology->getProperty(TaoOntology::PROPERTY_LANGUAGE); /** @var core_kernel_classes_Resource $language */ $language = $translationResource->getUniquePropertyValue($languageProperty); diff --git a/models/classes/Translation/Repository/ResourceTranslationRepository.php b/models/classes/Translation/Repository/ResourceTranslationRepository.php index e5d30c9c23..777c4b5c2d 100644 --- a/models/classes/Translation/Repository/ResourceTranslationRepository.php +++ b/models/classes/Translation/Repository/ResourceTranslationRepository.php @@ -27,6 +27,7 @@ use oat\generis\model\data\Ontology; use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; use oat\search\helper\SupportedOperatorHelper; +use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceTranslation; use oat\tao\model\Translation\Entity\ResourceTranslationCollection; use oat\tao\model\Translation\Entity\ResourceTranslationException; @@ -64,9 +65,9 @@ public function find(ResourceTranslationQuery $query): ResourceTranslationCollec } /** @var core_kernel_classes_Resource $translationType */ - $translationType = $originResource->getUniquePropertyValue($this->ontology->getProperty(ResourceTranslation::PROPERTY_TRANSLATION_TYPE)); + $translationType = $originResource->getUniquePropertyValue($this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_TYPE)); - if ($translationType->getUri() !== ResourceTranslation::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL) { + if ($translationType->getUri() !== TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL) { throw new ResourceTranslationException( sprintf('Translation Origin Resource %s it not the original', $originResourceId) ); @@ -74,7 +75,7 @@ public function find(ResourceTranslationQuery $query): ResourceTranslationCollec $output = new ResourceTranslationCollection($originResourceId); $uniqueId = $originResource->getUniquePropertyValue( - $this->ontology->getProperty(ResourceTranslation::PROPERTY_UNIQUE_IDENTIFIER) + $this->ontology->getProperty(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER) ); $queryBuilder = $this->complexSearch->query(); @@ -84,19 +85,19 @@ public function find(ResourceTranslationQuery $query): ResourceTranslationCollec true ); $searchQuery->addCriterion( - ResourceTranslation::PROPERTY_TRANSLATION_TYPE, + TaoOntology::PROPERTY_TRANSLATION_TYPE, SupportedOperatorHelper::EQUAL, - ResourceTranslation::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION + TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION ); $searchQuery->addCriterion( - ResourceTranslation::PROPERTY_UNIQUE_IDENTIFIER, + TaoOntology::PROPERTY_UNIQUE_IDENTIFIER, SupportedOperatorHelper::EQUAL, $uniqueId ); if ($query->getLanguageUri()) { $searchQuery->addCriterion( - ResourceTranslation::PROPERTY_LANGUAGE, + TaoOntology::PROPERTY_LANGUAGE, SupportedOperatorHelper::EQUAL, $query->getLanguageUri() ); From b7fdee0f3163782871b64ab3aff41ddca6bd0db9 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Fri, 6 Sep 2024 16:46:13 +0200 Subject: [PATCH 16/50] feat: add new endpoint to get master unit and increase contract output --- actions/class.Translation.php | 17 +++ .../Entity/ResourceTranslatable.php | 103 ++++++++++++++++++ .../Entity/ResourceTranslatableCollection.php | 41 +++++++ .../Entity/ResourceTranslationCollection.php | 23 ++-- .../Factory/ResourceTranslatableFactory.php | 66 +++++++++++ .../Factory/ResourceTranslationFactory.php | 5 +- .../Query/ResourceTranslatableQuery.php | 52 +++++++++ .../Query/ResourceTranslationQuery.php | 9 +- .../ResourceTranslatableRepository.php | 90 +++++++++++++++ .../ResourceTranslationRepository.php | 45 ++++---- .../Service/ResourceTranslatableRetriever.php | 59 ++++++++++ .../Service/ResourceTranslationRetriever.php | 13 ++- .../TranslationServiceProvider.php | 29 ++++- 13 files changed, 519 insertions(+), 33 deletions(-) create mode 100644 models/classes/Translation/Entity/ResourceTranslatable.php create mode 100644 models/classes/Translation/Entity/ResourceTranslatableCollection.php create mode 100644 models/classes/Translation/Factory/ResourceTranslatableFactory.php create mode 100644 models/classes/Translation/Query/ResourceTranslatableQuery.php create mode 100644 models/classes/Translation/Repository/ResourceTranslatableRepository.php create mode 100644 models/classes/Translation/Service/ResourceTranslatableRetriever.php diff --git a/actions/class.Translation.php b/actions/class.Translation.php index 37a78aada1..af311dd78d 100644 --- a/actions/class.Translation.php +++ b/actions/class.Translation.php @@ -22,6 +22,7 @@ use oat\tao\model\http\HttpJsonResponseTrait; use oat\tao\model\Translation\Service\ResourceTranslationRetriever; +use oat\tao\model\Translation\Service\ResourceTranslatableRetriever; class tao_actions_Translation extends tao_actions_CommonModule { @@ -38,8 +39,24 @@ public function translations(): void } } + public function translatable(): void + { + try { + $this->setSuccessJsonResponse( + $this->getResourceTranslatableRetriever()->getByRequest($this->getPsrRequest()) + ); + } catch (Throwable $exception) { + $this->setErrorJsonResponse($exception->getMessage()); + } + } + private function getResourceTranslationRetriever(): ResourceTranslationRetriever { return $this->getServiceManager()->getContainer()->get(ResourceTranslationRetriever::class); } + + private function getResourceTranslatableRetriever(): ResourceTranslatableRetriever + { + return $this->getServiceManager()->getContainer()->get(ResourceTranslatableRetriever::class); + } } diff --git a/models/classes/Translation/Entity/ResourceTranslatable.php b/models/classes/Translation/Entity/ResourceTranslatable.php new file mode 100644 index 0000000000..501d103a28 --- /dev/null +++ b/models/classes/Translation/Entity/ResourceTranslatable.php @@ -0,0 +1,103 @@ + self::STATUS_READY_FOR_TRANSLATION, + TaoOntology::PROPERTY_VALUE_TRANSLATION_STATUS_NOT_READY => self::STATUS_NOT_READY_FOR_TRANSLATION + ]; + + private string $resourceUri; + private string $status; + private string $statusUri; + private string $languageCode; + private string $languageUri; + private string $uniqueId; + + public function __construct( + string $resourceUri, + string $uniqueId, + string $progress, + string $progressUri, + string $languageCode, + string $languageUri + ) + { + $this->resourceUri = $resourceUri; + $this->uniqueId = $uniqueId; + $this->status = $progress; + $this->statusUri = $progressUri; + $this->languageCode = $languageCode; + $this->languageUri = $languageUri; + } + + public function getResourceUri(): string + { + return $this->resourceUri; + } + + public function getUniqueId(): string + { + return $this->uniqueId; + } + + public function getStatus(): string + { + return $this->status; + } + + public function getStatusUri(): string + { + return $this->statusUri; + } + + public function getLanguageCode(): string + { + return $this->languageCode; + } + + public function getLanguageUri(): string + { + return $this->languageUri; + } + + public function jsonSerialize(): array + { + return [ + 'resourceUri' => $this->getResourceUri(), + 'uniqueId' => $this->getUniqueId(), + 'status' => $this->getStatus(), + 'statusUri' => $this->getStatusUri(), + 'languageCode' => $this->getLanguageCode(), + 'languageUri' => $this->getLanguageUri(), + ]; + } +} diff --git a/models/classes/Translation/Entity/ResourceTranslatableCollection.php b/models/classes/Translation/Entity/ResourceTranslatableCollection.php new file mode 100644 index 0000000000..bb64c8333d --- /dev/null +++ b/models/classes/Translation/Entity/ResourceTranslatableCollection.php @@ -0,0 +1,41 @@ + $this->getArrayCopy() + ]; + } +} diff --git a/models/classes/Translation/Entity/ResourceTranslationCollection.php b/models/classes/Translation/Entity/ResourceTranslationCollection.php index 7bfc3c9a30..5458808c4c 100644 --- a/models/classes/Translation/Entity/ResourceTranslationCollection.php +++ b/models/classes/Translation/Entity/ResourceTranslationCollection.php @@ -22,39 +22,44 @@ namespace oat\tao\model\Translation\Entity; +use ArrayIterator; use JsonSerializable; -class ResourceTranslationCollection implements JsonSerializable +class ResourceTranslationCollection extends ArrayIterator implements JsonSerializable { - private array $translations = []; private string $originResourceUri; + private string $uniqueId; - public function __construct(string $originResourceUri) + public function __construct(string $originResourceUri, string $uniqueId) { + parent::__construct(); + $this->originResourceUri = $originResourceUri; + $this->uniqueId = $uniqueId; } public function addTranslation(ResourceTranslation $resourceTranslation): void { - $this->translations[] = $resourceTranslation; + $this->append($resourceTranslation); } - public function getTranslations(): array + public function getOriginResourceUri(): string { - return $this->translations; + return $this->originResourceUri; } - public function getOriginResourceUri(): string + public function getUniqueId(): string { - return $this->originResourceUri; + return $this->uniqueId; } public function jsonSerialize(): array { return [ 'originResourceUri' => $this->getOriginResourceUri(), - 'translations' => $this->getTranslations() + 'uniqueId' => $this->getUniqueId(), + 'translations' => $this->getArrayCopy() ]; } } diff --git a/models/classes/Translation/Factory/ResourceTranslatableFactory.php b/models/classes/Translation/Factory/ResourceTranslatableFactory.php new file mode 100644 index 0000000000..f371a4968d --- /dev/null +++ b/models/classes/Translation/Factory/ResourceTranslatableFactory.php @@ -0,0 +1,66 @@ +ontology = $ontology; + } + + public function create(core_kernel_classes_Resource $originResource): ResourceTranslatable + { + $progressProperty = $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_STATUS); + + /** @var core_kernel_classes_Resource $progress */ + $progress = $originResource->getUniquePropertyValue($progressProperty); + + $uniqueId = $originResource->getUniquePropertyValue( + $this->ontology->getProperty(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER) + ); + + $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); + $languageProperty = $this->ontology->getProperty(TaoOntology::PROPERTY_LANGUAGE); + + /** @var core_kernel_classes_Resource $language */ + $language = $originResource->getUniquePropertyValue($languageProperty); + $languageCode = $language->getUniquePropertyValue($valueProperty); + + return new ResourceTranslatable( + $originResource->getUri(), + (string)$uniqueId, + ResourceTranslatable::STATUS_MAPPING[$progress->getUri()], + $progress->getUri(), + (string)$languageCode, + $language->getUri() + ); + } +} diff --git a/models/classes/Translation/Factory/ResourceTranslationFactory.php b/models/classes/Translation/Factory/ResourceTranslationFactory.php index 231908c20f..eb2aa2b605 100644 --- a/models/classes/Translation/Factory/ResourceTranslationFactory.php +++ b/models/classes/Translation/Factory/ResourceTranslationFactory.php @@ -25,6 +25,7 @@ use core_kernel_classes_Resource; use oat\generis\model\data\Ontology; use oat\tao\model\TaoOntology; +use oat\tao\model\Translation\Entity\ResourceTranslatable; use oat\tao\model\Translation\Entity\ResourceTranslation; class ResourceTranslationFactory @@ -37,7 +38,7 @@ public function __construct(Ontology $ontology) } public function create( - core_kernel_classes_Resource $originResource, + ResourceTranslatable $originResource, core_kernel_classes_Resource $translationResource, ): ResourceTranslation { $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); @@ -52,7 +53,7 @@ public function create( $progress = $translationResource->getUniquePropertyValue($progressProperty); return new ResourceTranslation( - $originResource->getUri(), + $originResource->getResourceUri(), $translationResource->getUri(), $translationResource->getLabel(), ResourceTranslation::PROGRESS_MAPPING[$progress->getUri()], diff --git a/models/classes/Translation/Query/ResourceTranslatableQuery.php b/models/classes/Translation/Query/ResourceTranslatableQuery.php new file mode 100644 index 0000000000..9bda0b5fc9 --- /dev/null +++ b/models/classes/Translation/Query/ResourceTranslatableQuery.php @@ -0,0 +1,52 @@ +resourceType = $resourceType; + $this->resourceIds = $resourceIds; + $this->uniqueIds = $uniqueIds; + } + + public function getResourceType(): string + { + return $this->resourceType; + } + + public function getResourceIds(): array + { + return $this->resourceIds; + } + + public function getUniqueIds(): array + { + return $this->uniqueIds; + } +} diff --git a/models/classes/Translation/Query/ResourceTranslationQuery.php b/models/classes/Translation/Query/ResourceTranslationQuery.php index c1f53c1fad..628b394c29 100644 --- a/models/classes/Translation/Query/ResourceTranslationQuery.php +++ b/models/classes/Translation/Query/ResourceTranslationQuery.php @@ -24,15 +24,22 @@ class ResourceTranslationQuery { + private string $resourceType; private string $originResourceId; private ?string $languageUri; - public function __construct(string $originResourceId, string $languageUri = null) + public function __construct(string $resourceType, string $originResourceId, string $languageUri = null) { + $this->resourceType = $resourceType; $this->originResourceId = $originResourceId; $this->languageUri = $languageUri; } + public function getResourceType(): string + { + return $this->resourceType; + } + public function getOriginResourceId(): string { return $this->originResourceId; diff --git a/models/classes/Translation/Repository/ResourceTranslatableRepository.php b/models/classes/Translation/Repository/ResourceTranslatableRepository.php new file mode 100644 index 0000000000..be94c0b79a --- /dev/null +++ b/models/classes/Translation/Repository/ResourceTranslatableRepository.php @@ -0,0 +1,90 @@ +complexSearch = $complexSearch; + $this->factory = $factory; + $this->ontology = $ontology; + } + + public function find(ResourceTranslatableQuery $query): ResourceTranslatableCollection + { + $queryBuilder = $this->complexSearch->query(); + $searchQuery = $this->complexSearch->searchType( + $queryBuilder, + 'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject', + true + ); + $searchQuery->addCriterion( + TaoOntology::PROPERTY_TRANSLATION_TYPE, + SupportedOperatorHelper::EQUAL, + TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL + ); + + if (!empty($query->getUniqueIds())) { + $searchQuery->addCriterion( + TaoOntology::PROPERTY_UNIQUE_IDENTIFIER, + SupportedOperatorHelper::IN, + $query->getUniqueIds() + ); + } + + $queryBuilder->setCriteria($searchQuery); + + $result = $this->complexSearch->getGateway()->search($queryBuilder); + $output = []; + + $resourceTypeClass = $this->ontology->getClass($query->getResourceType()); + + /** @var core_kernel_classes_Resource $resource */ + foreach ($result as $resource) { + if (!$resource->isInstanceOf($resourceTypeClass)) { + continue; + } + + $output[] = $this->factory->create($resource); + } + + return new ResourceTranslatableCollection(...$output); + } +} diff --git a/models/classes/Translation/Repository/ResourceTranslationRepository.php b/models/classes/Translation/Repository/ResourceTranslationRepository.php index 777c4b5c2d..3e7fcfff6b 100644 --- a/models/classes/Translation/Repository/ResourceTranslationRepository.php +++ b/models/classes/Translation/Repository/ResourceTranslationRepository.php @@ -28,10 +28,10 @@ use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; use oat\search\helper\SupportedOperatorHelper; use oat\tao\model\TaoOntology; -use oat\tao\model\Translation\Entity\ResourceTranslation; +use oat\tao\model\Translation\Entity\ResourceTranslatable; use oat\tao\model\Translation\Entity\ResourceTranslationCollection; -use oat\tao\model\Translation\Entity\ResourceTranslationException; use oat\tao\model\Translation\Factory\ResourceTranslationFactory; +use oat\tao\model\Translation\Query\ResourceTranslatableQuery; use oat\tao\model\Translation\Query\ResourceTranslationQuery; use Psr\Log\LoggerInterface; use Throwable; @@ -42,15 +42,18 @@ class ResourceTranslationRepository private ComplexSearchService $complexSearch; private LoggerInterface $logger; private ResourceTranslationFactory $factory; + private ResourceTranslatableRepository $resourceTranslatableRepository; public function __construct( Ontology $ontology, ComplexSearchService $complexSearch, + ResourceTranslatableRepository $resourceTranslatableRepository, ResourceTranslationFactory $resourceTranslationFactory, LoggerInterface $logger ) { $this->ontology = $ontology; $this->complexSearch = $complexSearch; + $this->resourceTranslatableRepository = $resourceTranslatableRepository; $this->factory = $resourceTranslationFactory; $this->logger = $logger; } @@ -58,25 +61,24 @@ public function __construct( public function find(ResourceTranslationQuery $query): ResourceTranslationCollection { $originResourceId = $query->getOriginResourceId(); - $originResource = $this->ontology->getResource($originResourceId); + $resources = $this->resourceTranslatableRepository->find( + new ResourceTranslatableQuery( + $query->getResourceType(), + [ + $originResourceId + ] + ) + ); - if (!$originResource->exists()) { + if ($resources->count() === 0) { throw new Exception(sprintf('Translation Origin Resource %s does not exist', $originResourceId)); } - /** @var core_kernel_classes_Resource $translationType */ - $translationType = $originResource->getUniquePropertyValue($this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_TYPE)); - - if ($translationType->getUri() !== TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL) { - throw new ResourceTranslationException( - sprintf('Translation Origin Resource %s it not the original', $originResourceId) - ); - } - - $output = new ResourceTranslationCollection($originResourceId); - $uniqueId = $originResource->getUniquePropertyValue( - $this->ontology->getProperty(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER) - ); + /** @var ResourceTranslatable $originResource */ + $originResource = $resources->current(); + + $uniqueId = $originResource->getUniqueId(); + $output = new ResourceTranslationCollection($originResourceId, $uniqueId); $queryBuilder = $this->complexSearch->query(); $searchQuery = $this->complexSearch->searchType( @@ -106,17 +108,22 @@ public function find(ResourceTranslationQuery $query): ResourceTranslationCollec $queryBuilder->setCriteria($searchQuery); $result = $this->complexSearch->getGateway()->search($queryBuilder); + $resourceTypeClass = $this->ontology->getClass($query->getResourceType()); - /** @var core_kernel_classes_Resource $resource */ + /** @var core_kernel_classes_Resource $translationResource */ foreach ($result as $translationResource) { try { + if (!$translationResource->isInstanceOf($resourceTypeClass)) { + continue; + } + $output->addTranslation($this->factory->create($originResource, $translationResource)); } catch (Throwable $exception) { $this->logger->warning( sprintf( 'Cannot read translation status for [originResourceId=%s, translationResourceId=%s]: %s - %s', $originResourceId, - $resource->getUri(), + $translationResource->getUri(), $exception->getMessage(), $exception->getTraceAsString() ) diff --git a/models/classes/Translation/Service/ResourceTranslatableRetriever.php b/models/classes/Translation/Service/ResourceTranslatableRetriever.php new file mode 100644 index 0000000000..006f3d24af --- /dev/null +++ b/models/classes/Translation/Service/ResourceTranslatableRetriever.php @@ -0,0 +1,59 @@ +resourceTranslatableRepository = $resourceTranslationRepository; + } + + public function getByRequest(ServerRequestInterface $request): ResourceTranslatableCollection + { + $queryParams = $request->getQueryParams(); + $resourceType = $queryParams['resourceType'] ?? null; + $resourceUris = $queryParams['resourceUris'] ?? []; + $uniqueIds = $queryParams['uniqueIds'] ?? []; + + if (empty($resourceType)) { + throw new InvalidArgumentException('Param resourceType is required'); + } + + return $this->resourceTranslatableRepository->find( + new ResourceTranslatableQuery( + $resourceType, + $resourceUris, + $uniqueIds + ) + ); + } +} diff --git a/models/classes/Translation/Service/ResourceTranslationRetriever.php b/models/classes/Translation/Service/ResourceTranslationRetriever.php index 7f59dd2a2a..76c9cce2ef 100644 --- a/models/classes/Translation/Service/ResourceTranslationRetriever.php +++ b/models/classes/Translation/Service/ResourceTranslationRetriever.php @@ -40,13 +40,24 @@ public function __construct(ResourceTranslationRepository $resourceTranslationRe public function getByRequest(ServerRequestInterface $request): ResourceTranslationCollection { $queryParams = $request->getQueryParams(); + $resourceType = $queryParams['resourceType'] ?? null; $resourceUri = $queryParams['resourceUri'] ?? null; $languageUri = $queryParams['languageUri'] ?? null; + if (empty($resourceType)) { + throw new InvalidArgumentException('Param resourceType is required'); + } + if (empty($resourceUri)) { throw new InvalidArgumentException('Param resourceUri is required'); } - return $this->resourceTranslationRepository->find(new ResourceTranslationQuery($resourceUri, $languageUri)); + return $this->resourceTranslationRepository->find( + new ResourceTranslationQuery( + $resourceType, + $resourceUri, + $languageUri + ) + ); } } diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index dc275e61ca..6a48917b67 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -26,12 +26,14 @@ use oat\generis\model\DependencyInjection\ContainerServiceProviderInterface; use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; use oat\oatbox\log\LoggerService; +use oat\tao\model\Translation\Factory\ResourceTranslatableFactory; use oat\tao\model\Translation\Factory\ResourceTranslationFactory; +use oat\tao\model\Translation\Repository\ResourceTranslatableRepository; use oat\tao\model\Translation\Repository\ResourceTranslationRepository; +use oat\tao\model\Translation\Service\ResourceTranslatableRetriever; use oat\tao\model\Translation\Service\ResourceTranslationRetriever; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; -use function Symfony\Component\DependencyInjection\Loader\Configurator\inline_service; use function Symfony\Component\DependencyInjection\Loader\Configurator\service; /** @@ -47,11 +49,21 @@ public function __invoke(ContainerConfigurator $configurator): void [ service(Ontology::SERVICE_ID), service(ComplexSearchService::SERVICE_ID), + service(ResourceTranslatableRepository::class), service(ResourceTranslationFactory::class), service(LoggerService::SERVICE_ID), ] ); + $services->set(ResourceTranslatableRepository::class, ResourceTranslatableRepository::class) + ->args( + [ + service(Ontology::SERVICE_ID), + service(ComplexSearchService::SERVICE_ID), + service(ResourceTranslatableFactory::class) + ] + ); + $services->set(ResourceTranslationFactory::class, ResourceTranslationFactory::class) ->args( [ @@ -59,6 +71,13 @@ public function __invoke(ContainerConfigurator $configurator): void ] ); + $services->set(ResourceTranslatableFactory::class, ResourceTranslatableFactory::class) + ->args( + [ + service(Ontology::SERVICE_ID) + ] + ); + $services->set(ResourceTranslationRetriever::class, ResourceTranslationRetriever::class) ->args( [ @@ -66,5 +85,13 @@ public function __invoke(ContainerConfigurator $configurator): void ] ) ->public(); + + $services->set(ResourceTranslatableRetriever::class, ResourceTranslatableRetriever::class) + ->args( + [ + service(ResourceTranslatableRepository::class) + ] + ) + ->public(); } } From 9bc1a328c3741efd6015eab4dedbfc56a0a1904c Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Fri, 6 Sep 2024 17:49:33 +0200 Subject: [PATCH 17/50] chore: adding unit tests --- .../Entity/ResourceTranslatable.php | 8 +-- .../Entity/ResourceTranslatableTest.php | 61 +++++++++++++++++++ ...usTest.php => ResourceTranslationTest.php} | 43 ++++++------- 3 files changed, 83 insertions(+), 29 deletions(-) create mode 100644 test/unit/models/classes/Translation/Entity/ResourceTranslatableTest.php rename test/unit/models/classes/Translation/Entity/{ResourceTranslationStatusTest.php => ResourceTranslationTest.php} (53%) diff --git a/models/classes/Translation/Entity/ResourceTranslatable.php b/models/classes/Translation/Entity/ResourceTranslatable.php index 501d103a28..ca5c7759fd 100644 --- a/models/classes/Translation/Entity/ResourceTranslatable.php +++ b/models/classes/Translation/Entity/ResourceTranslatable.php @@ -45,16 +45,16 @@ class ResourceTranslatable implements JsonSerializable public function __construct( string $resourceUri, string $uniqueId, - string $progress, - string $progressUri, + string $status, + string $statusUri, string $languageCode, string $languageUri ) { $this->resourceUri = $resourceUri; $this->uniqueId = $uniqueId; - $this->status = $progress; - $this->statusUri = $progressUri; + $this->status = $status; + $this->statusUri = $statusUri; $this->languageCode = $languageCode; $this->languageUri = $languageUri; } diff --git a/test/unit/models/classes/Translation/Entity/ResourceTranslatableTest.php b/test/unit/models/classes/Translation/Entity/ResourceTranslatableTest.php new file mode 100644 index 0000000000..7bd59a6888 --- /dev/null +++ b/test/unit/models/classes/Translation/Entity/ResourceTranslatableTest.php @@ -0,0 +1,61 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Entity; + +use oat\tao\model\Translation\Entity\ResourceTranslatable; +use PHPUnit\Framework\TestCase; + +class ResourceTranslatableTest extends TestCase +{ + /** @var ResourceTranslatable */ + private $sut; + + public function setUp(): void + { + $this->sut = new ResourceTranslatable( + 'resourceUri', + 'uniqueId', + 'status', + 'statusUri', + 'languageCode', + 'languageUri' + ); + } + + public function testGetters(): void + { + $this->assertSame( + [ + 'resourceUri' => 'resourceUri', + 'uniqueId' => 'uniqueId', + 'status' => 'status', + 'statusUri' => 'statusUri', + 'languageCode' => 'languageCode', + 'languageUri' => 'languageUri' + ], + $this->sut->jsonSerialize() + ); + } +} diff --git a/test/unit/models/classes/Translation/Entity/ResourceTranslationStatusTest.php b/test/unit/models/classes/Translation/Entity/ResourceTranslationTest.php similarity index 53% rename from test/unit/models/classes/Translation/Entity/ResourceTranslationStatusTest.php rename to test/unit/models/classes/Translation/Entity/ResourceTranslationTest.php index f974efaf0f..0cda827664 100644 --- a/test/unit/models/classes/Translation/Entity/ResourceTranslationStatusTest.php +++ b/test/unit/models/classes/Translation/Entity/ResourceTranslationTest.php @@ -27,42 +27,35 @@ use oat\tao\model\Translation\Entity\ResourceTranslation; use PHPUnit\Framework\TestCase; -class ResourceTranslationStatusTest extends TestCase +class ResourceTranslationTest extends TestCase { /** @var ResourceTranslation */ private $sut; public function setUp(): void { - $this->sut = new ResourceTranslation('myResourceUri'); + $this->sut = new ResourceTranslation( + 'originResourceUri', + 'resourceUri', + 'resourceLabel', + 'progress', + 'progressUri', + 'languageCode', + 'languageUri', + ); } - public function testGetStatus(): void + public function testGetters(): void { - $this->sut->addTranslation('en-US', ResourceTranslation::STATUS_PENDING, 'uri1'); - $this->sut->addTranslation('fr-FR', ResourceTranslation::STATUS_TRANSLATING, 'uri2'); - $this->sut->addTranslation('de-DE', ResourceTranslation::STATUS_TRANSLATED, 'uri3'); - $this->assertSame( [ - 'originResourceUri' => 'myResourceUri', - 'translations' => [ - [ - 'status' => 'pending', - 'locale' => 'en-US', - 'resourceUri' => 'uri1', - ], - [ - 'status' => 'translating', - 'locale' => 'fr-FR', - 'resourceUri' => 'uri2' - ], - [ - 'status' => 'translated', - 'locale' => 'de-DE', - 'resourceUri' => 'uri3' - ] - ], + 'originResourceUri' => 'originResourceUri', + 'resourceUri' => 'resourceUri', + 'resourceLabel' => 'resourceLabel', + 'languageCode' => 'languageCode', + 'languageUri' => 'languageUri', + 'progress' => 'progress', + 'progressUri' => 'progressUri', ], $this->sut->jsonSerialize() ); From 05944c8fa8441245090e8423de47f0d42f4bc0e9 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Fri, 6 Sep 2024 17:53:00 +0200 Subject: [PATCH 18/50] chore: adding unit tests --- .../ResourceTranslatableCollectionTest.php | 49 +++++++++++++++++ .../ResourceTranslationCollectionTest.php | 54 +++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 test/unit/models/classes/Translation/Entity/ResourceTranslatableCollectionTest.php create mode 100644 test/unit/models/classes/Translation/Entity/ResourceTranslationCollectionTest.php diff --git a/test/unit/models/classes/Translation/Entity/ResourceTranslatableCollectionTest.php b/test/unit/models/classes/Translation/Entity/ResourceTranslatableCollectionTest.php new file mode 100644 index 0000000000..9b73ec0cd6 --- /dev/null +++ b/test/unit/models/classes/Translation/Entity/ResourceTranslatableCollectionTest.php @@ -0,0 +1,49 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Entity; + +use oat\tao\model\Translation\Entity\ResourceTranslatableCollection; +use PHPUnit\Framework\TestCase; + +class ResourceTranslatableCollectionTest extends TestCase +{ + /** @var ResourceTranslatableCollection */ + private $sut; + + public function setUp(): void + { + $this->sut = new ResourceTranslatableCollection(...[]); + } + + public function testGetters(): void + { + $this->assertSame( + [ + 'resources' => [] + ], + $this->sut->jsonSerialize() + ); + } +} diff --git a/test/unit/models/classes/Translation/Entity/ResourceTranslationCollectionTest.php b/test/unit/models/classes/Translation/Entity/ResourceTranslationCollectionTest.php new file mode 100644 index 0000000000..52d0d2f507 --- /dev/null +++ b/test/unit/models/classes/Translation/Entity/ResourceTranslationCollectionTest.php @@ -0,0 +1,54 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Entity; + +use oat\tao\model\Translation\Entity\ResourceTranslationCollection; +use PHPUnit\Framework\TestCase; + +class ResourceTranslationCollectionTest extends TestCase +{ + /** @var ResourceTranslationCollection */ + private $sut; + + public function setUp(): void + { + $this->sut = new ResourceTranslationCollection( + 'originResourceUri', + 'uniqueId', + ); + } + + public function testGetters(): void + { + $this->assertSame( + [ + 'originResourceUri' => 'originResourceUri', + 'uniqueId' => 'uniqueId', + 'translations' => [], + ], + $this->sut->jsonSerialize() + ); + } +} From c866e86335f84f7a2e58a87e0ec24c98cb9933cc Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Mon, 9 Sep 2024 16:15:40 +0200 Subject: [PATCH 19/50] feat: add possibility to hide button in tree by path and feature flag --- actions/class.Main.php | 19 ++++++++-- models/classes/featureFlag/README.md | 14 ++++++-- .../classes/menu/SectionVisibilityFilter.php | 36 +++++++++++++------ .../menu/SectionVisibilityFilterInterface.php | 2 +- 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/actions/class.Main.php b/actions/class.Main.php index f17b3a72fb..f2d693b0a3 100644 --- a/actions/class.Main.php +++ b/actions/class.Main.php @@ -521,11 +521,13 @@ private function getSections($shownExtension, $shownStructure) $sections = []; $user = $this->getSession()->getUser(); $structure = MenuService::getPerspective($shownExtension, $shownStructure); + $sectionVisibilityFilter = $this->getSectionVisibilityFilter(); + if (!is_null($structure)) { foreach ($structure->getChildren() as $section) { $resolver = new ActionResolver($section->getUrl()); - if (!$this->getSectionVisibilityFilter()->isVisible($section->getId())) { + if (!$sectionVisibilityFilter->isVisible($section->getId())) { continue; } @@ -540,6 +542,19 @@ private function getSections($shownExtension, $shownStructure) if (FuncProxy::accessPossible($user, $resolver->getController(), $resolver->getAction())) { foreach ($section->getActions() as $action) { + $sectionPath = $sectionVisibilityFilter->createSectionPath( + [ + $section->getId(), + $action->getId() + ] + ); + + if (!$sectionVisibilityFilter->isVisible($sectionPath)) { + $section->removeAction($action); + + continue; + } + $this->propagate($action); $resolver = new ActionResolver($action->getUrl()); if ( @@ -580,7 +595,7 @@ protected function getUserService() return $this->getServiceLocator()->get(tao_models_classes_UserService::SERVICE_ID); } - private function getSectionVisibilityFilter(): SectionVisibilityFilterInterface + private function getSectionVisibilityFilter(): SectionVisibilityFilter { if (empty($this->sectionVisibilityFilter)) { $this->sectionVisibilityFilter = $this->getServiceLocator()->get(SectionVisibilityFilter::SERVICE_ID); diff --git a/models/classes/featureFlag/README.md b/models/classes/featureFlag/README.md index 1f0877c874..3936e2ddf6 100644 --- a/models/classes/featureFlag/README.md +++ b/models/classes/featureFlag/README.md @@ -71,20 +71,28 @@ sections that have to be disabled/enabled based on feature flag. return new oat\tao\model\menu\SectionVisibilityFilter(array( 'featureFlagSections' => [ - 'sectionName' => [ + 'sectionName1' => [ + 'FEATURE_FLAG_01' + ], + 'sectionName2/actionName' => [ 'FEATURE_FLAG_01' ] ], 'featureFlagSectionsToHide' => [ - 'sectionNameToHide' => [ + 'sectionNameToHide1' => [ + 'FEATURE_FLAG_02' + ], + 'sectionNameToHide2/actionName' => [ 'FEATURE_FLAG_02' ] ] )); ``` -This configuration will display `sectionName` when `FEATURE_FLAG_01` is enabled. +This configuration will display `sectionName1` when `FEATURE_FLAG_01` is enabled. +This configuration will display `actionName` from `sectionName2` when `FEATURE_FLAG_01` is enabled. This configuration will hide `sectionNameToHide` when `FEATURE_FLAG_02` is enabled. +This configuration will display `actionName` from `sectionNameToHide` when `FEATURE_FLAG_02` is enabled. ### Override configs on execution time diff --git a/models/classes/menu/SectionVisibilityFilter.php b/models/classes/menu/SectionVisibilityFilter.php index e236b6435e..c14a75932f 100644 --- a/models/classes/menu/SectionVisibilityFilter.php +++ b/models/classes/menu/SectionVisibilityFilter.php @@ -22,7 +22,6 @@ namespace oat\tao\model\menu; -use LogicException; use oat\generis\model\GenerisRdf; use oat\oatbox\service\ConfigurableService; use oat\tao\model\featureFlag\FeatureFlagChecker; @@ -33,6 +32,7 @@ class SectionVisibilityFilter extends ConfigurableService implements SectionVisibilityFilterInterface { + private const SECTION_PATH_SEPARATOR = '/'; public const SERVICE_ID = 'tao/SectionVisibilityFilter'; public const OPTION_FEATURE_FLAG_SECTIONS = 'featureFlagSections'; public const OPTION_FEATURE_FLAG_SECTIONS_TO_HIDE = 'featureFlagSectionsToHide'; @@ -44,10 +44,7 @@ class SectionVisibilityFilter extends ConfigurableService implements SectionVisi public const SIMPLE_INTERFACE_MODE_HIDDEN_SECTIONS = []; - /** - * @throws LogicException - */ - public function isVisible(string $section): bool + public function isVisible(string $sectionPath): bool { $sections = $this->getOption(self::OPTION_FEATURE_FLAG_SECTIONS, []); $sectionToHide = array_merge_recursive( @@ -55,13 +52,13 @@ public function isVisible(string $section): bool self::DEFAULT_FEATURE_FLAG_SECTIONS_TO_HIDE ); - foreach ($sectionToHide[$section] ?? [] as $featureFlag) { + foreach ($sectionToHide[$sectionPath] ?? [] as $featureFlag) { if ($this->getFeatureFlagChecker()->isEnabled($featureFlag)) { return false; } } - foreach ($sections[$section] ?? [] as $featureFlag) { + foreach ($sections[$sectionPath] ?? [] as $featureFlag) { if (!$this->getFeatureFlagChecker()->isEnabled($featureFlag)) { return false; } @@ -73,7 +70,7 @@ public function isVisible(string $section): bool $userSettings->getSetting( UserSettingsInterface::INTERFACE_MODE ) === GenerisRdf::PROPERTY_USER_INTERFACE_MODE_SIMPLE - && in_array($section, self::SIMPLE_INTERFACE_MODE_HIDDEN_SECTIONS) + && in_array($sectionPath, self::SIMPLE_INTERFACE_MODE_HIDDEN_SECTIONS) ) { return false; } @@ -81,11 +78,16 @@ public function isVisible(string $section): bool return true; } - public function hideSectionByFeatureFlag(string $section, string $featureFlag): void + public function createSectionPath(array $segments): string + { + return implode(self::SECTION_PATH_SEPARATOR, $segments); + } + + public function hideSectionByFeatureFlag(string $sectionPath, string $featureFlag): void { $options = $this->getOption(SectionVisibilityFilter::OPTION_FEATURE_FLAG_SECTIONS_TO_HIDE, []); - $options[$section] = array_merge( - $options[$section] ?? [], + $options[$sectionPath] = array_merge( + $options[$sectionPath] ?? [], [ $featureFlag ] @@ -93,6 +95,18 @@ public function hideSectionByFeatureFlag(string $section, string $featureFlag): $this->setOption(SectionVisibilityFilter::OPTION_FEATURE_FLAG_SECTIONS_TO_HIDE, $options); } + public function showSectionByFeatureFlag(string $sectionPath, string $featureFlag): void + { + $options = $this->getOption(SectionVisibilityFilter::OPTION_FEATURE_FLAG_SECTIONS, []); + $options[$sectionPath] = array_merge( + $options[$sectionPath] ?? [], + [ + $featureFlag + ] + ); + $this->setOption(SectionVisibilityFilter::OPTION_FEATURE_FLAG_SECTIONS, $options); + } + private function getFeatureFlagChecker(): FeatureFlagCheckerInterface { return $this->getServiceManager()->getContainer()->get(FeatureFlagChecker::class); diff --git a/models/classes/menu/SectionVisibilityFilterInterface.php b/models/classes/menu/SectionVisibilityFilterInterface.php index bf7c86b035..77e0f3357f 100644 --- a/models/classes/menu/SectionVisibilityFilterInterface.php +++ b/models/classes/menu/SectionVisibilityFilterInterface.php @@ -24,5 +24,5 @@ interface SectionVisibilityFilterInterface { - public function isVisible(string $section): bool; + public function isVisible(string $sectionPath): bool; } From 41375eb86112ced04cd1aa0598bfee6d25aa1787 Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Mon, 9 Sep 2024 18:49:03 +0300 Subject: [PATCH 20/50] feat: implement form modifiers, make uniq id readonly --- helpers/form/class.FormContainer.php | 22 ++++++- manifest.php | 2 + .../EditTranslationInstanceFormModifier.php | 58 +++++++++++++++++++ .../TranslationServiceProvider.php | 18 ++++++ .../form/Modifier/FormModifierInterface.php | 14 +++++ .../form/Modifier/FormModifierManager.php | 38 ++++++++++++ .../Modifier/FormModifierServiceProvider.php | 18 ++++++ models/ontology/tao.rdf | 4 +- 8 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 models/classes/Translation/Form/Modifier/EditTranslationInstanceFormModifier.php create mode 100644 models/classes/form/Modifier/FormModifierInterface.php create mode 100644 models/classes/form/Modifier/FormModifierManager.php create mode 100644 models/classes/form/Modifier/FormModifierServiceProvider.php diff --git a/helpers/form/class.FormContainer.php b/helpers/form/class.FormContainer.php index 7fe405faa3..eaae9c496b 100644 --- a/helpers/form/class.FormContainer.php +++ b/helpers/form/class.FormContainer.php @@ -26,7 +26,9 @@ use oat\oatbox\service\ServiceManager; use oat\oatbox\validator\ValidatorInterface; +use oat\tao\model\form\Modifier\FormModifierManager; use oat\tao\model\security\xsrf\TokenService; +use Psr\Container\ContainerInterface; use tao_helpers_form_FormFactory as FormFactory; use oat\tao\helpers\form\elements\xhtml\CsrfToken; use oat\tao\helpers\form\elements\FormElementAware; @@ -46,6 +48,7 @@ abstract class tao_helpers_form_FormContainer public const IS_DISABLED = 'is_disabled'; public const ADDITIONAL_VALIDATORS = 'extraValidators'; public const ATTRIBUTE_VALIDATORS = 'attributeValidators'; + public const FORM_MODIFIERS = 'formModifiers'; public const WITH_SERVICE_MANAGER = 'withServiceManager'; @@ -118,6 +121,10 @@ public function __construct(array $data = [], array $options = []) // initialize the elements of the form $this->initElements(); + if (!empty($options[self::FORM_MODIFIERS])) { + $this->getFormModifierManager()->modify($this->form, $options[self::FORM_MODIFIERS]); + } + if ($this->form !== null) { $this->form->evaluateInputValues(); @@ -317,13 +324,17 @@ private function configureFormValidators(iterable $validators, tao_helpers_form_ private function getSanitizerValidationFeeder(): SanitizerValidationFeederInterface { if (!isset($this->sanitizerValidationFeeder)) { - $serviceManager = $this->serviceManager ?? ServiceManager::getServiceManager(); - $this->sanitizerValidationFeeder = $serviceManager->getContainer()->get(SanitizerValidationFeeder::class); + $this->sanitizerValidationFeeder = $this->getContainer()->get(SanitizerValidationFeeder::class); } return $this->sanitizerValidationFeeder; } + private function getFormModifierManager(): FormModifierManager + { + return $this->getContainer()->get(FormModifierManager::class); + } + private function withServiceManager(array &$options): void { if ( @@ -335,4 +346,11 @@ private function withServiceManager(array &$options): void unset($options[self::WITH_SERVICE_MANAGER]); } + + private function getContainer(): ContainerInterface + { + $serviceManager = $this->serviceManager ?? ServiceManager::getServiceManager(); + + return $serviceManager->getContainer(); + } } diff --git a/manifest.php b/manifest.php index 4d92c7f509..6f5a7ca714 100755 --- a/manifest.php +++ b/manifest.php @@ -43,6 +43,7 @@ use oat\tao\model\featureFlag\FeatureFlagServiceProvider; use oat\tao\model\featureVisibility\FeatureVisibilityServiceProvider; use oat\tao\model\form\DataProvider\FormDataProviderServiceProvider; +use oat\tao\model\form\Modifier\FormModifierServiceProvider; use oat\tao\model\import\ServiceProvider\ImportServiceProvider; use oat\tao\model\LanguageServiceProvider; use oat\tao\model\listener\PropertyServiceProvider; @@ -421,6 +422,7 @@ FormDataProviderServiceProvider::class, PropertyServiceProvider::class, DynamicConfigServiceProvider::class, + FormModifierServiceProvider::class, TranslationServiceProvider::class ], 'middlewares' => [ diff --git a/models/classes/Translation/Form/Modifier/EditTranslationInstanceFormModifier.php b/models/classes/Translation/Form/Modifier/EditTranslationInstanceFormModifier.php new file mode 100644 index 0000000000..112c75b3db --- /dev/null +++ b/models/classes/Translation/Form/Modifier/EditTranslationInstanceFormModifier.php @@ -0,0 +1,58 @@ +ontology = $ontology; + } + + public function supports(Form $form, array $options = []): bool + { + $instanceUri = $form->getValue(self::FORM_INSTANCE_URI); + + if (!$instanceUri) { + return false; + } + + $instance = $this->ontology->getResource($instanceUri); + + // @TODO Check if FF for translation enabled + return $instance->isInstanceOf($this->ontology->getClass(TaoOntology::CLASS_URI_ITEM)) + || $instance->isInstanceOf($this->ontology->getClass(TaoOntology::CLASS_URI_TEST)); + } + + public function modify(Form $form, array $options = []): void + { + $translationTypeValue = $form->getValue(tao_helpers_Uri::encode(TaoOntology::PROPERTY_TRANSLATION_TYPE)); + + $translationTypeRelatedElementUris = [ + TaoOntology::PROPERTY_TRANSLATION_STATUS, + TaoOntology::PROPERTY_TRANSLATION_PROGRESS, + ]; + + if ($translationTypeValue === TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL) { + unset($translationTypeRelatedElementUris[0]); + } + + if ($translationTypeValue === TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION) { + unset($translationTypeRelatedElementUris[1]); + } + + foreach ($translationTypeRelatedElementUris as $elementUri) { + $form->removeElement(tao_helpers_Uri::encode($elementUri)); + } + } +} diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index 6a48917b67..2b371993ea 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -26,8 +26,10 @@ use oat\generis\model\DependencyInjection\ContainerServiceProviderInterface; use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; use oat\oatbox\log\LoggerService; +use oat\tao\model\form\Modifier\FormModifierManager; use oat\tao\model\Translation\Factory\ResourceTranslatableFactory; use oat\tao\model\Translation\Factory\ResourceTranslationFactory; +use oat\tao\model\Translation\Form\Modifier\EditTranslationInstanceFormModifier; use oat\tao\model\Translation\Repository\ResourceTranslatableRepository; use oat\tao\model\Translation\Repository\ResourceTranslationRepository; use oat\tao\model\Translation\Service\ResourceTranslatableRetriever; @@ -93,5 +95,21 @@ public function __invoke(ContainerConfigurator $configurator): void ] ) ->public(); + + $services + ->set(EditTranslationInstanceFormModifier::class, EditTranslationInstanceFormModifier::class) + ->args([ + service(Ontology::SERVICE_ID) + ]); + + $formModifierManager = $services->get(FormModifierManager::class); + $formModifierManager + ->call( + 'add', + [ + service(EditTranslationInstanceFormModifier::class), + EditTranslationInstanceFormModifier::ID, + ] + ); } } diff --git a/models/classes/form/Modifier/FormModifierInterface.php b/models/classes/form/Modifier/FormModifierInterface.php new file mode 100644 index 0000000000..00371a3fd2 --- /dev/null +++ b/models/classes/form/Modifier/FormModifierInterface.php @@ -0,0 +1,14 @@ +extenders)) { + throw new InvalidArgumentException(sprintf('Form extender with id "%s" already exists.', $id)); + } + + $this->extenders[$id] = $extender; + } + + public function modify(Form $form, array $options = []): void + { + $ids = $options[self::OPTIONS_IDS] ?? []; + + $extenders = !empty($ids) + ? array_intersect_key($this->extenders, array_flip($ids)) + : $this->extenders; + + foreach ($extenders as $extender) { + if ($extender->supports($form, $options)) { + $extender->modify($form, $options); + } + } + } +} \ No newline at end of file diff --git a/models/classes/form/Modifier/FormModifierServiceProvider.php b/models/classes/form/Modifier/FormModifierServiceProvider.php new file mode 100644 index 0000000000..a98a6cfa64 --- /dev/null +++ b/models/classes/form/Modifier/FormModifierServiceProvider.php @@ -0,0 +1,18 @@ +services(); + + $services + ->set(FormModifierManager::class, FormModifierManager::class) + ->public(); + } +} \ No newline at end of file diff --git a/models/ontology/tao.rdf b/models/ontology/tao.rdf index 955a63d7d7..fdf7335be5 100644 --- a/models/ontology/tao.rdf +++ b/models/ontology/tao.rdf @@ -343,7 +343,7 @@ @@ -403,7 +403,7 @@ - + From bf4f835cf1439c70630c044a28062ce4784cd562 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Tue, 10 Sep 2024 09:15:12 +0200 Subject: [PATCH 21/50] chore: add dynamic metadata, so it can be extended later --- .../Entity/ResourceMetadataTrait.php | 63 ++++++++++++++++ .../Entity/ResourceTranslatable.php | 58 +++++---------- .../Entity/ResourceTranslation.php | 40 ++--------- .../Entity/ResourceTranslationCollection.php | 10 ++- .../Factory/ResourceTranslatableFactory.php | 41 ++++------- .../Factory/ResourceTranslationFactory.php | 35 ++++----- .../ResourceTranslatableRepository.php | 2 +- .../ResourceTranslationRepository.php | 2 +- .../ResourceMetadataPopulateService.php | 71 +++++++++++++++++++ .../TranslationServiceProvider.php | 12 +++- 10 files changed, 206 insertions(+), 128 deletions(-) create mode 100644 models/classes/Translation/Entity/ResourceMetadataTrait.php create mode 100644 models/classes/Translation/Service/ResourceMetadataPopulateService.php diff --git a/models/classes/Translation/Entity/ResourceMetadataTrait.php b/models/classes/Translation/Entity/ResourceMetadataTrait.php new file mode 100644 index 0000000000..11e9829a0c --- /dev/null +++ b/models/classes/Translation/Entity/ResourceMetadataTrait.php @@ -0,0 +1,63 @@ +metadata[$uri] = [ + 'value' => $value, + 'literal' => $literal + ]; + } + + public function getMetadataValue(string $metadata): ?string + { + if (!empty($this->metadata[$metadata])) { + return $this->metadata[$metadata]['value']; + } + + return null; + } + + public function getMetadataLiteralValue(string $metadata): ?string + { + if (!empty($this->metadata[$metadata])) { + return $this->metadata[$metadata]['literal']; + } + + return null; + } + + public function getMetadata(): array + { + return $this->metadata; + } +} diff --git a/models/classes/Translation/Entity/ResourceTranslatable.php b/models/classes/Translation/Entity/ResourceTranslatable.php index ca5c7759fd..6419ba9ebd 100644 --- a/models/classes/Translation/Entity/ResourceTranslatable.php +++ b/models/classes/Translation/Entity/ResourceTranslatable.php @@ -27,36 +27,15 @@ class ResourceTranslatable implements JsonSerializable { - public const STATUS_READY_FOR_TRANSLATION = 'ready-for-translation'; - public const STATUS_NOT_READY_FOR_TRANSLATION = 'not-ready-for-translation'; - - public const STATUS_MAPPING = [ - TaoOntology::PROPERTY_VALUE_TRANSLATION_STATUS_READY => self::STATUS_READY_FOR_TRANSLATION, - TaoOntology::PROPERTY_VALUE_TRANSLATION_STATUS_NOT_READY => self::STATUS_NOT_READY_FOR_TRANSLATION - ]; - + use ResourceMetadataTrait; + private string $resourceUri; - private string $status; - private string $statusUri; - private string $languageCode; - private string $languageUri; - private string $uniqueId; + private string $resourceLabel; - public function __construct( - string $resourceUri, - string $uniqueId, - string $status, - string $statusUri, - string $languageCode, - string $languageUri - ) + public function __construct(string $resourceUri, string $resourceLabel) { $this->resourceUri = $resourceUri; - $this->uniqueId = $uniqueId; - $this->status = $status; - $this->statusUri = $statusUri; - $this->languageCode = $languageCode; - $this->languageUri = $languageUri; + $this->resourceLabel = $resourceLabel; } public function getResourceUri(): string @@ -64,40 +43,37 @@ public function getResourceUri(): string return $this->resourceUri; } - public function getUniqueId(): string + public function getResourceLabel(): string { - return $this->uniqueId; + return $this->resourceLabel; } - public function getStatus(): string + public function getUniqueId(): ?string { - return $this->status; + return $this->getMetadataValue(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER); } - public function getStatusUri(): string + public function getStatusUri(): ?string { - return $this->statusUri; + return $this->getMetadataValue(TaoOntology::PROPERTY_TRANSLATION_STATUS); } - public function getLanguageCode(): string + public function getLanguageCode(): ?string { - return $this->languageCode; + return $this->getMetadataLiteralValue(TaoOntology::PROPERTY_LANGUAGE); } - public function getLanguageUri(): string + public function getLanguageUri(): ?string { - return $this->languageUri; + return $this->getMetadataValue(TaoOntology::PROPERTY_LANGUAGE); } public function jsonSerialize(): array { return [ 'resourceUri' => $this->getResourceUri(), - 'uniqueId' => $this->getUniqueId(), - 'status' => $this->getStatus(), - 'statusUri' => $this->getStatusUri(), - 'languageCode' => $this->getLanguageCode(), - 'languageUri' => $this->getLanguageUri(), + 'resourceLabel' => $this->getResourceLabel(), + 'metadata' => $this->metadata, ]; } } diff --git a/models/classes/Translation/Entity/ResourceTranslation.php b/models/classes/Translation/Entity/ResourceTranslation.php index b1a1b021f2..0a60a262be 100644 --- a/models/classes/Translation/Entity/ResourceTranslation.php +++ b/models/classes/Translation/Entity/ResourceTranslation.php @@ -27,40 +27,20 @@ class ResourceTranslation implements JsonSerializable { - public const PROGRESS_PENDING = 'pending'; - public const PROGRESS_TRANSLATING = 'translating'; - public const PROGRESS_TRANSLATED = 'translated'; - - public const PROGRESS_MAPPING = [ - TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_PENDING => self::PROGRESS_PENDING, - TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATING => self::PROGRESS_TRANSLATING, - TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED => self::PROGRESS_TRANSLATED, - ]; + use ResourceMetadataTrait; private string $originResourceUri; private string $resourceUri; private string $resourceLabel; - private string $progress; - private string $progressUri; - private string $languageCode; - private string $languageUri; public function __construct( string $originResourceUri, string $resourceUri, - string $resourceLabel, - string $progress, - string $progressUri, - string $languageCode, - string $languageUri + string $resourceLabel ) { $this->originResourceUri = $originResourceUri; $this->resourceUri = $resourceUri; $this->resourceLabel = $resourceLabel; - $this->progress = $progress; - $this->progressUri = $progressUri; - $this->languageCode = $languageCode; - $this->languageUri = $languageUri; } public function getOriginResourceUri(): string @@ -78,24 +58,19 @@ public function getResourceLabel(): string return $this->resourceLabel; } - public function getProgress(): string - { - return $this->progress; - } - public function getProgressUri(): string { - return $this->progressUri; + return $this->getMetadataValue(TaoOntology::PROPERTY_TRANSLATION_PROGRESS); } public function getLanguageCode(): string { - return $this->languageCode; + return $this->getMetadataLiteralValue(TaoOntology::PROPERTY_LANGUAGE); } public function getLanguageUri(): string { - return $this->languageUri; + return $this->getMetadataValue(TaoOntology::PROPERTY_LANGUAGE); } public function jsonSerialize(): array @@ -104,10 +79,7 @@ public function jsonSerialize(): array 'originResourceUri' => $this->getOriginResourceUri(), 'resourceUri' => $this->getResourceUri(), 'resourceLabel' => $this->getResourceLabel(), - 'languageCode' => $this->getLanguageCode(), - 'languageUri' => $this->getLanguageUri(), - 'progress' => $this->getProgress(), - 'progressUri' => $this->getProgressUri(), + 'metadata' => $this->getMetadata(), ]; } } diff --git a/models/classes/Translation/Entity/ResourceTranslationCollection.php b/models/classes/Translation/Entity/ResourceTranslationCollection.php index 5458808c4c..0c1c1b91e6 100644 --- a/models/classes/Translation/Entity/ResourceTranslationCollection.php +++ b/models/classes/Translation/Entity/ResourceTranslationCollection.php @@ -28,14 +28,16 @@ class ResourceTranslationCollection extends ArrayIterator implements JsonSerializable { private string $originResourceUri; + private string $resourceLabel; private string $uniqueId; - public function __construct(string $originResourceUri, string $uniqueId) + public function __construct(string $originResourceUri, string $resourceLabel, string $uniqueId) { parent::__construct(); $this->originResourceUri = $originResourceUri; + $this->resourceLabel = $resourceLabel; $this->uniqueId = $uniqueId; } @@ -49,6 +51,11 @@ public function getOriginResourceUri(): string return $this->originResourceUri; } + public function getOriginResourceLabel(): string + { + return $this->resourceLabel; + } + public function getUniqueId(): string { return $this->uniqueId; @@ -58,6 +65,7 @@ public function jsonSerialize(): array { return [ 'originResourceUri' => $this->getOriginResourceUri(), + 'originResourceLabel' => $this->getOriginResourceLabel(), 'uniqueId' => $this->getUniqueId(), 'translations' => $this->getArrayCopy() ]; diff --git a/models/classes/Translation/Factory/ResourceTranslatableFactory.php b/models/classes/Translation/Factory/ResourceTranslatableFactory.php index f371a4968d..a967afb2a3 100644 --- a/models/classes/Translation/Factory/ResourceTranslatableFactory.php +++ b/models/classes/Translation/Factory/ResourceTranslatableFactory.php @@ -23,44 +23,31 @@ namespace oat\tao\model\Translation\Factory; use core_kernel_classes_Resource; -use oat\generis\model\data\Ontology; use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceTranslatable; +use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; class ResourceTranslatableFactory { - private Ontology $ontology; - - public function __construct(Ontology $ontology) + private ResourceMetadataPopulateService $metadataPopulateService; + private array $metadataUris = [ + TaoOntology::PROPERTY_TRANSLATION_TYPE, + TaoOntology::PROPERTY_UNIQUE_IDENTIFIER, + TaoOntology::PROPERTY_TRANSLATION_STATUS, + TaoOntology::PROPERTY_LANGUAGE + ]; + + public function __construct(ResourceMetadataPopulateService $metadataPopulateService) { - $this->ontology = $ontology; + $this->metadataPopulateService = $metadataPopulateService; } public function create(core_kernel_classes_Resource $originResource): ResourceTranslatable { - $progressProperty = $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_STATUS); - - /** @var core_kernel_classes_Resource $progress */ - $progress = $originResource->getUniquePropertyValue($progressProperty); - - $uniqueId = $originResource->getUniquePropertyValue( - $this->ontology->getProperty(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER) - ); + $resource = new ResourceTranslatable($originResource->getUri(), $originResource->getLabel()); - $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); - $languageProperty = $this->ontology->getProperty(TaoOntology::PROPERTY_LANGUAGE); + $this->metadataPopulateService->populate($resource, $originResource, $this->metadataUris); - /** @var core_kernel_classes_Resource $language */ - $language = $originResource->getUniquePropertyValue($languageProperty); - $languageCode = $language->getUniquePropertyValue($valueProperty); - - return new ResourceTranslatable( - $originResource->getUri(), - (string)$uniqueId, - ResourceTranslatable::STATUS_MAPPING[$progress->getUri()], - $progress->getUri(), - (string)$languageCode, - $language->getUri() - ); + return $resource; } } diff --git a/models/classes/Translation/Factory/ResourceTranslationFactory.php b/models/classes/Translation/Factory/ResourceTranslationFactory.php index eb2aa2b605..41d0aba979 100644 --- a/models/classes/Translation/Factory/ResourceTranslationFactory.php +++ b/models/classes/Translation/Factory/ResourceTranslationFactory.php @@ -23,43 +23,36 @@ namespace oat\tao\model\Translation\Factory; use core_kernel_classes_Resource; -use oat\generis\model\data\Ontology; use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceTranslatable; use oat\tao\model\Translation\Entity\ResourceTranslation; +use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; class ResourceTranslationFactory { - private Ontology $ontology; + private ResourceMetadataPopulateService $metadataPopulateService; + private array $metadataUris = [ + TaoOntology::PROPERTY_TRANSLATION_PROGRESS, + TaoOntology::PROPERTY_LANGUAGE + ]; - public function __construct(Ontology $ontology) + public function __construct(ResourceMetadataPopulateService $metadataPopulateService) { - $this->ontology = $ontology; + $this->metadataPopulateService = $metadataPopulateService; } public function create( ResourceTranslatable $originResource, core_kernel_classes_Resource $translationResource, ): ResourceTranslation { - $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); - $progressProperty = $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_PROGRESS); - $languageProperty = $this->ontology->getProperty(TaoOntology::PROPERTY_LANGUAGE); - - /** @var core_kernel_classes_Resource $language */ - $language = $translationResource->getUniquePropertyValue($languageProperty); - $languageCode = $language->getUniquePropertyValue($valueProperty); - - /** @var core_kernel_classes_Resource $progress */ - $progress = $translationResource->getUniquePropertyValue($progressProperty); - - return new ResourceTranslation( + $resource = new ResourceTranslation( $originResource->getResourceUri(), $translationResource->getUri(), - $translationResource->getLabel(), - ResourceTranslation::PROGRESS_MAPPING[$progress->getUri()], - $progress->getUri(), - (string)$languageCode, - $language->getUri() + $translationResource->getLabel() ); + + $this->metadataPopulateService->populate($resource, $translationResource, $this->metadataUris); + + return $resource; } } diff --git a/models/classes/Translation/Repository/ResourceTranslatableRepository.php b/models/classes/Translation/Repository/ResourceTranslatableRepository.php index be94c0b79a..4df0dbcbb2 100644 --- a/models/classes/Translation/Repository/ResourceTranslatableRepository.php +++ b/models/classes/Translation/Repository/ResourceTranslatableRepository.php @@ -60,7 +60,7 @@ public function find(ResourceTranslatableQuery $query): ResourceTranslatableColl SupportedOperatorHelper::EQUAL, TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL ); - + if (!empty($query->getUniqueIds())) { $searchQuery->addCriterion( TaoOntology::PROPERTY_UNIQUE_IDENTIFIER, diff --git a/models/classes/Translation/Repository/ResourceTranslationRepository.php b/models/classes/Translation/Repository/ResourceTranslationRepository.php index 3e7fcfff6b..4774e9cf18 100644 --- a/models/classes/Translation/Repository/ResourceTranslationRepository.php +++ b/models/classes/Translation/Repository/ResourceTranslationRepository.php @@ -78,7 +78,7 @@ public function find(ResourceTranslationQuery $query): ResourceTranslationCollec $originResource = $resources->current(); $uniqueId = $originResource->getUniqueId(); - $output = new ResourceTranslationCollection($originResourceId, $uniqueId); + $output = new ResourceTranslationCollection($originResourceId, $originResource->getResourceLabel(), $uniqueId); $queryBuilder = $this->complexSearch->query(); $searchQuery = $this->complexSearch->searchType( diff --git a/models/classes/Translation/Service/ResourceMetadataPopulateService.php b/models/classes/Translation/Service/ResourceMetadataPopulateService.php new file mode 100644 index 0000000000..37f3e2d1cb --- /dev/null +++ b/models/classes/Translation/Service/ResourceMetadataPopulateService.php @@ -0,0 +1,71 @@ +ontology = $ontology; + } + + /** + * @param ResourceTranslatable|ResourceTranslation $resource + * @throws core_kernel_persistence_Exception + */ + public function populate($resource, core_kernel_classes_Resource $originResource, array $metadataUris): void + { + $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); + + foreach ($metadataUris as $metadataUri) { + $values = $originResource->getPropertyValues($this->ontology->getProperty($metadataUri)); + + if (empty($values)) { + continue; + } + + $literal = null; + $value = empty($values) ? null : current($values); + + if ($value) { + $literalProperty = $this->ontology->getProperty($value); + $oneValue = $literalProperty->getOnePropertyValue($valueProperty); + + if ($oneValue instanceof core_kernel_classes_Literal) { + $literal = $oneValue->literal; + } + } + + $resource->addMetadata($metadataUri, $value, $literal); + } + } +} diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index 6a48917b67..a04277bb3c 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -30,6 +30,7 @@ use oat\tao\model\Translation\Factory\ResourceTranslationFactory; use oat\tao\model\Translation\Repository\ResourceTranslatableRepository; use oat\tao\model\Translation\Repository\ResourceTranslationRepository; +use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; use oat\tao\model\Translation\Service\ResourceTranslatableRetriever; use oat\tao\model\Translation\Service\ResourceTranslationRetriever; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; @@ -44,6 +45,13 @@ class TranslationServiceProvider implements ContainerServiceProviderInterface public function __invoke(ContainerConfigurator $configurator): void { $services = $configurator->services(); + $services->set(ResourceMetadataPopulateService::class, ResourceMetadataPopulateService::class) + ->args( + [ + service(Ontology::SERVICE_ID), + ] + ); + $services->set(ResourceTranslationRepository::class, ResourceTranslationRepository::class) ->args( [ @@ -67,14 +75,14 @@ public function __invoke(ContainerConfigurator $configurator): void $services->set(ResourceTranslationFactory::class, ResourceTranslationFactory::class) ->args( [ - service(Ontology::SERVICE_ID) + service(ResourceMetadataPopulateService::class) ] ); $services->set(ResourceTranslatableFactory::class, ResourceTranslatableFactory::class) ->args( [ - service(Ontology::SERVICE_ID) + service(ResourceMetadataPopulateService::class) ] ); From 58c3acc50cc9441aa4cf48d53054de922d9b1176 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Tue, 10 Sep 2024 11:35:10 +0200 Subject: [PATCH 22/50] feat: add custom metadata for resources --- .../Entity/ResourceMetadataTrait.php | 11 ++++++++++ .../Entity/ResourceTranslatable.php | 6 +++++- .../Entity/ResourceTranslation.php | 2 ++ .../Entity/ResourceTranslationCollection.php | 1 - .../Factory/ResourceTranslatableFactory.php | 9 +------- .../Factory/ResourceTranslationFactory.php | 7 +------ .../ResourceMetadataPopulateService.php | 21 +++++++++++++++++-- 7 files changed, 39 insertions(+), 18 deletions(-) diff --git a/models/classes/Translation/Entity/ResourceMetadataTrait.php b/models/classes/Translation/Entity/ResourceMetadataTrait.php index 11e9829a0c..29c2c23696 100644 --- a/models/classes/Translation/Entity/ResourceMetadataTrait.php +++ b/models/classes/Translation/Entity/ResourceMetadataTrait.php @@ -24,6 +24,7 @@ trait ResourceMetadataTrait { + private array $metadataUris = []; private array $metadata = []; /** @@ -60,4 +61,14 @@ public function getMetadata(): array { return $this->metadata; } + + public function addMetadataUri(string $uri): void + { + $this->metadataUris = array_unique(array_merge($this->metadataUris, [$uri])); + } + + public function getMetadataUris(): array + { + return $this->metadataUris; + } } diff --git a/models/classes/Translation/Entity/ResourceTranslatable.php b/models/classes/Translation/Entity/ResourceTranslatable.php index 6419ba9ebd..338523d2af 100644 --- a/models/classes/Translation/Entity/ResourceTranslatable.php +++ b/models/classes/Translation/Entity/ResourceTranslatable.php @@ -28,7 +28,7 @@ class ResourceTranslatable implements JsonSerializable { use ResourceMetadataTrait; - + private string $resourceUri; private string $resourceLabel; @@ -36,6 +36,10 @@ public function __construct(string $resourceUri, string $resourceLabel) { $this->resourceUri = $resourceUri; $this->resourceLabel = $resourceLabel; + $this->addMetadataUri(TaoOntology::PROPERTY_TRANSLATION_TYPE); + $this->addMetadataUri(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER); + $this->addMetadataUri(TaoOntology::PROPERTY_TRANSLATION_STATUS); + $this->addMetadataUri(TaoOntology::PROPERTY_LANGUAGE); } public function getResourceUri(): string diff --git a/models/classes/Translation/Entity/ResourceTranslation.php b/models/classes/Translation/Entity/ResourceTranslation.php index 0a60a262be..2d7e94ced4 100644 --- a/models/classes/Translation/Entity/ResourceTranslation.php +++ b/models/classes/Translation/Entity/ResourceTranslation.php @@ -41,6 +41,8 @@ public function __construct( $this->originResourceUri = $originResourceUri; $this->resourceUri = $resourceUri; $this->resourceLabel = $resourceLabel; + $this->addMetadataUri(TaoOntology::PROPERTY_TRANSLATION_PROGRESS); + $this->addMetadataUri(TaoOntology::PROPERTY_LANGUAGE); } public function getOriginResourceUri(): string diff --git a/models/classes/Translation/Entity/ResourceTranslationCollection.php b/models/classes/Translation/Entity/ResourceTranslationCollection.php index 0c1c1b91e6..c0c1ee9f70 100644 --- a/models/classes/Translation/Entity/ResourceTranslationCollection.php +++ b/models/classes/Translation/Entity/ResourceTranslationCollection.php @@ -31,7 +31,6 @@ class ResourceTranslationCollection extends ArrayIterator implements JsonSeriali private string $resourceLabel; private string $uniqueId; - public function __construct(string $originResourceUri, string $resourceLabel, string $uniqueId) { parent::__construct(); diff --git a/models/classes/Translation/Factory/ResourceTranslatableFactory.php b/models/classes/Translation/Factory/ResourceTranslatableFactory.php index a967afb2a3..aefb267bcf 100644 --- a/models/classes/Translation/Factory/ResourceTranslatableFactory.php +++ b/models/classes/Translation/Factory/ResourceTranslatableFactory.php @@ -23,19 +23,12 @@ namespace oat\tao\model\Translation\Factory; use core_kernel_classes_Resource; -use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceTranslatable; use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; class ResourceTranslatableFactory { private ResourceMetadataPopulateService $metadataPopulateService; - private array $metadataUris = [ - TaoOntology::PROPERTY_TRANSLATION_TYPE, - TaoOntology::PROPERTY_UNIQUE_IDENTIFIER, - TaoOntology::PROPERTY_TRANSLATION_STATUS, - TaoOntology::PROPERTY_LANGUAGE - ]; public function __construct(ResourceMetadataPopulateService $metadataPopulateService) { @@ -46,7 +39,7 @@ public function create(core_kernel_classes_Resource $originResource): ResourceTr { $resource = new ResourceTranslatable($originResource->getUri(), $originResource->getLabel()); - $this->metadataPopulateService->populate($resource, $originResource, $this->metadataUris); + $this->metadataPopulateService->populate($resource, $originResource); return $resource; } diff --git a/models/classes/Translation/Factory/ResourceTranslationFactory.php b/models/classes/Translation/Factory/ResourceTranslationFactory.php index 41d0aba979..cfeeac7a46 100644 --- a/models/classes/Translation/Factory/ResourceTranslationFactory.php +++ b/models/classes/Translation/Factory/ResourceTranslationFactory.php @@ -23,7 +23,6 @@ namespace oat\tao\model\Translation\Factory; use core_kernel_classes_Resource; -use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceTranslatable; use oat\tao\model\Translation\Entity\ResourceTranslation; use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; @@ -31,10 +30,6 @@ class ResourceTranslationFactory { private ResourceMetadataPopulateService $metadataPopulateService; - private array $metadataUris = [ - TaoOntology::PROPERTY_TRANSLATION_PROGRESS, - TaoOntology::PROPERTY_LANGUAGE - ]; public function __construct(ResourceMetadataPopulateService $metadataPopulateService) { @@ -51,7 +46,7 @@ public function create( $translationResource->getLabel() ); - $this->metadataPopulateService->populate($resource, $translationResource, $this->metadataUris); + $this->metadataPopulateService->populate($resource, $translationResource); return $resource; } diff --git a/models/classes/Translation/Service/ResourceMetadataPopulateService.php b/models/classes/Translation/Service/ResourceMetadataPopulateService.php index 37f3e2d1cb..8c0875681a 100644 --- a/models/classes/Translation/Service/ResourceMetadataPopulateService.php +++ b/models/classes/Translation/Service/ResourceMetadataPopulateService.php @@ -32,21 +32,38 @@ class ResourceMetadataPopulateService { private Ontology $ontology; + private array $metadata; public function __construct(Ontology $ontology) { $this->ontology = $ontology; } + public function addMetadata(string $resourceType, string $metadataUri): void + { + $this->metadata[$resourceType] = empty($this->metadata[$resourceType]) ? [] : $this->metadata[$resourceType]; + $this->metadata[$resourceType] = array_unique(array_merge($this->metadata[$resourceType], [$metadataUri])); + } + /** * @param ResourceTranslatable|ResourceTranslation $resource * @throws core_kernel_persistence_Exception */ - public function populate($resource, core_kernel_classes_Resource $originResource, array $metadataUris): void + public function populate($resource, core_kernel_classes_Resource $originResource): void { $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); - foreach ($metadataUris as $metadataUri) { + foreach ($originResource->getTypes() as $type) { + if (empty($this->metadata[$type->getUri()])) { + continue; + } + + foreach ($this->metadata[$type->getUri()] as $metadataUri) { + $resource->addMetadataUri($metadataUri); + } + } + + foreach ($resource->getMetadataUris() as $metadataUri) { $values = $originResource->getPropertyValues($this->ontology->getProperty($metadataUri)); if (empty($values)) { From f75c3bec969d39b08a334973f9ace5fff5181db4 Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Tue, 10 Sep 2024 13:22:59 +0300 Subject: [PATCH 23/50] chore: add abstract modifier with ontology to avoid code duplications, add checks if FF enabled, rename modifiers --- .../EditTranslationInstanceFormModifier.php | 58 ----------- .../TranslationInstanceFormModifier.php | 96 +++++++++++++++++++ .../TranslationServiceProvider.php | 12 ++- .../FeatureFlagCheckerInterface.php | 1 + .../form/Modifier/AbstractFormModifier.php | 48 ++++++++++ .../form/Modifier/FormModifierInterface.php | 23 ++++- .../form/Modifier/FormModifierManager.php | 22 ++++- .../Modifier/FormModifierServiceProvider.php | 22 ++++- 8 files changed, 216 insertions(+), 66 deletions(-) delete mode 100644 models/classes/Translation/Form/Modifier/EditTranslationInstanceFormModifier.php create mode 100644 models/classes/Translation/Form/Modifier/TranslationInstanceFormModifier.php create mode 100644 models/classes/form/Modifier/AbstractFormModifier.php diff --git a/models/classes/Translation/Form/Modifier/EditTranslationInstanceFormModifier.php b/models/classes/Translation/Form/Modifier/EditTranslationInstanceFormModifier.php deleted file mode 100644 index 112c75b3db..0000000000 --- a/models/classes/Translation/Form/Modifier/EditTranslationInstanceFormModifier.php +++ /dev/null @@ -1,58 +0,0 @@ -ontology = $ontology; - } - - public function supports(Form $form, array $options = []): bool - { - $instanceUri = $form->getValue(self::FORM_INSTANCE_URI); - - if (!$instanceUri) { - return false; - } - - $instance = $this->ontology->getResource($instanceUri); - - // @TODO Check if FF for translation enabled - return $instance->isInstanceOf($this->ontology->getClass(TaoOntology::CLASS_URI_ITEM)) - || $instance->isInstanceOf($this->ontology->getClass(TaoOntology::CLASS_URI_TEST)); - } - - public function modify(Form $form, array $options = []): void - { - $translationTypeValue = $form->getValue(tao_helpers_Uri::encode(TaoOntology::PROPERTY_TRANSLATION_TYPE)); - - $translationTypeRelatedElementUris = [ - TaoOntology::PROPERTY_TRANSLATION_STATUS, - TaoOntology::PROPERTY_TRANSLATION_PROGRESS, - ]; - - if ($translationTypeValue === TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL) { - unset($translationTypeRelatedElementUris[0]); - } - - if ($translationTypeValue === TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION) { - unset($translationTypeRelatedElementUris[1]); - } - - foreach ($translationTypeRelatedElementUris as $elementUri) { - $form->removeElement(tao_helpers_Uri::encode($elementUri)); - } - } -} diff --git a/models/classes/Translation/Form/Modifier/TranslationInstanceFormModifier.php b/models/classes/Translation/Form/Modifier/TranslationInstanceFormModifier.php new file mode 100644 index 0000000000..f10d95f5b4 --- /dev/null +++ b/models/classes/Translation/Form/Modifier/TranslationInstanceFormModifier.php @@ -0,0 +1,96 @@ +featureFlagChecker = $featureFlagChecker; + } + + public function supports(Form $form, array $options = []): bool + { + $instance = $this->getInstance($form, $options); + + if ($instance === null) { + return false; + } + + return $instance->isInstanceOf($this->ontology->getClass(TaoOntology::CLASS_URI_ITEM)) + || $instance->isInstanceOf($this->ontology->getClass(TaoOntology::CLASS_URI_TEST)); + } + + public function modify(Form $form, array $options = []): void + { + foreach ($this->getTranslationElementsToRemove($form) as $elementUri) { + $form->removeElement(tao_helpers_Uri::encode($elementUri)); + } + } + + private function getTranslationElementsToRemove(Form $form): array + { + if (!$this->featureFlagChecker->isEnabled(FeatureFlagCheckerInterface::FEATURE_TRANSLATION_ENABLED)) { + return [ + TaoOntology::PROPERTY_UNIQUE_IDENTIFIER, + TaoOntology::PROPERTY_LANGUAGE, + TaoOntology::PROPERTY_TRANSLATION_TYPE, + TaoOntology::PROPERTY_TRANSLATION_STATUS, + TaoOntology::PROPERTY_TRANSLATION_PROGRESS, + ]; + } + + $elementsToRemove = []; + $translationTypeValue = $form->getValue(tao_helpers_Uri::encode(TaoOntology::PROPERTY_TRANSLATION_TYPE)); + $isTranslationTypeValueEmpty = empty($translationTypeValue); + + if ( + $isTranslationTypeValueEmpty + || $translationTypeValue === TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL + ) { + $elementsToRemove[] = TaoOntology::PROPERTY_TRANSLATION_PROGRESS; + } + + if ( + $isTranslationTypeValueEmpty + || $translationTypeValue === TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION + ) { + $elementsToRemove[] = TaoOntology::PROPERTY_TRANSLATION_STATUS; + } + + return $elementsToRemove; + } +} diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index 528e21496b..4b952950d6 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -26,10 +26,11 @@ use oat\generis\model\DependencyInjection\ContainerServiceProviderInterface; use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; use oat\oatbox\log\LoggerService; +use oat\tao\model\featureFlag\FeatureFlagChecker; use oat\tao\model\form\Modifier\FormModifierManager; use oat\tao\model\Translation\Factory\ResourceTranslatableFactory; use oat\tao\model\Translation\Factory\ResourceTranslationFactory; -use oat\tao\model\Translation\Form\Modifier\EditTranslationInstanceFormModifier; +use oat\tao\model\Translation\Form\Modifier\TranslationInstanceFormModifier; use oat\tao\model\Translation\Repository\ResourceTranslatableRepository; use oat\tao\model\Translation\Repository\ResourceTranslationRepository; use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; @@ -105,9 +106,10 @@ public function __invoke(ContainerConfigurator $configurator): void ->public(); $services - ->set(EditTranslationInstanceFormModifier::class, EditTranslationInstanceFormModifier::class) + ->set(TranslationInstanceFormModifier::class, TranslationInstanceFormModifier::class) ->args([ - service(Ontology::SERVICE_ID) + service(Ontology::SERVICE_ID), + service(FeatureFlagChecker::class), ]); $formModifierManager = $services->get(FormModifierManager::class); @@ -115,8 +117,8 @@ public function __invoke(ContainerConfigurator $configurator): void ->call( 'add', [ - service(EditTranslationInstanceFormModifier::class), - EditTranslationInstanceFormModifier::ID, + service(TranslationInstanceFormModifier::class), + TranslationInstanceFormModifier::ID, ] ); } diff --git a/models/classes/featureFlag/FeatureFlagCheckerInterface.php b/models/classes/featureFlag/FeatureFlagCheckerInterface.php index f4bb9616d5..2debcb982d 100644 --- a/models/classes/featureFlag/FeatureFlagCheckerInterface.php +++ b/models/classes/featureFlag/FeatureFlagCheckerInterface.php @@ -31,6 +31,7 @@ interface FeatureFlagCheckerInterface public const FEATURE_FLAG_PASSWORD_CHANGE_DISABLED = 'FEATURE_FLAG_PASSWORD_CHANGE_DISABLED'; public const FEATURE_FLAG_TAO_AS_A_TOOL = 'FEATURE_FLAG_TAO_AS_A_TOOL'; public const FEATURE_FLAG_SOLAR_DESIGN_ENABLED = 'FEATURE_FLAG_SOLAR_DESIGN_ENABLED'; + public const FEATURE_TRANSLATION_ENABLED = 'FEATURE_TRANSLATION_ENABLED'; public function isEnabled(string $feature): bool; } diff --git a/models/classes/form/Modifier/AbstractFormModifier.php b/models/classes/form/Modifier/AbstractFormModifier.php new file mode 100644 index 0000000000..7b948d8ddc --- /dev/null +++ b/models/classes/form/Modifier/AbstractFormModifier.php @@ -0,0 +1,48 @@ +ontology = $ontology; + } + + protected function getInstance(tao_helpers_form_Form $form, array $options = []): ?core_kernel_classes_Resource + { + if (($options[self::OPTION_INSTANCE] ?? null) instanceof core_kernel_classes_Resource) { + return $options[self::OPTION_INSTANCE]; + } + + $instanceUri = $form->getValue(self::FORM_INSTANCE_URI); + + return $instanceUri ? $this->ontology->getResource($instanceUri) : null; + } +} \ No newline at end of file diff --git a/models/classes/form/Modifier/FormModifierInterface.php b/models/classes/form/Modifier/FormModifierInterface.php index 00371a3fd2..88ff702d7d 100644 --- a/models/classes/form/Modifier/FormModifierInterface.php +++ b/models/classes/form/Modifier/FormModifierInterface.php @@ -1,5 +1,25 @@ set(FormModifierManager::class, FormModifierManager::class) ->public(); } -} \ No newline at end of file +} From b50c1decd8d367b1815551e8d109f47626d4e6d1 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Tue, 10 Sep 2024 13:34:28 +0200 Subject: [PATCH 24/50] chore: simplify entities and make them agnostic --- ...ionCollection.php => AbstractResource.php} | 49 ++++++------ ...eCollection.php => ResourceCollection.php} | 0 .../Entity/ResourceMetadataTrait.php | 74 ------------------- ...ionTest.php => ResourceCollectionTest.php} | 0 .../Entity/ResourceTranslatableTest.php | 44 +++++++---- .../ResourceTranslationCollectionTest.php | 54 -------------- 6 files changed, 56 insertions(+), 165 deletions(-) rename models/classes/Translation/Entity/{ResourceTranslationCollection.php => AbstractResource.php} (51%) rename models/classes/Translation/Entity/{ResourceTranslatableCollection.php => ResourceCollection.php} (100%) delete mode 100644 models/classes/Translation/Entity/ResourceMetadataTrait.php rename test/unit/models/classes/Translation/Entity/{ResourceTranslatableCollectionTest.php => ResourceCollectionTest.php} (100%) delete mode 100644 test/unit/models/classes/Translation/Entity/ResourceTranslationCollectionTest.php diff --git a/models/classes/Translation/Entity/ResourceTranslationCollection.php b/models/classes/Translation/Entity/AbstractResource.php similarity index 51% rename from models/classes/Translation/Entity/ResourceTranslationCollection.php rename to models/classes/Translation/Entity/AbstractResource.php index c0c1ee9f70..6e43460f5c 100644 --- a/models/classes/Translation/Entity/ResourceTranslationCollection.php +++ b/models/classes/Translation/Entity/AbstractResource.php @@ -22,51 +22,58 @@ namespace oat\tao\model\Translation\Entity; -use ArrayIterator; use JsonSerializable; +use oat\tao\model\TaoOntology; -class ResourceTranslationCollection extends ArrayIterator implements JsonSerializable +class ResourceTranslatable implements JsonSerializable { - private string $originResourceUri; + use ResourceMetadataTrait; + + private string $resourceUri; private string $resourceLabel; - private string $uniqueId; - public function __construct(string $originResourceUri, string $resourceLabel, string $uniqueId) + public function __construct(string $resourceUri, string $resourceLabel) { - parent::__construct(); - - $this->originResourceUri = $originResourceUri; + $this->resourceUri = $resourceUri; $this->resourceLabel = $resourceLabel; - $this->uniqueId = $uniqueId; } - public function addTranslation(ResourceTranslation $resourceTranslation): void + public function getResourceUri(): string { - $this->append($resourceTranslation); + return $this->resourceUri; } - public function getOriginResourceUri(): string + public function getResourceLabel(): string { - return $this->originResourceUri; + return $this->resourceLabel; } - public function getOriginResourceLabel(): string + public function getUniqueId(): ?string { - return $this->resourceLabel; + return $this->getMetadataValue(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER); + } + + public function getStatusUri(): ?string + { + return $this->getMetadataValue(TaoOntology::PROPERTY_TRANSLATION_STATUS); + } + + public function getLanguageCode(): ?string + { + return $this->getMetadataLiteralValue(TaoOntology::PROPERTY_LANGUAGE); } - public function getUniqueId(): string + public function getLanguageUri(): ?string { - return $this->uniqueId; + return $this->getMetadataValue(TaoOntology::PROPERTY_LANGUAGE); } public function jsonSerialize(): array { return [ - 'originResourceUri' => $this->getOriginResourceUri(), - 'originResourceLabel' => $this->getOriginResourceLabel(), - 'uniqueId' => $this->getUniqueId(), - 'translations' => $this->getArrayCopy() + 'resourceUri' => $this->getResourceUri(), + 'resourceLabel' => $this->getResourceLabel(), + 'metadata' => $this->metadata, ]; } } diff --git a/models/classes/Translation/Entity/ResourceTranslatableCollection.php b/models/classes/Translation/Entity/ResourceCollection.php similarity index 100% rename from models/classes/Translation/Entity/ResourceTranslatableCollection.php rename to models/classes/Translation/Entity/ResourceCollection.php diff --git a/models/classes/Translation/Entity/ResourceMetadataTrait.php b/models/classes/Translation/Entity/ResourceMetadataTrait.php deleted file mode 100644 index 29c2c23696..0000000000 --- a/models/classes/Translation/Entity/ResourceMetadataTrait.php +++ /dev/null @@ -1,74 +0,0 @@ -metadata[$uri] = [ - 'value' => $value, - 'literal' => $literal - ]; - } - - public function getMetadataValue(string $metadata): ?string - { - if (!empty($this->metadata[$metadata])) { - return $this->metadata[$metadata]['value']; - } - - return null; - } - - public function getMetadataLiteralValue(string $metadata): ?string - { - if (!empty($this->metadata[$metadata])) { - return $this->metadata[$metadata]['literal']; - } - - return null; - } - - public function getMetadata(): array - { - return $this->metadata; - } - - public function addMetadataUri(string $uri): void - { - $this->metadataUris = array_unique(array_merge($this->metadataUris, [$uri])); - } - - public function getMetadataUris(): array - { - return $this->metadataUris; - } -} diff --git a/test/unit/models/classes/Translation/Entity/ResourceTranslatableCollectionTest.php b/test/unit/models/classes/Translation/Entity/ResourceCollectionTest.php similarity index 100% rename from test/unit/models/classes/Translation/Entity/ResourceTranslatableCollectionTest.php rename to test/unit/models/classes/Translation/Entity/ResourceCollectionTest.php diff --git a/test/unit/models/classes/Translation/Entity/ResourceTranslatableTest.php b/test/unit/models/classes/Translation/Entity/ResourceTranslatableTest.php index 7bd59a6888..b39a27b70d 100644 --- a/test/unit/models/classes/Translation/Entity/ResourceTranslatableTest.php +++ b/test/unit/models/classes/Translation/Entity/ResourceTranslatableTest.php @@ -24,36 +24,48 @@ namespace oat\tao\test\unit\model\Translation\Entity; -use oat\tao\model\Translation\Entity\ResourceTranslatable; +use oat\tao\model\TaoOntology; +use oat\tao\model\Translation\Entity\ResourceTranslation; use PHPUnit\Framework\TestCase; -class ResourceTranslatableTest extends TestCase +class ResourceTranslationTest extends TestCase { - /** @var ResourceTranslatable */ + /** @var ResourceTranslation */ private $sut; public function setUp(): void { - $this->sut = new ResourceTranslatable( - 'resourceUri', - 'uniqueId', - 'status', - 'statusUri', - 'languageCode', - 'languageUri' - ); + $this->sut = new ResourceTranslation('resourceUri', 'resourceLabel'); + $this->sut->setOriginResourceUri('originResourceUri'); + $this->sut->addMetadata(TaoOntology::PROPERTY_LANGUAGE, 'languageUri', 'en-US'); + $this->sut->addMetadata(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER, 'abc123', null); + $this->sut->addMetadata(TaoOntology::PROPERTY_TRANSLATION_PROGRESS, 'progressUri', null); } public function testGetters(): void { + $this->assertSame('en-US', $this->sut->getLanguageCode()); + $this->assertSame('languageUri', $this->sut->getLanguageUri()); + $this->assertSame('progressUri', $this->sut->getProgressUri()); $this->assertSame( [ + 'originResourceUri' => 'originResourceUri', 'resourceUri' => 'resourceUri', - 'uniqueId' => 'uniqueId', - 'status' => 'status', - 'statusUri' => 'statusUri', - 'languageCode' => 'languageCode', - 'languageUri' => 'languageUri' + 'resourceLabel' => 'resourceLabel', + 'metadata' => [ + TaoOntology::PROPERTY_LANGUAGE => [ + 'value' => 'languageUri', + 'literal' => 'en-US', + ], + TaoOntology::PROPERTY_UNIQUE_IDENTIFIER => [ + 'value' => 'abc123', + 'literal' => null, + ], + TaoOntology::PROPERTY_TRANSLATION_PROGRESS => [ + 'value' => 'progressUri', + 'literal' => null, + ] + ], ], $this->sut->jsonSerialize() ); diff --git a/test/unit/models/classes/Translation/Entity/ResourceTranslationCollectionTest.php b/test/unit/models/classes/Translation/Entity/ResourceTranslationCollectionTest.php deleted file mode 100644 index 52d0d2f507..0000000000 --- a/test/unit/models/classes/Translation/Entity/ResourceTranslationCollectionTest.php +++ /dev/null @@ -1,54 +0,0 @@ - - */ - -declare(strict_types=1); - -namespace oat\tao\test\unit\model\Translation\Entity; - -use oat\tao\model\Translation\Entity\ResourceTranslationCollection; -use PHPUnit\Framework\TestCase; - -class ResourceTranslationCollectionTest extends TestCase -{ - /** @var ResourceTranslationCollection */ - private $sut; - - public function setUp(): void - { - $this->sut = new ResourceTranslationCollection( - 'originResourceUri', - 'uniqueId', - ); - } - - public function testGetters(): void - { - $this->assertSame( - [ - 'originResourceUri' => 'originResourceUri', - 'uniqueId' => 'uniqueId', - 'translations' => [], - ], - $this->sut->jsonSerialize() - ); - } -} From 4a9281707994444a02ff5b80e1ccaf1c0af9b10f Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Tue, 10 Sep 2024 13:35:02 +0200 Subject: [PATCH 25/50] chore: simplify entities and make them agnostic --- .../Translation/Entity/AbstractResource.php | 61 ++++++++++++++++--- .../Translation/Entity/ResourceCollection.php | 4 +- .../Entity/ResourceTranslatable.php | 52 +--------------- .../Entity/ResourceTranslation.php | 50 +++------------ .../Factory/ResourceTranslatableFactory.php | 2 + .../Factory/ResourceTranslationFactory.php | 11 ++-- .../ResourceTranslatableRepository.php | 6 +- .../ResourceTranslationRepository.php | 10 +-- .../ResourceMetadataPopulateService.php | 10 +-- .../Service/ResourceTranslatableRetriever.php | 4 +- .../Service/ResourceTranslationRetriever.php | 4 +- .../Entity/ResourceCollectionTest.php | 9 ++- .../Entity/ResourceTranslatableTest.php | 19 +++--- .../Entity/ResourceTranslationTest.php | 39 +++++++----- 14 files changed, 121 insertions(+), 160 deletions(-) diff --git a/models/classes/Translation/Entity/AbstractResource.php b/models/classes/Translation/Entity/AbstractResource.php index 6e43460f5c..78a165c638 100644 --- a/models/classes/Translation/Entity/AbstractResource.php +++ b/models/classes/Translation/Entity/AbstractResource.php @@ -25,10 +25,13 @@ use JsonSerializable; use oat\tao\model\TaoOntology; -class ResourceTranslatable implements JsonSerializable +abstract class AbstractResource implements JsonSerializable { - use ResourceMetadataTrait; - + private array $metadataUris = [ + TaoOntology::PROPERTY_UNIQUE_IDENTIFIER, + TaoOntology::PROPERTY_LANGUAGE + ]; + private array $metadata = []; private string $resourceUri; private string $resourceLabel; @@ -47,17 +50,12 @@ public function getResourceLabel(): string { return $this->resourceLabel; } - + public function getUniqueId(): ?string { return $this->getMetadataValue(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER); } - public function getStatusUri(): ?string - { - return $this->getMetadataValue(TaoOntology::PROPERTY_TRANSLATION_STATUS); - } - public function getLanguageCode(): ?string { return $this->getMetadataLiteralValue(TaoOntology::PROPERTY_LANGUAGE); @@ -68,6 +66,51 @@ public function getLanguageUri(): ?string return $this->getMetadataValue(TaoOntology::PROPERTY_LANGUAGE); } + /** + * @param string|array|null $value + * @param string|null $literal + */ + public function addMetadata(string $uri, $value, $literal): void + { + $this->metadata[$uri] = [ + 'value' => $value, + 'literal' => $literal + ]; + } + + public function getMetadataValue(string $metadata): ?string + { + if (!empty($this->metadata[$metadata])) { + return $this->metadata[$metadata]['value']; + } + + return null; + } + + public function getMetadataLiteralValue(string $metadata): ?string + { + if (!empty($this->metadata[$metadata])) { + return $this->metadata[$metadata]['literal']; + } + + return null; + } + + public function getMetadata(): array + { + return $this->metadata; + } + + public function addMetadataUri(string $uri): void + { + $this->metadataUris = array_unique(array_merge($this->metadataUris, [$uri])); + } + + public function getMetadataUris(): array + { + return $this->metadataUris; + } + public function jsonSerialize(): array { return [ diff --git a/models/classes/Translation/Entity/ResourceCollection.php b/models/classes/Translation/Entity/ResourceCollection.php index bb64c8333d..a9b368a0bd 100644 --- a/models/classes/Translation/Entity/ResourceCollection.php +++ b/models/classes/Translation/Entity/ResourceCollection.php @@ -25,9 +25,9 @@ use ArrayIterator; use JsonSerializable; -class ResourceTranslatableCollection extends ArrayIterator implements JsonSerializable +class ResourceCollection extends ArrayIterator implements JsonSerializable { - public function __construct(ResourceTranslatable ...$resources) + public function __construct(AbstractResource ...$resources) { parent::__construct($resources); } diff --git a/models/classes/Translation/Entity/ResourceTranslatable.php b/models/classes/Translation/Entity/ResourceTranslatable.php index 338523d2af..3821fc3b18 100644 --- a/models/classes/Translation/Entity/ResourceTranslatable.php +++ b/models/classes/Translation/Entity/ResourceTranslatable.php @@ -22,62 +22,12 @@ namespace oat\tao\model\Translation\Entity; -use JsonSerializable; use oat\tao\model\TaoOntology; -class ResourceTranslatable implements JsonSerializable +class ResourceTranslatable extends AbstractResource { - use ResourceMetadataTrait; - - private string $resourceUri; - private string $resourceLabel; - - public function __construct(string $resourceUri, string $resourceLabel) - { - $this->resourceUri = $resourceUri; - $this->resourceLabel = $resourceLabel; - $this->addMetadataUri(TaoOntology::PROPERTY_TRANSLATION_TYPE); - $this->addMetadataUri(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER); - $this->addMetadataUri(TaoOntology::PROPERTY_TRANSLATION_STATUS); - $this->addMetadataUri(TaoOntology::PROPERTY_LANGUAGE); - } - - public function getResourceUri(): string - { - return $this->resourceUri; - } - - public function getResourceLabel(): string - { - return $this->resourceLabel; - } - - public function getUniqueId(): ?string - { - return $this->getMetadataValue(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER); - } - public function getStatusUri(): ?string { return $this->getMetadataValue(TaoOntology::PROPERTY_TRANSLATION_STATUS); } - - public function getLanguageCode(): ?string - { - return $this->getMetadataLiteralValue(TaoOntology::PROPERTY_LANGUAGE); - } - - public function getLanguageUri(): ?string - { - return $this->getMetadataValue(TaoOntology::PROPERTY_LANGUAGE); - } - - public function jsonSerialize(): array - { - return [ - 'resourceUri' => $this->getResourceUri(), - 'resourceLabel' => $this->getResourceLabel(), - 'metadata' => $this->metadata, - ]; - } } diff --git a/models/classes/Translation/Entity/ResourceTranslation.php b/models/classes/Translation/Entity/ResourceTranslation.php index 2d7e94ced4..0b9d0c0b11 100644 --- a/models/classes/Translation/Entity/ResourceTranslation.php +++ b/models/classes/Translation/Entity/ResourceTranslation.php @@ -22,27 +22,15 @@ namespace oat\tao\model\Translation\Entity; -use JsonSerializable; use oat\tao\model\TaoOntology; -class ResourceTranslation implements JsonSerializable +class ResourceTranslation extends AbstractResource { - use ResourceMetadataTrait; - private string $originResourceUri; - private string $resourceUri; - private string $resourceLabel; - public function __construct( - string $originResourceUri, - string $resourceUri, - string $resourceLabel - ) { + public function setOriginResourceUri(string $originResourceUri): void + { $this->originResourceUri = $originResourceUri; - $this->resourceUri = $resourceUri; - $this->resourceLabel = $resourceLabel; - $this->addMetadataUri(TaoOntology::PROPERTY_TRANSLATION_PROGRESS); - $this->addMetadataUri(TaoOntology::PROPERTY_LANGUAGE); } public function getOriginResourceUri(): string @@ -50,38 +38,18 @@ public function getOriginResourceUri(): string return $this->originResourceUri; } - public function getResourceUri(): string - { - return $this->resourceUri; - } - - public function getResourceLabel(): string - { - return $this->resourceLabel; - } - public function getProgressUri(): string { return $this->getMetadataValue(TaoOntology::PROPERTY_TRANSLATION_PROGRESS); } - public function getLanguageCode(): string - { - return $this->getMetadataLiteralValue(TaoOntology::PROPERTY_LANGUAGE); - } - - public function getLanguageUri(): string - { - return $this->getMetadataValue(TaoOntology::PROPERTY_LANGUAGE); - } - public function jsonSerialize(): array { - return [ - 'originResourceUri' => $this->getOriginResourceUri(), - 'resourceUri' => $this->getResourceUri(), - 'resourceLabel' => $this->getResourceLabel(), - 'metadata' => $this->getMetadata(), - ]; + return array_merge( + [ + 'originResourceUri' => $this->getOriginResourceUri() + ], + parent::jsonSerialize(), + ); } } diff --git a/models/classes/Translation/Factory/ResourceTranslatableFactory.php b/models/classes/Translation/Factory/ResourceTranslatableFactory.php index aefb267bcf..b001355745 100644 --- a/models/classes/Translation/Factory/ResourceTranslatableFactory.php +++ b/models/classes/Translation/Factory/ResourceTranslatableFactory.php @@ -23,6 +23,7 @@ namespace oat\tao\model\Translation\Factory; use core_kernel_classes_Resource; +use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceTranslatable; use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; @@ -38,6 +39,7 @@ public function __construct(ResourceMetadataPopulateService $metadataPopulateSer public function create(core_kernel_classes_Resource $originResource): ResourceTranslatable { $resource = new ResourceTranslatable($originResource->getUri(), $originResource->getLabel()); + $resource->addMetadataUri(TaoOntology::PROPERTY_TRANSLATION_STATUS); $this->metadataPopulateService->populate($resource, $originResource); diff --git a/models/classes/Translation/Factory/ResourceTranslationFactory.php b/models/classes/Translation/Factory/ResourceTranslationFactory.php index cfeeac7a46..2c652dc45e 100644 --- a/models/classes/Translation/Factory/ResourceTranslationFactory.php +++ b/models/classes/Translation/Factory/ResourceTranslationFactory.php @@ -23,6 +23,7 @@ namespace oat\tao\model\Translation\Factory; use core_kernel_classes_Resource; +use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceTranslatable; use oat\tao\model\Translation\Entity\ResourceTranslation; use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; @@ -40,14 +41,12 @@ public function create( ResourceTranslatable $originResource, core_kernel_classes_Resource $translationResource, ): ResourceTranslation { - $resource = new ResourceTranslation( - $originResource->getResourceUri(), - $translationResource->getUri(), - $translationResource->getLabel() - ); + $resource = new ResourceTranslation($translationResource->getUri(), $translationResource->getLabel()); + $resource->setOriginResourceUri($originResource->getResourceUri()); + $resource->addMetadataUri(TaoOntology::PROPERTY_TRANSLATION_PROGRESS); $this->metadataPopulateService->populate($resource, $translationResource); - + return $resource; } } diff --git a/models/classes/Translation/Repository/ResourceTranslatableRepository.php b/models/classes/Translation/Repository/ResourceTranslatableRepository.php index 4df0dbcbb2..3e816f0d58 100644 --- a/models/classes/Translation/Repository/ResourceTranslatableRepository.php +++ b/models/classes/Translation/Repository/ResourceTranslatableRepository.php @@ -27,7 +27,7 @@ use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; use oat\search\helper\SupportedOperatorHelper; use oat\tao\model\TaoOntology; -use oat\tao\model\Translation\Entity\ResourceTranslatableCollection; +use oat\tao\model\Translation\Entity\ResourceCollection; use oat\tao\model\Translation\Factory\ResourceTranslatableFactory; use oat\tao\model\Translation\Query\ResourceTranslatableQuery; @@ -47,7 +47,7 @@ public function __construct( $this->ontology = $ontology; } - public function find(ResourceTranslatableQuery $query): ResourceTranslatableCollection + public function find(ResourceTranslatableQuery $query): ResourceCollection { $queryBuilder = $this->complexSearch->query(); $searchQuery = $this->complexSearch->searchType( @@ -85,6 +85,6 @@ public function find(ResourceTranslatableQuery $query): ResourceTranslatableColl $output[] = $this->factory->create($resource); } - return new ResourceTranslatableCollection(...$output); + return new ResourceCollection(...$output); } } diff --git a/models/classes/Translation/Repository/ResourceTranslationRepository.php b/models/classes/Translation/Repository/ResourceTranslationRepository.php index 4774e9cf18..14746aad36 100644 --- a/models/classes/Translation/Repository/ResourceTranslationRepository.php +++ b/models/classes/Translation/Repository/ResourceTranslationRepository.php @@ -28,8 +28,8 @@ use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; use oat\search\helper\SupportedOperatorHelper; use oat\tao\model\TaoOntology; +use oat\tao\model\Translation\Entity\ResourceCollection; use oat\tao\model\Translation\Entity\ResourceTranslatable; -use oat\tao\model\Translation\Entity\ResourceTranslationCollection; use oat\tao\model\Translation\Factory\ResourceTranslationFactory; use oat\tao\model\Translation\Query\ResourceTranslatableQuery; use oat\tao\model\Translation\Query\ResourceTranslationQuery; @@ -58,7 +58,7 @@ public function __construct( $this->logger = $logger; } - public function find(ResourceTranslationQuery $query): ResourceTranslationCollection + public function find(ResourceTranslationQuery $query): ResourceCollection { $originResourceId = $query->getOriginResourceId(); $resources = $this->resourceTranslatableRepository->find( @@ -78,7 +78,7 @@ public function find(ResourceTranslationQuery $query): ResourceTranslationCollec $originResource = $resources->current(); $uniqueId = $originResource->getUniqueId(); - $output = new ResourceTranslationCollection($originResourceId, $originResource->getResourceLabel(), $uniqueId); + $output = []; $queryBuilder = $this->complexSearch->query(); $searchQuery = $this->complexSearch->searchType( @@ -117,7 +117,7 @@ public function find(ResourceTranslationQuery $query): ResourceTranslationCollec continue; } - $output->addTranslation($this->factory->create($originResource, $translationResource)); + $output[] = $this->factory->create($originResource, $translationResource); } catch (Throwable $exception) { $this->logger->warning( sprintf( @@ -131,6 +131,6 @@ public function find(ResourceTranslationQuery $query): ResourceTranslationCollec } } - return $output; + return new ResourceCollection(...$output); } } diff --git a/models/classes/Translation/Service/ResourceMetadataPopulateService.php b/models/classes/Translation/Service/ResourceMetadataPopulateService.php index 8c0875681a..0da9ca556e 100644 --- a/models/classes/Translation/Service/ResourceMetadataPopulateService.php +++ b/models/classes/Translation/Service/ResourceMetadataPopulateService.php @@ -24,10 +24,8 @@ use core_kernel_classes_Literal; use core_kernel_classes_Resource; -use core_kernel_persistence_Exception; use oat\generis\model\data\Ontology; -use oat\tao\model\Translation\Entity\ResourceTranslatable; -use oat\tao\model\Translation\Entity\ResourceTranslation; +use oat\tao\model\Translation\Entity\AbstractResource; class ResourceMetadataPopulateService { @@ -45,11 +43,7 @@ public function addMetadata(string $resourceType, string $metadataUri): void $this->metadata[$resourceType] = array_unique(array_merge($this->metadata[$resourceType], [$metadataUri])); } - /** - * @param ResourceTranslatable|ResourceTranslation $resource - * @throws core_kernel_persistence_Exception - */ - public function populate($resource, core_kernel_classes_Resource $originResource): void + public function populate(AbstractResource $resource, core_kernel_classes_Resource $originResource): void { $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); diff --git a/models/classes/Translation/Service/ResourceTranslatableRetriever.php b/models/classes/Translation/Service/ResourceTranslatableRetriever.php index 006f3d24af..70af704a0f 100644 --- a/models/classes/Translation/Service/ResourceTranslatableRetriever.php +++ b/models/classes/Translation/Service/ResourceTranslatableRetriever.php @@ -23,7 +23,7 @@ namespace oat\tao\model\Translation\Service; use InvalidArgumentException; -use oat\tao\model\Translation\Entity\ResourceTranslatableCollection; +use oat\tao\model\Translation\Entity\ResourceCollection; use oat\tao\model\Translation\Query\ResourceTranslatableQuery; use oat\tao\model\Translation\Repository\ResourceTranslatableRepository; use Psr\Http\Message\ServerRequestInterface; @@ -37,7 +37,7 @@ public function __construct(ResourceTranslatableRepository $resourceTranslationR $this->resourceTranslatableRepository = $resourceTranslationRepository; } - public function getByRequest(ServerRequestInterface $request): ResourceTranslatableCollection + public function getByRequest(ServerRequestInterface $request): ResourceCollection { $queryParams = $request->getQueryParams(); $resourceType = $queryParams['resourceType'] ?? null; diff --git a/models/classes/Translation/Service/ResourceTranslationRetriever.php b/models/classes/Translation/Service/ResourceTranslationRetriever.php index 76c9cce2ef..66163e6b61 100644 --- a/models/classes/Translation/Service/ResourceTranslationRetriever.php +++ b/models/classes/Translation/Service/ResourceTranslationRetriever.php @@ -23,7 +23,7 @@ namespace oat\tao\model\Translation\Service; use InvalidArgumentException; -use oat\tao\model\Translation\Entity\ResourceTranslationCollection; +use oat\tao\model\Translation\Entity\ResourceCollection; use oat\tao\model\Translation\Query\ResourceTranslationQuery; use oat\tao\model\Translation\Repository\ResourceTranslationRepository; use Psr\Http\Message\ServerRequestInterface; @@ -37,7 +37,7 @@ public function __construct(ResourceTranslationRepository $resourceTranslationRe $this->resourceTranslationRepository = $resourceTranslationRepository; } - public function getByRequest(ServerRequestInterface $request): ResourceTranslationCollection + public function getByRequest(ServerRequestInterface $request): ResourceCollection { $queryParams = $request->getQueryParams(); $resourceType = $queryParams['resourceType'] ?? null; diff --git a/test/unit/models/classes/Translation/Entity/ResourceCollectionTest.php b/test/unit/models/classes/Translation/Entity/ResourceCollectionTest.php index 9b73ec0cd6..27fe187f78 100644 --- a/test/unit/models/classes/Translation/Entity/ResourceCollectionTest.php +++ b/test/unit/models/classes/Translation/Entity/ResourceCollectionTest.php @@ -24,17 +24,16 @@ namespace oat\tao\test\unit\model\Translation\Entity; -use oat\tao\model\Translation\Entity\ResourceTranslatableCollection; +use oat\tao\model\Translation\Entity\ResourceCollection; use PHPUnit\Framework\TestCase; -class ResourceTranslatableCollectionTest extends TestCase +class ResourceCollectionTest extends TestCase { - /** @var ResourceTranslatableCollection */ - private $sut; + private ResourceCollection $sut; public function setUp(): void { - $this->sut = new ResourceTranslatableCollection(...[]); + $this->sut = new ResourceCollection(...[]); } public function testGetters(): void diff --git a/test/unit/models/classes/Translation/Entity/ResourceTranslatableTest.php b/test/unit/models/classes/Translation/Entity/ResourceTranslatableTest.php index b39a27b70d..505559a6e6 100644 --- a/test/unit/models/classes/Translation/Entity/ResourceTranslatableTest.php +++ b/test/unit/models/classes/Translation/Entity/ResourceTranslatableTest.php @@ -25,31 +25,28 @@ namespace oat\tao\test\unit\model\Translation\Entity; use oat\tao\model\TaoOntology; -use oat\tao\model\Translation\Entity\ResourceTranslation; +use oat\tao\model\Translation\Entity\ResourceTranslatable; use PHPUnit\Framework\TestCase; -class ResourceTranslationTest extends TestCase +class ResourceTranslatableTest extends TestCase { - /** @var ResourceTranslation */ - private $sut; + private ResourceTranslatable $sut; public function setUp(): void { - $this->sut = new ResourceTranslation('resourceUri', 'resourceLabel'); - $this->sut->setOriginResourceUri('originResourceUri'); + $this->sut = new ResourceTranslatable('resourceUri', 'resourceLabel'); $this->sut->addMetadata(TaoOntology::PROPERTY_LANGUAGE, 'languageUri', 'en-US'); $this->sut->addMetadata(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER, 'abc123', null); - $this->sut->addMetadata(TaoOntology::PROPERTY_TRANSLATION_PROGRESS, 'progressUri', null); + $this->sut->addMetadata(TaoOntology::PROPERTY_TRANSLATION_STATUS, 'statusUri', null); } public function testGetters(): void { $this->assertSame('en-US', $this->sut->getLanguageCode()); $this->assertSame('languageUri', $this->sut->getLanguageUri()); - $this->assertSame('progressUri', $this->sut->getProgressUri()); + $this->assertSame('statusUri', $this->sut->getStatusUri()); $this->assertSame( [ - 'originResourceUri' => 'originResourceUri', 'resourceUri' => 'resourceUri', 'resourceLabel' => 'resourceLabel', 'metadata' => [ @@ -61,8 +58,8 @@ public function testGetters(): void 'value' => 'abc123', 'literal' => null, ], - TaoOntology::PROPERTY_TRANSLATION_PROGRESS => [ - 'value' => 'progressUri', + TaoOntology::PROPERTY_TRANSLATION_STATUS => [ + 'value' => 'statusUri', 'literal' => null, ] ], diff --git a/test/unit/models/classes/Translation/Entity/ResourceTranslationTest.php b/test/unit/models/classes/Translation/Entity/ResourceTranslationTest.php index 0cda827664..51cb86dec4 100644 --- a/test/unit/models/classes/Translation/Entity/ResourceTranslationTest.php +++ b/test/unit/models/classes/Translation/Entity/ResourceTranslationTest.php @@ -24,38 +24,47 @@ namespace oat\tao\test\unit\model\Translation\Entity; +use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceTranslation; use PHPUnit\Framework\TestCase; class ResourceTranslationTest extends TestCase { - /** @var ResourceTranslation */ - private $sut; + private ResourceTranslation $sut; public function setUp(): void { - $this->sut = new ResourceTranslation( - 'originResourceUri', - 'resourceUri', - 'resourceLabel', - 'progress', - 'progressUri', - 'languageCode', - 'languageUri', - ); + $this->sut = new ResourceTranslation('resourceUri', 'resourceLabel'); + $this->sut->setOriginResourceUri('originResourceUri'); + $this->sut->addMetadata(TaoOntology::PROPERTY_LANGUAGE, 'languageUri', 'en-US'); + $this->sut->addMetadata(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER, 'abc123', null); + $this->sut->addMetadata(TaoOntology::PROPERTY_TRANSLATION_PROGRESS, 'progressUri', null); } public function testGetters(): void { + $this->assertSame('en-US', $this->sut->getLanguageCode()); + $this->assertSame('languageUri', $this->sut->getLanguageUri()); + $this->assertSame('progressUri', $this->sut->getProgressUri()); $this->assertSame( [ 'originResourceUri' => 'originResourceUri', 'resourceUri' => 'resourceUri', 'resourceLabel' => 'resourceLabel', - 'languageCode' => 'languageCode', - 'languageUri' => 'languageUri', - 'progress' => 'progress', - 'progressUri' => 'progressUri', + 'metadata' => [ + TaoOntology::PROPERTY_LANGUAGE => [ + 'value' => 'languageUri', + 'literal' => 'en-US', + ], + TaoOntology::PROPERTY_UNIQUE_IDENTIFIER => [ + 'value' => 'abc123', + 'literal' => null, + ], + TaoOntology::PROPERTY_TRANSLATION_PROGRESS => [ + 'value' => 'progressUri', + 'literal' => null, + ] + ], ], $this->sut->jsonSerialize() ); From b93da9f112373ef735347475393a8eb7bcac6e98 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Tue, 10 Sep 2024 15:26:21 +0200 Subject: [PATCH 26/50] chore: use unique ids and parent classes ids instead --- .../Translation/Query/ResourceTranslatableQuery.php | 9 +-------- .../Translation/Query/ResourceTranslationQuery.php | 10 +++++----- .../Repository/ResourceTranslationRepository.php | 12 +++++------- .../Service/ResourceMetadataPopulateService.php | 11 ++++------- .../Service/ResourceTranslatableRetriever.php | 6 ++++-- .../Service/ResourceTranslationRetriever.php | 8 ++++---- 6 files changed, 23 insertions(+), 33 deletions(-) diff --git a/models/classes/Translation/Query/ResourceTranslatableQuery.php b/models/classes/Translation/Query/ResourceTranslatableQuery.php index 9bda0b5fc9..6af00a9d1e 100644 --- a/models/classes/Translation/Query/ResourceTranslatableQuery.php +++ b/models/classes/Translation/Query/ResourceTranslatableQuery.php @@ -25,13 +25,11 @@ class ResourceTranslatableQuery { private string $resourceType; - private array $resourceIds; private array $uniqueIds; - public function __construct(string $resourceType, array $resourceIds = [], array $uniqueIds = []) + public function __construct(string $resourceType, array $uniqueIds = []) { $this->resourceType = $resourceType; - $this->resourceIds = $resourceIds; $this->uniqueIds = $uniqueIds; } @@ -39,11 +37,6 @@ public function getResourceType(): string { return $this->resourceType; } - - public function getResourceIds(): array - { - return $this->resourceIds; - } public function getUniqueIds(): array { diff --git a/models/classes/Translation/Query/ResourceTranslationQuery.php b/models/classes/Translation/Query/ResourceTranslationQuery.php index 628b394c29..4ce04ef7e5 100644 --- a/models/classes/Translation/Query/ResourceTranslationQuery.php +++ b/models/classes/Translation/Query/ResourceTranslationQuery.php @@ -25,13 +25,13 @@ class ResourceTranslationQuery { private string $resourceType; - private string $originResourceId; + private string $uniqueId; private ?string $languageUri; - public function __construct(string $resourceType, string $originResourceId, string $languageUri = null) + public function __construct(string $resourceType, string $uniqueId, string $languageUri = null) { $this->resourceType = $resourceType; - $this->originResourceId = $originResourceId; + $this->uniqueId = $uniqueId; $this->languageUri = $languageUri; } @@ -40,9 +40,9 @@ public function getResourceType(): string return $this->resourceType; } - public function getOriginResourceId(): string + public function getUniqueId(): string { - return $this->originResourceId; + return $this->uniqueId; } public function getLanguageUri(): ?string diff --git a/models/classes/Translation/Repository/ResourceTranslationRepository.php b/models/classes/Translation/Repository/ResourceTranslationRepository.php index 14746aad36..fd9b3d8b6a 100644 --- a/models/classes/Translation/Repository/ResourceTranslationRepository.php +++ b/models/classes/Translation/Repository/ResourceTranslationRepository.php @@ -60,24 +60,22 @@ public function __construct( public function find(ResourceTranslationQuery $query): ResourceCollection { - $originResourceId = $query->getOriginResourceId(); + $uniqueId = $query->getUniqueId(); $resources = $this->resourceTranslatableRepository->find( new ResourceTranslatableQuery( $query->getResourceType(), [ - $originResourceId + $uniqueId ] ) ); if ($resources->count() === 0) { - throw new Exception(sprintf('Translation Origin Resource %s does not exist', $originResourceId)); + throw new Exception(sprintf('Translation Origin Resource %s does not exist', $uniqueId)); } /** @var ResourceTranslatable $originResource */ $originResource = $resources->current(); - - $uniqueId = $originResource->getUniqueId(); $output = []; $queryBuilder = $this->complexSearch->query(); @@ -121,8 +119,8 @@ public function find(ResourceTranslationQuery $query): ResourceCollection } catch (Throwable $exception) { $this->logger->warning( sprintf( - 'Cannot read translation status for [originResourceId=%s, translationResourceId=%s]: %s - %s', - $originResourceId, + 'Cannot read translation status for [uniqueId=%s, translationResourceId=%s]: %s - %s', + $uniqueId, $translationResource->getUri(), $exception->getMessage(), $exception->getTraceAsString() diff --git a/models/classes/Translation/Service/ResourceMetadataPopulateService.php b/models/classes/Translation/Service/ResourceMetadataPopulateService.php index 0da9ca556e..a5830fbe9b 100644 --- a/models/classes/Translation/Service/ResourceMetadataPopulateService.php +++ b/models/classes/Translation/Service/ResourceMetadataPopulateService.php @@ -47,14 +47,11 @@ public function populate(AbstractResource $resource, core_kernel_classes_Resourc { $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); - foreach ($originResource->getTypes() as $type) { - if (empty($this->metadata[$type->getUri()])) { - continue; - } + $parentClasses = $originResource->getParentClassesIds(); + $resourceType = array_pop($parentClasses); - foreach ($this->metadata[$type->getUri()] as $metadataUri) { - $resource->addMetadataUri($metadataUri); - } + foreach ($this->metadata[$resourceType] ?? [] as $metadataUri) { + $resource->addMetadataUri($metadataUri); } foreach ($resource->getMetadataUris() as $metadataUri) { diff --git a/models/classes/Translation/Service/ResourceTranslatableRetriever.php b/models/classes/Translation/Service/ResourceTranslatableRetriever.php index 70af704a0f..071d79e4fa 100644 --- a/models/classes/Translation/Service/ResourceTranslatableRetriever.php +++ b/models/classes/Translation/Service/ResourceTranslatableRetriever.php @@ -41,17 +41,19 @@ public function getByRequest(ServerRequestInterface $request): ResourceCollectio { $queryParams = $request->getQueryParams(); $resourceType = $queryParams['resourceType'] ?? null; - $resourceUris = $queryParams['resourceUris'] ?? []; $uniqueIds = $queryParams['uniqueIds'] ?? []; if (empty($resourceType)) { throw new InvalidArgumentException('Param resourceType is required'); } + if (empty($uniqueIds)) { + throw new InvalidArgumentException('Param uniqueIds is required'); + } + return $this->resourceTranslatableRepository->find( new ResourceTranslatableQuery( $resourceType, - $resourceUris, $uniqueIds ) ); diff --git a/models/classes/Translation/Service/ResourceTranslationRetriever.php b/models/classes/Translation/Service/ResourceTranslationRetriever.php index 66163e6b61..4a10411556 100644 --- a/models/classes/Translation/Service/ResourceTranslationRetriever.php +++ b/models/classes/Translation/Service/ResourceTranslationRetriever.php @@ -41,21 +41,21 @@ public function getByRequest(ServerRequestInterface $request): ResourceCollectio { $queryParams = $request->getQueryParams(); $resourceType = $queryParams['resourceType'] ?? null; - $resourceUri = $queryParams['resourceUri'] ?? null; + $uniqueId = $queryParams['uniqueId'] ?? null; $languageUri = $queryParams['languageUri'] ?? null; if (empty($resourceType)) { throw new InvalidArgumentException('Param resourceType is required'); } - if (empty($resourceUri)) { - throw new InvalidArgumentException('Param resourceUri is required'); + if (empty($uniqueId)) { + throw new InvalidArgumentException('Param uniqueId is required'); } return $this->resourceTranslationRepository->find( new ResourceTranslationQuery( $resourceType, - $resourceUri, + $uniqueId, $languageUri ) ); From 1a91a2df80267a66caf80c17c85297a1ef577645 Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Tue, 10 Sep 2024 17:26:55 +0300 Subject: [PATCH 27/50] chore: use proxies instead of manager --- helpers/form/class.FormContainer.php | 15 +++-- manifest.php | 2 - ...difier.php => TranslationFormModifier.php} | 34 ++++------- .../TranslationServiceProvider.php | 16 +---- .../FeatureFlagCheckerInterface.php | 1 - .../form/Modifier/AbstractFormModifier.php | 25 ++++---- .../form/Modifier/FormModifierInterface.php | 35 ----------- .../form/Modifier/FormModifierManager.php | 58 ------------------- .../Modifier/FormModifierServiceProvider.php | 38 ------------ 9 files changed, 31 insertions(+), 193 deletions(-) rename models/classes/Translation/Form/Modifier/{TranslationInstanceFormModifier.php => TranslationFormModifier.php} (71%) delete mode 100644 models/classes/form/Modifier/FormModifierInterface.php delete mode 100644 models/classes/form/Modifier/FormModifierManager.php delete mode 100644 models/classes/form/Modifier/FormModifierServiceProvider.php diff --git a/helpers/form/class.FormContainer.php b/helpers/form/class.FormContainer.php index eaae9c496b..bd5437a8ad 100644 --- a/helpers/form/class.FormContainer.php +++ b/helpers/form/class.FormContainer.php @@ -26,7 +26,7 @@ use oat\oatbox\service\ServiceManager; use oat\oatbox\validator\ValidatorInterface; -use oat\tao\model\form\Modifier\FormModifierManager; +use oat\tao\model\form\Modifier\AbstractFormModifier; use oat\tao\model\security\xsrf\TokenService; use Psr\Container\ContainerInterface; use tao_helpers_form_FormFactory as FormFactory; @@ -121,8 +121,12 @@ public function __construct(array $data = [], array $options = []) // initialize the elements of the form $this->initElements(); - if (!empty($options[self::FORM_MODIFIERS])) { - $this->getFormModifierManager()->modify($this->form, $options[self::FORM_MODIFIERS]); + foreach ($options[self::FORM_MODIFIERS] ?? [] as $modifierClass) { + $modifier = $this->getContainer()->get($modifierClass); + + if ($modifier instanceof AbstractFormModifier) { + $modifier->modify($this->form, $options); + } } if ($this->form !== null) { @@ -330,11 +334,6 @@ private function getSanitizerValidationFeeder(): SanitizerValidationFeederInterf return $this->sanitizerValidationFeeder; } - private function getFormModifierManager(): FormModifierManager - { - return $this->getContainer()->get(FormModifierManager::class); - } - private function withServiceManager(array &$options): void { if ( diff --git a/manifest.php b/manifest.php index 6f5a7ca714..4d92c7f509 100755 --- a/manifest.php +++ b/manifest.php @@ -43,7 +43,6 @@ use oat\tao\model\featureFlag\FeatureFlagServiceProvider; use oat\tao\model\featureVisibility\FeatureVisibilityServiceProvider; use oat\tao\model\form\DataProvider\FormDataProviderServiceProvider; -use oat\tao\model\form\Modifier\FormModifierServiceProvider; use oat\tao\model\import\ServiceProvider\ImportServiceProvider; use oat\tao\model\LanguageServiceProvider; use oat\tao\model\listener\PropertyServiceProvider; @@ -422,7 +421,6 @@ FormDataProviderServiceProvider::class, PropertyServiceProvider::class, DynamicConfigServiceProvider::class, - FormModifierServiceProvider::class, TranslationServiceProvider::class ], 'middlewares' => [ diff --git a/models/classes/Translation/Form/Modifier/TranslationInstanceFormModifier.php b/models/classes/Translation/Form/Modifier/TranslationFormModifier.php similarity index 71% rename from models/classes/Translation/Form/Modifier/TranslationInstanceFormModifier.php rename to models/classes/Translation/Form/Modifier/TranslationFormModifier.php index f10d95f5b4..b9af7af51d 100644 --- a/models/classes/Translation/Form/Modifier/TranslationInstanceFormModifier.php +++ b/models/classes/Translation/Form/Modifier/TranslationFormModifier.php @@ -22,48 +22,31 @@ namespace oat\tao\model\Translation\Form\Modifier; -use oat\generis\model\data\Ontology; use oat\tao\model\featureFlag\FeatureFlagCheckerInterface; use oat\tao\model\form\Modifier\AbstractFormModifier; use oat\tao\model\TaoOntology; -use tao_helpers_form_Form as Form; +use tao_helpers_form_Form; use tao_helpers_Uri; -class TranslationInstanceFormModifier extends AbstractFormModifier +class TranslationFormModifier extends AbstractFormModifier { - public const ID = 'tao.form_modifier.translation_instance'; - private FeatureFlagCheckerInterface $featureFlagChecker; - public function __construct(Ontology $ontology, FeatureFlagCheckerInterface $featureFlagChecker) + public function __construct(FeatureFlagCheckerInterface $featureFlagChecker) { - parent::__construct($ontology); - $this->featureFlagChecker = $featureFlagChecker; } - public function supports(Form $form, array $options = []): bool - { - $instance = $this->getInstance($form, $options); - - if ($instance === null) { - return false; - } - - return $instance->isInstanceOf($this->ontology->getClass(TaoOntology::CLASS_URI_ITEM)) - || $instance->isInstanceOf($this->ontology->getClass(TaoOntology::CLASS_URI_TEST)); - } - - public function modify(Form $form, array $options = []): void + public function modify(tao_helpers_form_Form $form, array $options = []): void { foreach ($this->getTranslationElementsToRemove($form) as $elementUri) { $form->removeElement(tao_helpers_Uri::encode($elementUri)); } } - private function getTranslationElementsToRemove(Form $form): array + private function getTranslationElementsToRemove(tao_helpers_form_Form $form): array { - if (!$this->featureFlagChecker->isEnabled(FeatureFlagCheckerInterface::FEATURE_TRANSLATION_ENABLED)) { + if (!$this->featureFlagChecker->isEnabled('FEATURE_TRANSLATION_ENABLED')) { return [ TaoOntology::PROPERTY_UNIQUE_IDENTIFIER, TaoOntology::PROPERTY_LANGUAGE, @@ -74,6 +57,11 @@ private function getTranslationElementsToRemove(Form $form): array } $elementsToRemove = []; + + if (!$this->featureFlagChecker->isEnabled('FEATURE_TRANSLATION_DEVELOPER_MODE')) { + $elementsToRemove[] = TaoOntology::PROPERTY_TRANSLATION_TYPE; + } + $translationTypeValue = $form->getValue(tao_helpers_Uri::encode(TaoOntology::PROPERTY_TRANSLATION_TYPE)); $isTranslationTypeValueEmpty = empty($translationTypeValue); diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index 4b952950d6..c5d55c4d5c 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -27,10 +27,9 @@ use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; use oat\oatbox\log\LoggerService; use oat\tao\model\featureFlag\FeatureFlagChecker; -use oat\tao\model\form\Modifier\FormModifierManager; use oat\tao\model\Translation\Factory\ResourceTranslatableFactory; use oat\tao\model\Translation\Factory\ResourceTranslationFactory; -use oat\tao\model\Translation\Form\Modifier\TranslationInstanceFormModifier; +use oat\tao\model\Translation\Form\Modifier\TranslationFormModifier; use oat\tao\model\Translation\Repository\ResourceTranslatableRepository; use oat\tao\model\Translation\Repository\ResourceTranslationRepository; use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; @@ -106,20 +105,9 @@ public function __invoke(ContainerConfigurator $configurator): void ->public(); $services - ->set(TranslationInstanceFormModifier::class, TranslationInstanceFormModifier::class) + ->set(TranslationFormModifier::class, TranslationFormModifier::class) ->args([ - service(Ontology::SERVICE_ID), service(FeatureFlagChecker::class), ]); - - $formModifierManager = $services->get(FormModifierManager::class); - $formModifierManager - ->call( - 'add', - [ - service(TranslationInstanceFormModifier::class), - TranslationInstanceFormModifier::ID, - ] - ); } } diff --git a/models/classes/featureFlag/FeatureFlagCheckerInterface.php b/models/classes/featureFlag/FeatureFlagCheckerInterface.php index 2debcb982d..f4bb9616d5 100644 --- a/models/classes/featureFlag/FeatureFlagCheckerInterface.php +++ b/models/classes/featureFlag/FeatureFlagCheckerInterface.php @@ -31,7 +31,6 @@ interface FeatureFlagCheckerInterface public const FEATURE_FLAG_PASSWORD_CHANGE_DISABLED = 'FEATURE_FLAG_PASSWORD_CHANGE_DISABLED'; public const FEATURE_FLAG_TAO_AS_A_TOOL = 'FEATURE_FLAG_TAO_AS_A_TOOL'; public const FEATURE_FLAG_SOLAR_DESIGN_ENABLED = 'FEATURE_FLAG_SOLAR_DESIGN_ENABLED'; - public const FEATURE_TRANSLATION_ENABLED = 'FEATURE_TRANSLATION_ENABLED'; public function isEnabled(string $feature): bool; } diff --git a/models/classes/form/Modifier/AbstractFormModifier.php b/models/classes/form/Modifier/AbstractFormModifier.php index 7b948d8ddc..752c39bf5e 100644 --- a/models/classes/form/Modifier/AbstractFormModifier.php +++ b/models/classes/form/Modifier/AbstractFormModifier.php @@ -22,27 +22,24 @@ namespace oat\tao\model\form\Modifier; -use core_kernel_classes_Resource; -use oat\generis\model\data\Ontology; use tao_helpers_form_Form; -abstract class AbstractFormModifier implements FormModifierInterface +abstract class AbstractFormModifier { - protected Ontology $ontology; + /** @var AbstractFormModifier[] */ + private array $modifiers = []; - public function __construct(Ontology $ontology) + public function addModifier(AbstractFormModifier $modifier): void { - $this->ontology = $ontology; + if (!in_array($modifier, $this->modifiers, true)) { + $this->modifiers[] = $modifier; + } } - protected function getInstance(tao_helpers_form_Form $form, array $options = []): ?core_kernel_classes_Resource + public function modify(tao_helpers_form_Form $form, array $options = []): void { - if (($options[self::OPTION_INSTANCE] ?? null) instanceof core_kernel_classes_Resource) { - return $options[self::OPTION_INSTANCE]; + foreach ($this->modifiers as $modifier) { + $modifier->modify($form, $options); } - - $instanceUri = $form->getValue(self::FORM_INSTANCE_URI); - - return $instanceUri ? $this->ontology->getResource($instanceUri) : null; } -} \ No newline at end of file +} diff --git a/models/classes/form/Modifier/FormModifierInterface.php b/models/classes/form/Modifier/FormModifierInterface.php deleted file mode 100644 index 88ff702d7d..0000000000 --- a/models/classes/form/Modifier/FormModifierInterface.php +++ /dev/null @@ -1,35 +0,0 @@ -extenders)) { - throw new InvalidArgumentException(sprintf('Form extender with id "%s" already exists.', $id)); - } - - $this->extenders[$id] = $extender; - } - - public function modify(Form $form, array $options = []): void - { - $ids = $options[self::OPTIONS_IDS] ?? []; - - $extenders = !empty($ids) - ? array_intersect_key($this->extenders, array_flip($ids)) - : $this->extenders; - - foreach ($extenders as $extender) { - if ($extender->supports($form, $options)) { - $extender->modify($form, $options); - } - } - } -} diff --git a/models/classes/form/Modifier/FormModifierServiceProvider.php b/models/classes/form/Modifier/FormModifierServiceProvider.php deleted file mode 100644 index 8a276b4dc2..0000000000 --- a/models/classes/form/Modifier/FormModifierServiceProvider.php +++ /dev/null @@ -1,38 +0,0 @@ -services(); - - $services - ->set(FormModifierManager::class, FormModifierManager::class) - ->public(); - } -} From 613eeab4436ab19301bc05768ebb8e3bdc6a8446 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Tue, 10 Sep 2024 17:44:30 +0200 Subject: [PATCH 28/50] chore: add unit tests --- .../ResourceTranslatableFactoryTest.php | 71 ++++++++ .../ResourceTranslationFactoryTest.php | 79 +++++++++ .../ResourceTranslatableRepositoryTest.php | 159 ++++++++++++++++++ .../ResourceTranslationRepositoryTest.php | 159 ++++++++++++++++++ .../ResourceMetadataPopulateServiceTest.php | 116 +++++++++++++ .../ResourceTranslatableRetrieverTest.php | 107 ++++++++++++ .../ResourceTranslationRetrieverTest.php | 108 ++++++++++++ .../ResourceTranslationStatusServiceTest.php | 60 ------- 8 files changed, 799 insertions(+), 60 deletions(-) create mode 100644 test/unit/models/classes/Translation/Factory/ResourceTranslatableFactoryTest.php create mode 100644 test/unit/models/classes/Translation/Factory/ResourceTranslationFactoryTest.php create mode 100644 test/unit/models/classes/Translation/Repository/ResourceTranslatableRepositoryTest.php create mode 100644 test/unit/models/classes/Translation/Repository/ResourceTranslationRepositoryTest.php create mode 100644 test/unit/models/classes/Translation/Service/ResourceMetadataPopulateServiceTest.php create mode 100644 test/unit/models/classes/Translation/Service/ResourceTranslatableRetrieverTest.php create mode 100644 test/unit/models/classes/Translation/Service/ResourceTranslationRetrieverTest.php delete mode 100644 test/unit/models/classes/Translation/Service/ResourceTranslationStatusServiceTest.php diff --git a/test/unit/models/classes/Translation/Factory/ResourceTranslatableFactoryTest.php b/test/unit/models/classes/Translation/Factory/ResourceTranslatableFactoryTest.php new file mode 100644 index 0000000000..81e507fd2d --- /dev/null +++ b/test/unit/models/classes/Translation/Factory/ResourceTranslatableFactoryTest.php @@ -0,0 +1,71 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Factory; + +use core_kernel_classes_Resource; +use oat\tao\model\Translation\Entity\ResourceTranslatable; +use oat\tao\model\Translation\Factory\ResourceTranslatableFactory; +use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; +use oat\tao\model\TaoOntology; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class ResourceTranslatableFactoryTest extends TestCase +{ + private ResourceTranslatableFactory $sut; + + /** @var ResourceMetadataPopulateService|MockObject */ + private $metadataPopulateService; + + /** @var core_kernel_classes_Resource|MockObject */ + private $originResource; + + protected function setUp(): void + { + $this->metadataPopulateService = $this->createMock(ResourceMetadataPopulateService::class); + $this->originResource = $this->createMock(core_kernel_classes_Resource::class); + $this->sut = new ResourceTranslatableFactory($this->metadataPopulateService); + } + + public function testCreateReturnsResourceTranslatable(): void + { + $uri = 'http://example.com/resource'; + $label = 'Test Resource'; + + $this->originResource->method('getUri')->willReturn($uri); + $this->originResource->method('getLabel')->willReturn($label); + + $this->metadataPopulateService + ->expects($this->once()) + ->method('populate'); + + $resource = $this->sut->create($this->originResource); + + $this->assertInstanceOf(ResourceTranslatable::class, $resource); + $this->assertEquals($uri, $resource->getResourceUri()); + $this->assertEquals($label, $resource->getResourceLabel()); + $this->assertContains(TaoOntology::PROPERTY_TRANSLATION_STATUS, $resource->getMetadataUris()); + } +} diff --git a/test/unit/models/classes/Translation/Factory/ResourceTranslationFactoryTest.php b/test/unit/models/classes/Translation/Factory/ResourceTranslationFactoryTest.php new file mode 100644 index 0000000000..dfbc4123ad --- /dev/null +++ b/test/unit/models/classes/Translation/Factory/ResourceTranslationFactoryTest.php @@ -0,0 +1,79 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Factory; + +use core_kernel_classes_Resource; +use oat\tao\model\Translation\Entity\ResourceTranslation; +use oat\tao\model\Translation\Entity\ResourceTranslatable; +use oat\tao\model\Translation\Factory\ResourceTranslationFactory; +use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; +use oat\tao\model\TaoOntology; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class ResourceTranslationFactoryTest extends TestCase +{ + private ResourceTranslationFactory $sut; + + /** @var ResourceMetadataPopulateService|MockObject */ + private $metadataPopulateService; + + /** @var ResourceTranslatable|MockObject */ + private $resourceTranslatable; + + /** @var core_kernel_classes_Resource|MockObject */ + private $translationResource; + + protected function setUp(): void + { + $this->metadataPopulateService = $this->createMock(ResourceMetadataPopulateService::class); + $this->resourceTranslatable = $this->createMock(ResourceTranslatable::class); + $this->translationResource = $this->createMock(core_kernel_classes_Resource::class); + $this->sut = new ResourceTranslationFactory($this->metadataPopulateService); + } + + public function testCreateReturnsResourceTranslation(): void + { + $originUri = 'http://example.com/origin'; + $translationUri = 'http://example.com/translation'; + $label = 'Test Resource'; + + $this->resourceTranslatable->method('getResourceUri')->willReturn($originUri); + $this->translationResource->method('getUri')->willReturn($translationUri); + $this->translationResource->method('getLabel')->willReturn($label); + + $this->metadataPopulateService + ->expects($this->once()) + ->method('populate'); + + $resource = $this->sut->create($this->resourceTranslatable, $this->translationResource); + + $this->assertInstanceOf(ResourceTranslation::class, $resource); + $this->assertEquals($translationUri, $resource->getResourceUri()); + $this->assertEquals($label, $resource->getResourceLabel()); + $this->assertEquals($originUri, $resource->getOriginResourceUri()); + $this->assertContains(TaoOntology::PROPERTY_TRANSLATION_PROGRESS, $resource->getMetadataUris()); + } +} diff --git a/test/unit/models/classes/Translation/Repository/ResourceTranslatableRepositoryTest.php b/test/unit/models/classes/Translation/Repository/ResourceTranslatableRepositoryTest.php new file mode 100644 index 0000000000..5c6ef6bede --- /dev/null +++ b/test/unit/models/classes/Translation/Repository/ResourceTranslatableRepositoryTest.php @@ -0,0 +1,159 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Repository; + +use core_kernel_classes_Resource; +use core_kernel_classes_Class; +use oat\generis\model\data\Ontology; +use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; +use oat\search\QueryBuilder; +use oat\search\base\QueryInterface; +use oat\search\base\SearchGateWayInterface; +use oat\tao\model\Translation\Entity\ResourceCollection; +use oat\tao\model\Translation\Entity\ResourceTranslatable; +use oat\tao\model\Translation\Factory\ResourceTranslatableFactory; +use oat\tao\model\Translation\Query\ResourceTranslatableQuery; +use oat\tao\model\Translation\Repository\ResourceTranslatableRepository; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class ResourceTranslatableRepositoryTest extends TestCase +{ + private ResourceTranslatableRepository $sut; + + /** @var Ontology|MockObject */ + private $ontology; + + /** @var ComplexSearchService|MockObject */ + private $complexSearch; + + /** @var ResourceTranslatableFactory|MockObject */ + private $factory; + + /** @var ResourceTranslatableQuery|MockObject */ + private $query; + + /** @var QueryBuilder|MockObject */ + private $queryBuilder; + + /** @var QueryInterface|MockObject */ + private $searchQuery; + + /** @var SearchGateWayInterface|MockObject */ + private $gateway; + + /** @var core_kernel_classes_Class|MockObject */ + private $resourceTypeClass; + + protected function setUp(): void + { + $this->ontology = $this->createMock(Ontology::class); + $this->complexSearch = $this->createMock(ComplexSearchService::class); + $this->factory = $this->createMock(ResourceTranslatableFactory::class); + $this->query = $this->createMock(ResourceTranslatableQuery::class); + $this->queryBuilder = $this->createMock(QueryBuilder::class); + $this->searchQuery = $this->createMock(QueryInterface::class); + $this->gateway = $this->createMock(SearchGateWayInterface::class); + $this->resourceTypeClass = $this->createMock(core_kernel_classes_Class::class); + + $this->sut = new ResourceTranslatableRepository( + $this->ontology, + $this->complexSearch, + $this->factory + ); + } + + public function testFindReturnsResourceCollection(): void + { + $resourceType = 'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject'; + $uniqueIds = + [ + 'id1', + 'id2' + ]; + $resource1 = $this->createMock(core_kernel_classes_Resource::class); + $resource2 = $this->createMock(core_kernel_classes_Resource::class); + $translatable1 = $this->createMock(ResourceTranslatable::class); + $translatable2 = $this->createMock(ResourceTranslatable::class); + + $this->query + ->method('getResourceType') + ->willReturn($resourceType); + $this->query + ->method('getUniqueIds') + ->willReturn($uniqueIds); + + $this->complexSearch + ->method('query') + ->willReturn($this->queryBuilder); + $this->complexSearch + ->method('searchType') + ->willReturn($this->searchQuery); + $this->complexSearch + ->method('getGateway') + ->willReturn($this->gateway); + + $this->gateway + ->expects($this->once()) + ->method('search') + ->with($this->queryBuilder) + ->willReturn( + [ + $resource1, + $resource2 + ] + ); + + $this->ontology + ->method('getClass') + ->with($resourceType) + ->willReturn($this->resourceTypeClass); + + $resource1 + ->method('isInstanceOf') + ->with($this->resourceTypeClass) + ->willReturn(true); + $resource2 + ->method('isInstanceOf') + ->with($this->resourceTypeClass) + ->willReturn(true); + + $this->factory + ->method('create') + ->willReturnMap( + [ + [$resource1, $translatable1], + [$resource2, $translatable2] + ] + ); + + $result = $this->sut->find($this->query); + + $this->assertInstanceOf(ResourceCollection::class, $result); + $this->assertCount(2, $result); + $this->assertContains($translatable1, $result); + $this->assertContains($translatable2, $result); + } +} \ No newline at end of file diff --git a/test/unit/models/classes/Translation/Repository/ResourceTranslationRepositoryTest.php b/test/unit/models/classes/Translation/Repository/ResourceTranslationRepositoryTest.php new file mode 100644 index 0000000000..b27f4dc5e9 --- /dev/null +++ b/test/unit/models/classes/Translation/Repository/ResourceTranslationRepositoryTest.php @@ -0,0 +1,159 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Repository; + +use core_kernel_classes_Class; +use core_kernel_classes_Resource; +use Exception; +use oat\generis\model\data\Ontology; +use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; +use oat\search\QueryBuilder; +use oat\search\base\QueryInterface; +use oat\search\base\SearchGateWayInterface; +use oat\tao\model\Translation\Entity\ResourceCollection; +use oat\tao\model\Translation\Entity\ResourceTranslatable; +use oat\tao\model\Translation\Entity\ResourceTranslation; +use oat\tao\model\Translation\Factory\ResourceTranslationFactory; +use oat\tao\model\Translation\Query\ResourceTranslatableQuery; +use oat\tao\model\Translation\Query\ResourceTranslationQuery; +use oat\tao\model\Translation\Repository\ResourceTranslatableRepository; +use oat\tao\model\Translation\Repository\ResourceTranslationRepository; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; + +class ResourceTranslationRepositoryTest extends TestCase +{ + private ResourceTranslationRepository $sut; + + /** @var Ontology|MockObject */ + private $ontology; + + /** @var ComplexSearchService|MockObject */ + private $complexSearch; + + /** @var ResourceTranslatableRepository|MockObject */ + private $resourceTranslatableRepository; + + /** @var ResourceTranslationFactory|MockObject */ + private $factory; + + /** @var LoggerInterface|MockObject */ + private $logger; + + /** @var QueryBuilder|MockObject */ + private $queryBuilder; + + /** @var QueryInterface|MockObject */ + private $searchQuery; + + /** @var SearchGateWayInterface|MockObject */ + private $gateway; + + /** @var core_kernel_classes_Class|MockObject */ + private $resourceTypeClass; + + protected function setUp(): void + { + $this->ontology = $this->createMock(Ontology::class); + $this->complexSearch = $this->createMock(ComplexSearchService::class); + $this->resourceTranslatableRepository = $this->createMock(ResourceTranslatableRepository::class); + $this->factory = $this->createMock(ResourceTranslationFactory::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->queryBuilder = $this->createMock(QueryBuilder::class); + $this->searchQuery = $this->createMock(QueryInterface::class); + $this->gateway = $this->createMock(SearchGateWayInterface::class); + $this->resourceTypeClass = $this->createMock(core_kernel_classes_Class::class); + + $this->sut = new ResourceTranslationRepository( + $this->ontology, + $this->complexSearch, + $this->resourceTranslatableRepository, + $this->factory, + $this->logger + ); + } + + public function testFindReturnsResourceCollection(): void + { + $resourceType = 'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject'; + $uniqueId = 'id1'; + $translatable1 = $this->createMock(ResourceTranslatable::class); + $translationResource1 = $this->createMock(core_kernel_classes_Resource::class); + $translation1 = $this->createMock(ResourceTranslation::class); + + $query = $this->createMock(ResourceTranslationQuery::class); + $query->method('getResourceType')->willReturn($resourceType); + $query->method('getUniqueId')->willReturn($uniqueId); + + $this->resourceTranslatableRepository + ->method('find') + ->willReturn(new ResourceCollection($translatable1)); + + $this->complexSearch + ->method('query') + ->willReturn($this->queryBuilder); + $this->complexSearch + ->method('searchType') + ->willReturn($this->searchQuery); + $this->complexSearch + ->method('getGateway') + ->willReturn($this->gateway); + + $this->gateway + ->expects($this->once()) + ->method('search') + ->with($this->queryBuilder) + ->willReturn( + [ + $translationResource1 + ] + ); + + $this->ontology + ->method('getClass') + ->with($resourceType) + ->willReturn($this->resourceTypeClass); + + $translationResource1 + ->method('isInstanceOf') + ->with($this->resourceTypeClass) + ->willReturn(true); + + $this->factory + ->method('create') + ->willReturnMap( + [ + [$translatable1, $translationResource1, $translation1] + ] + ); + + $result = $this->sut->find($query); + + $this->assertInstanceOf(ResourceCollection::class, $result); + $this->assertCount(1, $result); + $this->assertContains($translation1, $result); + } +} \ No newline at end of file diff --git a/test/unit/models/classes/Translation/Service/ResourceMetadataPopulateServiceTest.php b/test/unit/models/classes/Translation/Service/ResourceMetadataPopulateServiceTest.php new file mode 100644 index 0000000000..178a26abb9 --- /dev/null +++ b/test/unit/models/classes/Translation/Service/ResourceMetadataPopulateServiceTest.php @@ -0,0 +1,116 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Service; + +use core_kernel_classes_Literal; +use core_kernel_classes_Property; +use core_kernel_classes_Resource; +use oat\generis\model\data\Ontology; +use oat\tao\model\Translation\Entity\AbstractResource; +use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class ResourceMetadataPopulateServiceTest extends TestCase +{ + private ResourceMetadataPopulateService $sut; + + /** @var Ontology|MockObject */ + private $ontology; + + /** @var AbstractResource|MockObject */ + private $resource; + + /** @var core_kernel_classes_Resource|MockObject */ + private $originResource; + + public function setUp(): void + { + $this->ontology = $this->createMock(Ontology::class); + $this->resource = $this->createMock(AbstractResource::class); + $this->originResource = $this->createMock(core_kernel_classes_Resource::class); + $this->sut = new ResourceMetadataPopulateService($this->ontology); + } + + public function testPopulateAddsMetadataToResource(): void + { + $resourceType = 'testResourceType'; + $metadataUri = 'http://example.com/metadata'; + $valuePropertyUri = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'; + $value = 'testValue'; + $literalValue = 'testLiteral'; + $valueProperty = $this->createMock(core_kernel_classes_Property::class); + $literal = $this->createMock(core_kernel_classes_Literal::class); + $literal->literal = $literalValue; + + $this->sut->addMetadata($resourceType, $metadataUri); + + $this->originResource + ->method('getParentClassesIds') + ->willReturn([$resourceType]); + + $this->originResource + ->method('getPropertyValues') + ->willReturn([$value]); + + $this->resource + ->expects($this->once()) + ->method('addMetadataUri') + ->with($metadataUri); + + $this->ontology->method('getProperty')->willReturnMap( + [ + [ + $metadataUri, + $valueProperty + ], + [ + $value, + $valueProperty + ], + [ + $valuePropertyUri, + $valueProperty + ], + ] + ); + + $valueProperty + ->method('getOnePropertyValue') + ->willReturn($literal); + + $this->resource + ->expects($this->once()) + ->method('addMetadata') + ->with($metadataUri, $value, $literalValue); + + $this->resource + ->expects($this->once()) + ->method('getMetadataUris') + ->willReturn([$metadataUri]); + + $this->sut->populate($this->resource, $this->originResource); + } +} \ No newline at end of file diff --git a/test/unit/models/classes/Translation/Service/ResourceTranslatableRetrieverTest.php b/test/unit/models/classes/Translation/Service/ResourceTranslatableRetrieverTest.php new file mode 100644 index 0000000000..d0ad69fbd8 --- /dev/null +++ b/test/unit/models/classes/Translation/Service/ResourceTranslatableRetrieverTest.php @@ -0,0 +1,107 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Service; + +use InvalidArgumentException; +use oat\tao\model\Translation\Entity\ResourceCollection; +use oat\tao\model\Translation\Query\ResourceTranslatableQuery; +use oat\tao\model\Translation\Repository\ResourceTranslatableRepository; +use oat\tao\model\Translation\Service\ResourceTranslatableRetriever; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use Psr\Http\Message\ServerRequestInterface; + +class ResourceTranslatableRetrieverTest extends TestCase +{ + private ResourceTranslatableRetriever $sut; + + /** @var ResourceTranslatableRepository|MockObject */ + private $resourceTranslatableRepository; + + /** @var MockObject|ServerRequestInterface */ + private $request; + + public function setUp(): void + { + $this->resourceTranslatableRepository = $this->createMock(ResourceTranslatableRepository::class); + $this->request = $this->createMock(ServerRequestInterface::class); + $this->sut = new ResourceTranslatableRetriever($this->resourceTranslatableRepository); + } + + public function testGetByRequest(): void + { + $this->request->expects($this->once()) + ->method('getQueryParams') + ->willReturn( + [ + 'resourceType' => 'resourceType', + 'uniqueIds' => ['uniqueId'], + ] + ); + + $result = new ResourceCollection(); + + $this->resourceTranslatableRepository + ->expects($this->once()) + ->method('find') + ->with( + new ResourceTranslatableQuery( + 'resourceType', + ['uniqueId'] + ) + ) + ->willReturn($result); + + $this->assertSame($result, $this->sut->getByRequest($this->request)); + } + + public function testGetByRequestRequiresResourceType(): void + { + $this->request->expects($this->once()) + ->method('getQueryParams') + ->willReturn([]); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Param resourceType is required'); + + $this->sut->getByRequest($this->request); + } + + public function testGetByRequestRequiresUniqueIds(): void + { + $this->request->expects($this->once()) + ->method('getQueryParams') + ->willReturn( + [ + 'resourceType' => 'resourceType', + ] + ); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Param uniqueIds is required'); + + $this->sut->getByRequest($this->request); + } +} diff --git a/test/unit/models/classes/Translation/Service/ResourceTranslationRetrieverTest.php b/test/unit/models/classes/Translation/Service/ResourceTranslationRetrieverTest.php new file mode 100644 index 0000000000..83925dd179 --- /dev/null +++ b/test/unit/models/classes/Translation/Service/ResourceTranslationRetrieverTest.php @@ -0,0 +1,108 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Service; + +use InvalidArgumentException; +use oat\tao\model\Translation\Entity\ResourceCollection; +use oat\tao\model\Translation\Query\ResourceTranslationQuery; +use oat\tao\model\Translation\Repository\ResourceTranslationRepository; +use oat\tao\model\Translation\Service\ResourceTranslationRetriever; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use Psr\Http\Message\ServerRequestInterface; + +class ResourceTranslationStatusServiceTest extends TestCase +{ + private ResourceTranslationRetriever $sut; + + /** @var ResourceTranslationRepository|MockObject */ + private $resourceTranslationRepository; + + /** @var MockObject|ServerRequestInterface */ + private $request; + + public function setUp(): void + { + $this->resourceTranslationRepository = $this->createMock(ResourceTranslationRepository::class); + $this->request = $this->createMock(ServerRequestInterface::class); + $this->sut = new ResourceTranslationRetriever($this->resourceTranslationRepository); + } + + public function testGetByRequest(): void + { + $this->request->expects($this->once()) + ->method('getQueryParams') + ->willReturn( + [ + 'resourceType' => 'resourceType', + 'uniqueId' => 'uniqueId', + ] + ); + + $result = new ResourceCollection(); + + $this->resourceTranslationRepository + ->expects($this->once()) + ->method('find') + ->with( + new ResourceTranslationQuery( + 'resourceType', + 'uniqueId', + null + ) + ) + ->willReturn($result); + + $this->assertSame($result, $this->sut->getByRequest($this->request)); + } + + public function testGetByRequestRequiresResourceType(): void + { + $this->request->expects($this->once()) + ->method('getQueryParams') + ->willReturn([]); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Param resourceType is required'); + + $this->sut->getByRequest($this->request); + } + + public function testGetByRequestRequiresUniqueId(): void + { + $this->request->expects($this->once()) + ->method('getQueryParams') + ->willReturn( + [ + 'resourceType' => 'resourceType', + ] + ); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Param uniqueId is required'); + + $this->sut->getByRequest($this->request); + } +} diff --git a/test/unit/models/classes/Translation/Service/ResourceTranslationStatusServiceTest.php b/test/unit/models/classes/Translation/Service/ResourceTranslationStatusServiceTest.php deleted file mode 100644 index 2ead75189e..0000000000 --- a/test/unit/models/classes/Translation/Service/ResourceTranslationStatusServiceTest.php +++ /dev/null @@ -1,60 +0,0 @@ - - */ - -declare(strict_types=1); - -namespace oat\tao\test\unit\model\Translation\Service; - -use oat\generis\model\data\Ontology; -use oat\tao\model\Translation\Query\ResourceTranslationQuery; -use oat\tao\model\Translation\Service\ResourceTranslationRepository; -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; - -class ResourceTranslationStatusServiceTest extends TestCase -{ - /** @var ResourceTranslationRepository */ - private $sut; - - /** @var Ontology|MockObject */ - private $ontology; - - public function setUp(): void - { - $this->ontology = $this->createMock(Ontology::class); - - $this->sut = new ResourceTranslationRepository($this->ontology); - } - - public function testGetStatus(): void - { - $status = $this->sut->find(new ResourceTranslationQuery('abc123')); - - $this->assertSame( - [ - 'originResourceUri' => 'abc123', - 'translations' => [], - ], - $status->jsonSerialize() - ); - } -} From b3e2fdb01d7e960ef81c9e03b6b9c6b0adc6e534 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Wed, 11 Sep 2024 08:04:14 +0200 Subject: [PATCH 29/50] chore: remove syntax error --- .../classes/Translation/Factory/ResourceTranslationFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/classes/Translation/Factory/ResourceTranslationFactory.php b/models/classes/Translation/Factory/ResourceTranslationFactory.php index 2c652dc45e..057fc07794 100644 --- a/models/classes/Translation/Factory/ResourceTranslationFactory.php +++ b/models/classes/Translation/Factory/ResourceTranslationFactory.php @@ -39,7 +39,7 @@ public function __construct(ResourceMetadataPopulateService $metadataPopulateSer public function create( ResourceTranslatable $originResource, - core_kernel_classes_Resource $translationResource, + core_kernel_classes_Resource $translationResource ): ResourceTranslation { $resource = new ResourceTranslation($translationResource->getUri(), $translationResource->getLabel()); $resource->setOriginResourceUri($originResource->getResourceUri()); From 9056d64d871150916fe0c1867338644fa1846e78 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Wed, 11 Sep 2024 08:18:58 +0200 Subject: [PATCH 30/50] chore: fix cs --- models/classes/TaoOntology.php | 21 ++++++++++++------- .../Translation/Entity/AbstractResource.php | 2 +- .../ResourceTranslationException.php | 2 +- .../Factory/ResourceTranslationFactory.php | 2 +- .../Query/ResourceTranslationQuery.php | 2 +- .../ResourceTranslatableRepository.php | 4 ++-- .../ResourceTranslationRepository.php | 10 ++++----- .../classes/menu/SectionVisibilityFilter.php | 2 +- .../ResourceTranslatableRepositoryTest.php | 5 ++--- .../ResourceTranslationRepositoryTest.php | 2 +- .../ResourceMetadataPopulateServiceTest.php | 2 +- 11 files changed, 30 insertions(+), 24 deletions(-) diff --git a/models/classes/TaoOntology.php b/models/classes/TaoOntology.php index 5f420cb0da..d87c454079 100644 --- a/models/classes/TaoOntology.php +++ b/models/classes/TaoOntology.php @@ -119,17 +119,24 @@ interface TaoOntology public const LANGUAGES_CLASS_URI = 'http://www.tao.lu/Ontologies/TAO.rdf#Languages'; public const PROPERTY_TRANSLATION_TYPE = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationType'; - public const PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationTypeOriginal'; - public const PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationTypeTranslation'; + public const PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL = + 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationTypeOriginal'; + public const PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION = + 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationTypeTranslation'; public const PROPERTY_TRANSLATION_PROGRESS = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgress'; - public const PROPERTY_VALUE_TRANSLATION_PROGRESS_PENDING = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgressStatusPending'; - public const PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATING = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgressStatusTranslating'; - public const PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgressStatusTranslated'; + public const PROPERTY_VALUE_TRANSLATION_PROGRESS_PENDING = + 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgressStatusPending'; + public const PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATING = + 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgressStatusTranslating'; + public const PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED = + 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationProgressStatusTranslated'; public const PROPERTY_TRANSLATION_STATUS = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationStatus'; - public const PROPERTY_VALUE_TRANSLATION_STATUS_READY = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationStatusReadyForTranslation'; - public const PROPERTY_VALUE_TRANSLATION_STATUS_NOT_READY = 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationStatusNotReadyForTranslation'; + public const PROPERTY_VALUE_TRANSLATION_STATUS_READY = + 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationStatusReadyForTranslation'; + public const PROPERTY_VALUE_TRANSLATION_STATUS_NOT_READY = + 'http://www.tao.lu/Ontologies/TAO.rdf#TranslationStatusNotReadyForTranslation'; public const PROPERTY_UNIQUE_IDENTIFIER = 'http://www.tao.lu/Ontologies/TAO.rdf#UniqueIdentifier'; public const PROPERTY_LANGUAGE = 'http://www.tao.lu/Ontologies/TAO.rdf#Language'; diff --git a/models/classes/Translation/Entity/AbstractResource.php b/models/classes/Translation/Entity/AbstractResource.php index 78a165c638..ee0d83bfe5 100644 --- a/models/classes/Translation/Entity/AbstractResource.php +++ b/models/classes/Translation/Entity/AbstractResource.php @@ -50,7 +50,7 @@ public function getResourceLabel(): string { return $this->resourceLabel; } - + public function getUniqueId(): ?string { return $this->getMetadataValue(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER); diff --git a/models/classes/Translation/Exception/ResourceTranslationException.php b/models/classes/Translation/Exception/ResourceTranslationException.php index 4dd7935c6d..4b993b0cdb 100644 --- a/models/classes/Translation/Exception/ResourceTranslationException.php +++ b/models/classes/Translation/Exception/ResourceTranslationException.php @@ -26,4 +26,4 @@ class ResourceTranslationException extends UserErrorException { -} \ No newline at end of file +} diff --git a/models/classes/Translation/Factory/ResourceTranslationFactory.php b/models/classes/Translation/Factory/ResourceTranslationFactory.php index 057fc07794..70f3ee2045 100644 --- a/models/classes/Translation/Factory/ResourceTranslationFactory.php +++ b/models/classes/Translation/Factory/ResourceTranslationFactory.php @@ -47,6 +47,6 @@ public function create( $this->metadataPopulateService->populate($resource, $translationResource); - return $resource; + return $resource; } } diff --git a/models/classes/Translation/Query/ResourceTranslationQuery.php b/models/classes/Translation/Query/ResourceTranslationQuery.php index 4ce04ef7e5..d009fc4334 100644 --- a/models/classes/Translation/Query/ResourceTranslationQuery.php +++ b/models/classes/Translation/Query/ResourceTranslationQuery.php @@ -39,7 +39,7 @@ public function getResourceType(): string { return $this->resourceType; } - + public function getUniqueId(): string { return $this->uniqueId; diff --git a/models/classes/Translation/Repository/ResourceTranslatableRepository.php b/models/classes/Translation/Repository/ResourceTranslatableRepository.php index 3e816f0d58..02c2f5e558 100644 --- a/models/classes/Translation/Repository/ResourceTranslatableRepository.php +++ b/models/classes/Translation/Repository/ResourceTranslatableRepository.php @@ -68,7 +68,7 @@ public function find(ResourceTranslatableQuery $query): ResourceCollection $query->getUniqueIds() ); } - + $queryBuilder->setCriteria($searchQuery); $result = $this->complexSearch->getGateway()->search($queryBuilder); @@ -81,7 +81,7 @@ public function find(ResourceTranslatableQuery $query): ResourceCollection if (!$resource->isInstanceOf($resourceTypeClass)) { continue; } - + $output[] = $this->factory->create($resource); } diff --git a/models/classes/Translation/Repository/ResourceTranslationRepository.php b/models/classes/Translation/Repository/ResourceTranslationRepository.php index fd9b3d8b6a..0a377cd38b 100644 --- a/models/classes/Translation/Repository/ResourceTranslationRepository.php +++ b/models/classes/Translation/Repository/ResourceTranslationRepository.php @@ -45,7 +45,7 @@ class ResourceTranslationRepository private ResourceTranslatableRepository $resourceTranslatableRepository; public function __construct( - Ontology $ontology, + Ontology $ontology, ComplexSearchService $complexSearch, ResourceTranslatableRepository $resourceTranslatableRepository, ResourceTranslationFactory $resourceTranslationFactory, @@ -69,7 +69,7 @@ public function find(ResourceTranslationQuery $query): ResourceCollection ] ) ); - + if ($resources->count() === 0) { throw new Exception(sprintf('Translation Origin Resource %s does not exist', $uniqueId)); } @@ -94,15 +94,15 @@ public function find(ResourceTranslationQuery $query): ResourceCollection SupportedOperatorHelper::EQUAL, $uniqueId ); - + if ($query->getLanguageUri()) { $searchQuery->addCriterion( TaoOntology::PROPERTY_LANGUAGE, SupportedOperatorHelper::EQUAL, $query->getLanguageUri() - ); + ); } - + $queryBuilder->setCriteria($searchQuery); $result = $this->complexSearch->getGateway()->search($queryBuilder); diff --git a/models/classes/menu/SectionVisibilityFilter.php b/models/classes/menu/SectionVisibilityFilter.php index c14a75932f..a2c932cf21 100644 --- a/models/classes/menu/SectionVisibilityFilter.php +++ b/models/classes/menu/SectionVisibilityFilter.php @@ -82,7 +82,7 @@ public function createSectionPath(array $segments): string { return implode(self::SECTION_PATH_SEPARATOR, $segments); } - + public function hideSectionByFeatureFlag(string $sectionPath, string $featureFlag): void { $options = $this->getOption(SectionVisibilityFilter::OPTION_FEATURE_FLAG_SECTIONS_TO_HIDE, []); diff --git a/test/unit/models/classes/Translation/Repository/ResourceTranslatableRepositoryTest.php b/test/unit/models/classes/Translation/Repository/ResourceTranslatableRepositoryTest.php index 5c6ef6bede..a6ce9ba37e 100644 --- a/test/unit/models/classes/Translation/Repository/ResourceTranslatableRepositoryTest.php +++ b/test/unit/models/classes/Translation/Repository/ResourceTranslatableRepositoryTest.php @@ -88,8 +88,7 @@ protected function setUp(): void public function testFindReturnsResourceCollection(): void { $resourceType = 'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject'; - $uniqueIds = - [ + $uniqueIds = [ 'id1', 'id2' ]; @@ -156,4 +155,4 @@ public function testFindReturnsResourceCollection(): void $this->assertContains($translatable1, $result); $this->assertContains($translatable2, $result); } -} \ No newline at end of file +} diff --git a/test/unit/models/classes/Translation/Repository/ResourceTranslationRepositoryTest.php b/test/unit/models/classes/Translation/Repository/ResourceTranslationRepositoryTest.php index b27f4dc5e9..92c519ee6e 100644 --- a/test/unit/models/classes/Translation/Repository/ResourceTranslationRepositoryTest.php +++ b/test/unit/models/classes/Translation/Repository/ResourceTranslationRepositoryTest.php @@ -156,4 +156,4 @@ public function testFindReturnsResourceCollection(): void $this->assertCount(1, $result); $this->assertContains($translation1, $result); } -} \ No newline at end of file +} diff --git a/test/unit/models/classes/Translation/Service/ResourceMetadataPopulateServiceTest.php b/test/unit/models/classes/Translation/Service/ResourceMetadataPopulateServiceTest.php index 178a26abb9..b199c632db 100644 --- a/test/unit/models/classes/Translation/Service/ResourceMetadataPopulateServiceTest.php +++ b/test/unit/models/classes/Translation/Service/ResourceMetadataPopulateServiceTest.php @@ -113,4 +113,4 @@ public function testPopulateAddsMetadataToResource(): void $this->sut->populate($this->resource, $this->originResource); } -} \ No newline at end of file +} From 0c23fb8e5c17d61d53f5e5a55cf4b8ece16cb93f Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Wed, 11 Sep 2024 09:39:13 +0200 Subject: [PATCH 31/50] chore: add unit tests --- .../ResourceTranslatableRepository.php | 6 +-- .../Query/ResourceTranslatableQueryTest.php | 42 +++++++++++++++ .../Query/ResourceTranslationQueryTest.php | 54 +++++++++++++++++++ 3 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 test/unit/models/classes/Translation/Query/ResourceTranslatableQueryTest.php create mode 100644 test/unit/models/classes/Translation/Query/ResourceTranslationQueryTest.php diff --git a/models/classes/Translation/Repository/ResourceTranslatableRepository.php b/models/classes/Translation/Repository/ResourceTranslatableRepository.php index 02c2f5e558..3e12ae523d 100644 --- a/models/classes/Translation/Repository/ResourceTranslatableRepository.php +++ b/models/classes/Translation/Repository/ResourceTranslatableRepository.php @@ -78,11 +78,9 @@ public function find(ResourceTranslatableQuery $query): ResourceCollection /** @var core_kernel_classes_Resource $resource */ foreach ($result as $resource) { - if (!$resource->isInstanceOf($resourceTypeClass)) { - continue; + if ($resource->isInstanceOf($resourceTypeClass)) { + $output[] = $this->factory->create($resource); } - - $output[] = $this->factory->create($resource); } return new ResourceCollection(...$output); diff --git a/test/unit/models/classes/Translation/Query/ResourceTranslatableQueryTest.php b/test/unit/models/classes/Translation/Query/ResourceTranslatableQueryTest.php new file mode 100644 index 0000000000..c719536262 --- /dev/null +++ b/test/unit/models/classes/Translation/Query/ResourceTranslatableQueryTest.php @@ -0,0 +1,42 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Query; + +use oat\tao\model\Translation\Query\ResourceTranslatableQuery; +use PHPUnit\Framework\TestCase; + +class ResourceTranslatableQueryTest extends TestCase +{ + public function testConstructorAndGetters(): void + { + $resourceType = 'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject'; + $uniqueIds = ['id1', 'id2']; + + $query = new ResourceTranslatableQuery($resourceType, $uniqueIds); + + $this->assertSame($resourceType, $query->getResourceType()); + $this->assertSame($uniqueIds, $query->getUniqueIds()); + } +} diff --git a/test/unit/models/classes/Translation/Query/ResourceTranslationQueryTest.php b/test/unit/models/classes/Translation/Query/ResourceTranslationQueryTest.php new file mode 100644 index 0000000000..c75684e3a1 --- /dev/null +++ b/test/unit/models/classes/Translation/Query/ResourceTranslationQueryTest.php @@ -0,0 +1,54 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Query; + +use oat\tao\model\TaoOntology; +use oat\tao\model\Translation\Query\ResourceTranslationQuery; +use PHPUnit\Framework\TestCase; + +class ResourceTranslationQueryTest extends TestCase +{ + public function testConstructorAndGetters(): void + { + $resourceType = 'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject'; + $uniqueId = 'id1'; + $languageUri = TaoOntology::PROPERTY_LANGUAGE; + + $query = new ResourceTranslationQuery($resourceType, $uniqueId, $languageUri); + + $this->assertSame($resourceType, $query->getResourceType()); + $this->assertSame($uniqueId, $query->getUniqueId()); + $this->assertSame($languageUri, $query->getLanguageUri()); + } + + public function testConstructorWithoutLanguageUri(): void + { + $query = new ResourceTranslationQuery( + 'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject', + 'id1' + ); + $this->assertNull($query->getLanguageUri()); + } +} From f1a4ee52027429fe5d0affa7b214f9de41639fe2 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Wed, 11 Sep 2024 11:00:50 +0200 Subject: [PATCH 32/50] chore: add api documentation --- doc/taoApi.yml | 120 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/doc/taoApi.yml b/doc/taoApi.yml index d02290b0c6..5118ec4d2b 100644 --- a/doc/taoApi.yml +++ b/doc/taoApi.yml @@ -5,6 +5,60 @@ info: version: v1 paths: + /tao/Translation/translations: + get: + summary: Return a list of translations for a given translatable resource + parameters: + - in: query + name: resourceType + required: true + schema: + type: string + description: The RDF resource type + - in: query + name: uniqueId + required: true + schema: + type: string + description: The uniqueId of a translation + - in: query + name: languageUri + required: false + schema: + type: string + description: The RDF language URI + responses: + 200: + $ref: '#/components/responses/TranslationsResponse' + 400: + $ref: '#/components/responses/BadRequestResponse' + 500: + $ref: '#/components/responses/InternalServerErrorResponse' + /tao/Translation/translatable: + get: + summary: Return translatable resources + parameters: + - in: query + name: resourceType + required: true + schema: + type: string + description: The RDF resource type + - in: query + name: uniqueIds + required: true + schema: + type: array + items: + type: string + description: The uniqueIds for a translatable + responses: + 200: + $ref: '#/components/responses/TranslationsResponse' + 400: + $ref: '#/components/responses/BadRequestResponse' + 500: + $ref: '#/components/responses/InternalServerErrorResponse' /tao/Languages/index: get: summary: Get a list of available languages in the TAO platform @@ -46,6 +100,60 @@ paths: $ref: '#/components/responses/InternalServerErrorResponse' components: schemas: + Translations: + properties: + success: + type: boolean + example: true + data: + type: object + properties: + resources: + type: array + items: + properties: + originResourceUri: + type: string + resourceUri: + type: string + resourceLabel: + type: string + metadata: + type: object + properties: + key: + type: object + properties: + value: + type: string + literal: + type: string + Translatable: + properties: + success: + type: boolean + example: true + data: + type: object + properties: + resources: + type: array + items: + properties: + resourceUri: + type: string + resourceLabel: + type: string + metadata: + type: object + properties: + key: + type: object + properties: + value: + type: string + literal: + type: string ResourceRelationResource: description: 'A resource related to another resources' type: object @@ -104,6 +212,18 @@ components: message: type: string responses: + TranslationsResponse: + description: The list of translations + content: + application/json: + schema: + $ref: '#/components/schemas/Translations' + TranslatableResponse: + description: The list of translatable + content: + application/json: + schema: + $ref: '#/components/schemas/Translatable' ResourceRelationsResponse: description: Bad request content: From 7c082f73b2b520f0aba252573636f5d08b668dc7 Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Wed, 11 Sep 2024 12:21:31 +0300 Subject: [PATCH 33/50] chore: add unit tests for modifier --- .../Modifier/TranslationFormModifierTest.php | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 test/unit/models/classes/Translation/Form/Modifier/TranslationFormModifierTest.php diff --git a/test/unit/models/classes/Translation/Form/Modifier/TranslationFormModifierTest.php b/test/unit/models/classes/Translation/Form/Modifier/TranslationFormModifierTest.php new file mode 100644 index 0000000000..b58fc5071a --- /dev/null +++ b/test/unit/models/classes/Translation/Form/Modifier/TranslationFormModifierTest.php @@ -0,0 +1,152 @@ +form = $this->createMock(tao_helpers_form_Form::class); + $this->featureFlagChecker = $this->createMock(FeatureFlagCheckerInterface::class); + $this->sut = new TranslationFormModifier($this->featureFlagChecker); + } + + public function testModifyTranslationDisabled(): void + { + $this->featureFlagChecker + ->expects($this->once()) + ->method('isEnabled') + ->with('FEATURE_TRANSLATION_ENABLED') + ->willReturn(false); + + $this->form + ->expects($this->exactly(5)) + ->method('removeElement') + ->withConsecutive( + [tao_helpers_Uri::encode(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER)], + [tao_helpers_Uri::encode(TaoOntology::PROPERTY_LANGUAGE)], + [tao_helpers_Uri::encode(TaoOntology::PROPERTY_TRANSLATION_TYPE)], + [tao_helpers_Uri::encode(TaoOntology::PROPERTY_TRANSLATION_STATUS)], + [tao_helpers_Uri::encode(TaoOntology::PROPERTY_TRANSLATION_PROGRESS)], + ); + + $this->sut->modify($this->form); + } + + /** + * @dataProvider modifyTranslationEnabledDataProvider + */ + public function testModifyTranslationEnabled(bool $developerMode, ?string $type, array $removeElements): void + { + $this->featureFlagChecker + ->expects($this->exactly(2)) + ->method('isEnabled') + ->withConsecutive( + ['FEATURE_TRANSLATION_ENABLED'], + ['FEATURE_TRANSLATION_DEVELOPER_MODE'], + ) + ->willReturnOnConsecutiveCalls(true, $developerMode); + + $this->form + ->expects($this->once()) + ->method('getValue') + ->with(tao_helpers_Uri::encode(TaoOntology::PROPERTY_TRANSLATION_TYPE)) + ->willReturn($type); + + $this->form + ->expects($this->exactly(count($removeElements))) + ->method('removeElement') + ->withConsecutive(...array_map(static fn ($element) => [tao_helpers_Uri::encode($element)], $removeElements)); + + $this->sut->modify($this->form); + } + + private function modifyTranslationEnabledDataProvider(): array + { + return [ + 'Developer Mode enabled and no type provided' => [ + 'developerMode' => true, + 'type' => null, + 'removeElements' => [ + TaoOntology::PROPERTY_TRANSLATION_PROGRESS, + TaoOntology::PROPERTY_TRANSLATION_STATUS, + ], + ], + 'Developer Mode enabled and type original' => [ + 'developerMode' => true, + 'type' => TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL, + 'removeElements' => [ + TaoOntology::PROPERTY_TRANSLATION_PROGRESS, + ], + ], + 'Developer Mode enabled and type translation' => [ + 'developerMode' => true, + 'type' => TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION, + 'removeElements' => [ + TaoOntology::PROPERTY_TRANSLATION_STATUS, + ], + ], + 'Developer Mode disabled and no type provided' => [ + 'developerMode' => false, + 'type' => null, + 'removeElements' => [ + TaoOntology::PROPERTY_TRANSLATION_TYPE, + TaoOntology::PROPERTY_TRANSLATION_PROGRESS, + TaoOntology::PROPERTY_TRANSLATION_STATUS, + ], + ], + 'Developer Mode disabled and type original' => [ + 'developerMode' => false, + 'type' => TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL, + 'removeElements' => [ + TaoOntology::PROPERTY_TRANSLATION_TYPE, + TaoOntology::PROPERTY_TRANSLATION_PROGRESS, + ], + ], + 'Developer Mode disabled and type translation' => [ + 'developerMode' => false, + 'type' => TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION, + 'removeElements' => [ + TaoOntology::PROPERTY_TRANSLATION_TYPE, + TaoOntology::PROPERTY_TRANSLATION_STATUS, + ], + ], + ]; + } +} From 85c4fe86cff0bfc03085d5063f7944d26ede7cfc Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Wed, 11 Sep 2024 16:17:55 +0300 Subject: [PATCH 34/50] chore: add setValue and setElementValue method to forms --- helpers/form/class.Form.php | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/helpers/form/class.Form.php b/helpers/form/class.Form.php index 8caac01ad8..cd3724a0e3 100644 --- a/helpers/form/class.Form.php +++ b/helpers/form/class.Form.php @@ -666,20 +666,37 @@ public function setValues($values) foreach ($values as $key => $value) { foreach ($this->elements as $element) { if ($element->getName() === $key) { - if ( - $element instanceof tao_helpers_form_elements_Checkbox || - (method_exists($element, 'setValues') && is_array($value)) - ) { - $element->setValues($value); - } else { - $element->setValue($value); - } + $this->setElementValue($element, $value); + break; } } } } + public function setElementValue(tao_helpers_form_FormElement $element, $value): void + { + if ( + $element instanceof tao_helpers_form_elements_Checkbox + || (method_exists($element, 'setValues') && is_array($value)) + ) { + $element->setValues($value); + + return; + } + + $element->setValue($value); + } + + public function setValue(string $name, $value): void + { + $element = $this->getElement($name); + + if ($element) { + $this->setElementValue($element, $value); + } + } + /** * Disables the whole form */ From 6bbba71351a64a16f45981c38b997a27009838ed Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Wed, 11 Sep 2024 17:10:07 +0300 Subject: [PATCH 35/50] feat: introduce property aliases --- models/ontology/tao.rdf | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/models/ontology/tao.rdf b/models/ontology/tao.rdf index fdf7335be5..9b933bd752 100644 --- a/models/ontology/tao.rdf +++ b/models/ontology/tao.rdf @@ -17,6 +17,14 @@ + + + + + + + + @@ -400,6 +408,7 @@ + @@ -407,6 +416,7 @@ + @@ -415,6 +425,7 @@ + @@ -423,6 +434,7 @@ + @@ -431,6 +443,7 @@ + From 3de82d25fcdf734659fe5b8e4c2091b7c0ff1c1f Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Wed, 11 Sep 2024 17:34:25 +0200 Subject: [PATCH 36/50] feat: add possibility to translate resources agnostically --- actions/class.Translation.php | 21 ++ .../Command/CreateTranslationCommand.php | 52 ++++ .../ResourceTranslationException.php | 2 +- .../Service/TranslationCreationService.php | 230 ++++++++++++++++ .../TranslationServiceProvider.php | 30 +++ .../Command/CreateTranslationCommandTest.php | 44 +++ .../TranslationCreationServiceTest.php | 252 ++++++++++++++++++ 7 files changed, 630 insertions(+), 1 deletion(-) create mode 100644 models/classes/Translation/Command/CreateTranslationCommand.php create mode 100644 models/classes/Translation/Service/TranslationCreationService.php create mode 100644 test/unit/models/classes/Translation/Command/CreateTranslationCommandTest.php create mode 100644 test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php diff --git a/actions/class.Translation.php b/actions/class.Translation.php index af311dd78d..27d13515ac 100644 --- a/actions/class.Translation.php +++ b/actions/class.Translation.php @@ -23,11 +23,27 @@ use oat\tao\model\http\HttpJsonResponseTrait; use oat\tao\model\Translation\Service\ResourceTranslationRetriever; use oat\tao\model\Translation\Service\ResourceTranslatableRetriever; +use oat\tao\model\Translation\Service\TranslationCreationService; class tao_actions_Translation extends tao_actions_CommonModule { use HttpJsonResponseTrait; + public function translate(): void + { + try { + $newResource = $this->getTranslationCreationService()->createByRequest($this->getPsrRequest()); + + $this->setSuccessJsonResponse( + [ + 'resourceUri' => $newResource->getUri() + ] + ); + } catch (Throwable $exception) { + $this->setErrorJsonResponse($exception->getMessage()); + } + } + public function translations(): void { try { @@ -59,4 +75,9 @@ private function getResourceTranslatableRetriever(): ResourceTranslatableRetriev { return $this->getServiceManager()->getContainer()->get(ResourceTranslatableRetriever::class); } + + private function getTranslationCreationService(): TranslationCreationService + { + return $this->getServiceManager()->getContainer()->get(TranslationCreationService::class); + } } diff --git a/models/classes/Translation/Command/CreateTranslationCommand.php b/models/classes/Translation/Command/CreateTranslationCommand.php new file mode 100644 index 0000000000..01bb70a7e8 --- /dev/null +++ b/models/classes/Translation/Command/CreateTranslationCommand.php @@ -0,0 +1,52 @@ +resourceType = $resourceType; + $this->uniqueId = $uniqueId; + $this->languageUri = $languageUri; + } + + public function getResourceType(): string + { + return $this->resourceType; + } + + public function getUniqueId(): string + { + return $this->uniqueId; + } + + public function getLanguageUri(): string + { + return $this->languageUri; + } +} diff --git a/models/classes/Translation/Exception/ResourceTranslationException.php b/models/classes/Translation/Exception/ResourceTranslationException.php index 4b993b0cdb..c341028182 100644 --- a/models/classes/Translation/Exception/ResourceTranslationException.php +++ b/models/classes/Translation/Exception/ResourceTranslationException.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace oat\tao\model\Translation\Entity; +namespace oat\tao\model\Translation\Exception; use oat\tao\model\exceptions\UserErrorException; diff --git a/models/classes/Translation/Service/TranslationCreationService.php b/models/classes/Translation/Service/TranslationCreationService.php new file mode 100644 index 0000000000..4f20d65bb8 --- /dev/null +++ b/models/classes/Translation/Service/TranslationCreationService.php @@ -0,0 +1,230 @@ +ontology = $ontology; + $this->resourceTranslatableRepository = $resourceTranslatableRepository; + $this->resourceTranslationRepository = $resourceTranslationRepository; + $this->languageRepository = $languageRepository; + $this->logger = $logger; + } + + public function setOntologyClassService(string $resourceType, OntologyClassService $ontologyClassService): void + { + $this->ontologyClassServices[$resourceType] = $ontologyClassService; + } + + public function addPostCreation(string $resourceType, callable $callable): void + { + $this->callables[$resourceType] = $this->callables[$resourceType] ?? []; + $this->callables[$resourceType][] = $callable; + } + + public function createByRequest(ServerRequestInterface $request): core_kernel_classes_Resource + { + $requestParams = $request->getParsedBody(); + + $requiredParams = [ + 'resourceType', + 'uniqueId', + 'languageUri', + ]; + + foreach ($requiredParams as $requiredParam) { + if (empty($requestParams[$requiredParam])) { + throw new ResourceTranslationException( + sprintf( + 'Parameter %s is mandatory', + $requiredParam + ) + ); + } + } + + return $this->create( + new CreateTranslationCommand( + $requestParams['resourceType'], + $requestParams['uniqueId'], + $requestParams['languageUri'] + ) + ); + } + + public function create(CreateTranslationCommand $command): core_kernel_classes_Resource + { + try { + return $this->doCreate($command); + } catch (Throwable $exception) { + $this->logger->error( + sprintf( + 'Could not translate [uniqueId=%s, resourceType=%s, language=%s] (%s): %s', + $command->getUniqueId(), + $command->getResourceType(), + $command->getLanguageUri(), + get_class($exception), + $exception->getMessage() + ) + ); + + throw $exception; + } + } + + private function doCreate(CreateTranslationCommand $command): core_kernel_classes_Resource + { + $translations = $this->resourceTranslationRepository->find( + new ResourceTranslationQuery( + $command->getResourceType(), + $command->getUniqueId(), + $command->getLanguageUri() + ) + ); + + if ($translations->count() > 0) { + throw new ResourceTranslationException( + sprintf( + 'Translation already exists for [uniqueId=%s, locale=%s]', + $command->getUniqueId(), + $command->getLanguageUri() + ) + ); + } + + $resources = $this->resourceTranslatableRepository->find( + new ResourceTranslatableQuery( + $command->getResourceType(), + [$command->getUniqueId()] + ) + ); + + if ($resources->count() === 0) { + throw new ResourceTranslationException( + sprintf( + 'There is not translatable resource for [uniqueId=%s]', + $command->getUniqueId() + ) + ); + } + + $existingLanguages = $this->languageRepository->findAvailableLanguagesByUsage(); + $language = null; + + /** @var Language $language */ + foreach ($existingLanguages as $existingLanguage) { + if ($existingLanguage->getUri() === $command->getLanguageUri()) { + $language = $existingLanguage; + } + } + + if (!$language) { + throw new ResourceTranslationException( + sprintf( + 'Language %s does not exist', + $command->getLanguageUri() + ) + ); + } + + /** @var ResourceTranslatable $resource */ + $resource = $resources->current(); + + $instance = $this->ontology->getResource($resource->getResourceUri()); + $types = $instance->getTypes(); + $type = array_pop($types); + + $clonedInstance = $this->getOntologyService($command->getResourceType())->cloneInstance($instance, $type); + + $clonedInstance->setLabel(sprintf('%s (%s)', $instance->getLabel(), $language->getCode())); + + $clonedInstance->setPropertyValue( + $this->ontology->getProperty(TaoOntology::PROPERTY_LANGUAGE), + $language->getUri() + ); + + $clonedInstance->setPropertyValue( + $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_TYPE), + TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION + ); + + $clonedInstance->setPropertyValue( + $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_PROGRESS), + TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_PENDING + ); + + foreach ($this->callables[$command->getResourceType()] ?? [] as $callable) { + $clonedInstance = $callable($clonedInstance); + } + + return $clonedInstance; + } + + private function getOntologyService(string $resourceType): OntologyClassService + { + $service = $this->ontologyClassServices[$resourceType] ?? null; + + if ($service) { + return $service; + } + + throw new ResourceTranslationException( + sprintf( + 'There is no OntologyClassService for resource type %s', + $resourceType + ) + ); + } +} diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index c5d55c4d5c..af41187ca6 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -27,6 +27,8 @@ use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService; use oat\oatbox\log\LoggerService; use oat\tao\model\featureFlag\FeatureFlagChecker; +use oat\tao\model\Language\Business\Contract\LanguageRepositoryInterface; +use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Factory\ResourceTranslatableFactory; use oat\tao\model\Translation\Factory\ResourceTranslationFactory; use oat\tao\model\Translation\Form\Modifier\TranslationFormModifier; @@ -35,8 +37,10 @@ use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; use oat\tao\model\Translation\Service\ResourceTranslatableRetriever; use oat\tao\model\Translation\Service\ResourceTranslationRetriever; +use oat\tao\model\Translation\Service\TranslationCreationService; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; +use taoItems_models_classes_ItemsService; use function Symfony\Component\DependencyInjection\Loader\Configurator\service; /** @@ -109,5 +113,31 @@ public function __invoke(ContainerConfigurator $configurator): void ->args([ service(FeatureFlagChecker::class), ]); + + $services + ->set(TranslationCreationService::class, TranslationCreationService::class) + ->args( + [ + service(Ontology::SERVICE_ID), + service(ResourceTranslatableRepository::class), + service(ResourceTranslationRepository::class), + service(LanguageRepositoryInterface::class), + service(LoggerService::SERVICE_ID), + ] + ) + //FIXME + //FIXME @TODO Move this to proper extension + //FIXME + ->call( + 'setOntologyClassService', + [ + TaoOntology::CLASS_URI_ITEM, + service(taoItems_models_classes_ItemsService::class) + ] + ) + //FIXME + //FIXME + //FIXME + ->public(); } } diff --git a/test/unit/models/classes/Translation/Command/CreateTranslationCommandTest.php b/test/unit/models/classes/Translation/Command/CreateTranslationCommandTest.php new file mode 100644 index 0000000000..fcd44e4335 --- /dev/null +++ b/test/unit/models/classes/Translation/Command/CreateTranslationCommandTest.php @@ -0,0 +1,44 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Command; + +use oat\tao\model\Translation\Command\CreateTranslationCommand; +use PHPUnit\Framework\TestCase; + +class CreateTranslationCommandTest extends TestCase +{ + public function testConstructorAndGetters(): void + { + $resourceType = 'http://www.tao.lu/Ontologies/TAO.rdf#SomeType'; + $uniqueId = 'id1'; + $languageUri = 'http://www.tao.lu/Ontologies/TAO.rdf#Langpt-BR'; + + $command = new CreateTranslationCommand($resourceType, $uniqueId, $languageUri); + + $this->assertSame($resourceType, $command->getResourceType()); + $this->assertSame($uniqueId, $command->getUniqueId()); + $this->assertSame($languageUri, $command->getLanguageUri()); + } +} diff --git a/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php b/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php new file mode 100644 index 0000000000..ff209e70a2 --- /dev/null +++ b/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php @@ -0,0 +1,252 @@ +ontology = $this->createMock(Ontology::class); + $this->resourceTranslatableRepository = $this->createMock(ResourceTranslatableRepository::class); + $this->resourceTranslationRepository = $this->createMock(ResourceTranslationRepository::class); + $this->languageRepository = $this->createMock(LanguageRepositoryInterface::class); + $this->ontologyClassService = $this->createMock(OntologyClassService::class); + $this->logger = $this->createMock(LoggerInterface::class); + + $this->service = new TranslationCreationService( + $this->ontology, + $this->resourceTranslatableRepository, + $this->resourceTranslationRepository, + $this->languageRepository, + $this->logger, + ); + + $this->service->setOntologyClassService( + TaoOntology::CLASS_URI_ITEM, + $this->ontologyClassService + ); + } + + public function testCreate(): void + { + $resourceType = TaoOntology::CLASS_URI_ITEM; + $uniqueId = 'id1'; + $languageUri = 'http://www.tao.lu/Ontologies/TAO.rdf#Langpt-BR'; + + $languageProperty = $this->createMock(core_kernel_classes_Property::class); + $translationTypeProperty = $this->createMock(core_kernel_classes_Property::class); + $translationProgressProperty = $this->createMock(core_kernel_classes_Property::class); + + $resourceCollection = new ResourceCollection(); + $translatableCollection = new ResourceCollection($this->createMock(ResourceTranslatable::class)); + + $language = $this->createMock(Language::class); + $language + ->expects($this->exactly(2)) + ->method('getUri') + ->willReturn($languageUri); + $language + ->expects($this->once()) + ->method('getCode') + ->willReturn('pt-BR'); + + $instance = $this->createMock(core_kernel_classes_Resource::class); + $instance + ->expects($this->once()) + ->method('getTypes') + ->willReturn([]); + $instance + ->expects($this->once()) + ->method('getLabel') + ->willReturn('MyInstance'); + + $clonedInstance = $this->createMock(core_kernel_classes_Resource::class); + $clonedInstance + ->expects($this->once()) + ->method('setLabel') + ->with('MyInstance (pt-BR)'); + $clonedInstance + ->expects($this->exactly(3)) + ->method('setPropertyValue') + ->withConsecutive( + [ + $languageProperty, + $languageUri + ], + [ + $translationTypeProperty, + TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION + ], + [ + $translationProgressProperty, + TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_PENDING + ] + ); + + $this->resourceTranslationRepository + ->expects($this->once()) + ->method('find') + ->willReturn($resourceCollection); + + $this->resourceTranslatableRepository + ->expects($this->once()) + ->method('find') + ->willReturn($translatableCollection); + + $this->languageRepository + ->expects($this->once()) + ->method('findAvailableLanguagesByUsage') + ->willReturn(new LanguageCollection($language)); + + $this->ontology + ->expects($this->once()) + ->method('getResource') + ->willReturn($instance); + + $this->ontology + ->expects($this->exactly(3)) + ->method('getProperty') + ->willReturnMap( + [ + [ + TaoOntology::PROPERTY_LANGUAGE, + $languageProperty + ], + [ + TaoOntology::PROPERTY_TRANSLATION_TYPE, + $translationTypeProperty + ], + [ + TaoOntology::PROPERTY_TRANSLATION_PROGRESS, + $translationProgressProperty + ] + ] + ); + + $this->ontologyClassService + ->expects($this->once()) + ->method('cloneInstance') + ->willReturn($clonedInstance); + + $this->assertInstanceOf( + core_kernel_classes_Resource::class, + $this->service->create(new CreateTranslationCommand($resourceType, $uniqueId, $languageUri)) + ); + } + + public function testCreateWillFailIfTranslationAlreadyExists(): void + { + $this->resourceTranslationRepository + ->expects($this->once()) + ->method('find') + ->willReturn(new ResourceCollection($this->createMock(ResourceTranslation::class))); + + $this->expectException(ResourceTranslationException::class); + $this->expectExceptionMessage( + 'Translation already exists for [uniqueId=id1, locale=http://www.tao.lu/Ontologies/TAO.rdf#Langpt-BR]' + ); + + $this->service->create( + new CreateTranslationCommand( + TaoOntology::CLASS_URI_ITEM, + 'id1', + 'http://www.tao.lu/Ontologies/TAO.rdf#Langpt-BR' + ) + ); + } + + public function testCreateWillFailIfResourceDoesNotExist(): void + { + $this->resourceTranslationRepository + ->expects($this->once()) + ->method('find') + ->willReturn(new ResourceCollection()); + + $this->resourceTranslatableRepository + ->expects($this->once()) + ->method('find') + ->willReturn(new ResourceCollection()); + + $this->expectException(ResourceTranslationException::class); + $this->expectExceptionMessage('There is not translatable resource for [uniqueId=id1]'); + + $this->service->create( + new CreateTranslationCommand( + TaoOntology::CLASS_URI_ITEM, + 'id1', + 'http://www.tao.lu/Ontologies/TAO.rdf#Langpt-BR' + ) + ); + } + + public function testCreateWillFailIfLanguageDoesNotExist(): void + { + $this->resourceTranslationRepository + ->expects($this->once()) + ->method('find') + ->willReturn(new ResourceCollection()); + + $this->resourceTranslatableRepository + ->expects($this->once()) + ->method('find') + ->willReturn(new ResourceCollection($this->createMock(ResourceTranslatable::class))); + + $this->languageRepository + ->expects($this->once()) + ->method('findAvailableLanguagesByUsage') + ->willReturn(new LanguageCollection()); + + $this->expectException(ResourceTranslationException::class); + $this->expectExceptionMessage('Language http://www.tao.lu/Ontologies/TAO.rdf#Langpt-BR does not exist'); + + $this->service->create( + new CreateTranslationCommand( + TaoOntology::CLASS_URI_ITEM, + 'id1', + 'http://www.tao.lu/Ontologies/TAO.rdf#Langpt-BR' + ) + ); + } +} From 49e0242ba10676d7f7e7e302e326a480ce4e975d Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 12 Sep 2024 08:07:58 +0200 Subject: [PATCH 37/50] chore: add missing php docs --- .../TranslationCreationServiceTest.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php b/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php index ff209e70a2..5fdca16789 100644 --- a/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php +++ b/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php @@ -1,5 +1,25 @@ + */ + declare(strict_types=1); namespace oat\tao\test\unit\models\classes\Translation\Service; From 35148cf3eed40e9cbb9d2d13e5ed48887d7c66cc Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 12 Sep 2024 08:19:30 +0200 Subject: [PATCH 38/50] chore: remove tmp code --- .../TranslationServiceProvider.php | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index af41187ca6..4240b81560 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -28,7 +28,6 @@ use oat\oatbox\log\LoggerService; use oat\tao\model\featureFlag\FeatureFlagChecker; use oat\tao\model\Language\Business\Contract\LanguageRepositoryInterface; -use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Factory\ResourceTranslatableFactory; use oat\tao\model\Translation\Factory\ResourceTranslationFactory; use oat\tao\model\Translation\Form\Modifier\TranslationFormModifier; @@ -40,7 +39,6 @@ use oat\tao\model\Translation\Service\TranslationCreationService; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; -use taoItems_models_classes_ItemsService; use function Symfony\Component\DependencyInjection\Loader\Configurator\service; /** @@ -125,19 +123,6 @@ public function __invoke(ContainerConfigurator $configurator): void service(LoggerService::SERVICE_ID), ] ) - //FIXME - //FIXME @TODO Move this to proper extension - //FIXME - ->call( - 'setOntologyClassService', - [ - TaoOntology::CLASS_URI_ITEM, - service(taoItems_models_classes_ItemsService::class) - ] - ) - //FIXME - //FIXME - //FIXME ->public(); } } From c5c81d673730cf5a8b4ca199dfa7de7ab60e807e Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 12 Sep 2024 10:29:31 +0200 Subject: [PATCH 39/50] fix: avoid duplicate properties --- .../Translation/Service/TranslationCreationService.php | 6 +++--- .../Translation/Service/TranslationCreationServiceTest.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/models/classes/Translation/Service/TranslationCreationService.php b/models/classes/Translation/Service/TranslationCreationService.php index 4f20d65bb8..d414d4907b 100644 --- a/models/classes/Translation/Service/TranslationCreationService.php +++ b/models/classes/Translation/Service/TranslationCreationService.php @@ -190,17 +190,17 @@ private function doCreate(CreateTranslationCommand $command): core_kernel_classe $clonedInstance->setLabel(sprintf('%s (%s)', $instance->getLabel(), $language->getCode())); - $clonedInstance->setPropertyValue( + $clonedInstance->editPropertyValues( $this->ontology->getProperty(TaoOntology::PROPERTY_LANGUAGE), $language->getUri() ); - $clonedInstance->setPropertyValue( + $clonedInstance->editPropertyValues( $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_TYPE), TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION ); - $clonedInstance->setPropertyValue( + $clonedInstance->editPropertyValues( $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_PROGRESS), TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_PENDING ); diff --git a/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php b/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php index 5fdca16789..466491f477 100644 --- a/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php +++ b/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php @@ -129,7 +129,7 @@ public function testCreate(): void ->with('MyInstance (pt-BR)'); $clonedInstance ->expects($this->exactly(3)) - ->method('setPropertyValue') + ->method('editPropertyValues') ->withConsecutive( [ $languageProperty, From debed911beb861764b148c014472126c53ec2ed6 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 12 Sep 2024 11:05:22 +0200 Subject: [PATCH 40/50] feat: make endpoints only require resource id or locale to work --- actions/class.Translation.php | 9 +++ doc/taoApi.yml | 64 ++++++++++------ .../Service/ResourceTranslatableRetriever.php | 38 +++++++--- .../Service/ResourceTranslationRetriever.php | 34 +++++++-- .../Service/TranslationCreationService.php | 43 ++++++----- .../TranslationServiceProvider.php | 2 + .../ResourceTranslatableRetrieverTest.php | 73 ++++++++++++++++--- 7 files changed, 196 insertions(+), 67 deletions(-) diff --git a/actions/class.Translation.php b/actions/class.Translation.php index 27d13515ac..8478186c3e 100644 --- a/actions/class.Translation.php +++ b/actions/class.Translation.php @@ -29,6 +29,9 @@ class tao_actions_Translation extends tao_actions_CommonModule { use HttpJsonResponseTrait; + /** + * @requiresRight id WRITE + */ public function translate(): void { try { @@ -44,6 +47,9 @@ public function translate(): void } } + /** + * @requiresRight id READ + */ public function translations(): void { try { @@ -55,6 +61,9 @@ public function translations(): void } } + /** + * @requiresRight id READ + */ public function translatable(): void { try { diff --git a/doc/taoApi.yml b/doc/taoApi.yml index 5118ec4d2b..0ad039f294 100644 --- a/doc/taoApi.yml +++ b/doc/taoApi.yml @@ -10,17 +10,11 @@ paths: summary: Return a list of translations for a given translatable resource parameters: - in: query - name: resourceType + name: id required: true schema: type: string - description: The RDF resource type - - in: query - name: uniqueId - required: true - schema: - type: string - description: The uniqueId of a translation + description: The RDF resource id - in: query name: languageUri required: false @@ -39,22 +33,34 @@ paths: summary: Return translatable resources parameters: - in: query - name: resourceType + name: id required: true schema: type: string - description: The RDF resource type - - in: query - name: uniqueIds - required: true - schema: - type: array - items: - type: string - description: The uniqueIds for a translatable + description: The RDF resource id responses: 200: - $ref: '#/components/responses/TranslationsResponse' + $ref: '#/components/responses/TranslatableResponse' + 400: + $ref: '#/components/responses/BadRequestResponse' + 500: + $ref: '#/components/responses/InternalServerErrorResponse' + /tao/Translation/translate: + post: + summary: translate a resources + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + id: + type: string + description: The resource URI + responses: + 200: + $ref: '#/components/responses/TranslateResponse' 400: $ref: '#/components/responses/BadRequestResponse' 500: @@ -108,7 +114,7 @@ components: data: type: object properties: - resources: + resources: type: array items: properties: @@ -136,7 +142,7 @@ components: data: type: object properties: - resources: + resources: type: array items: properties: @@ -154,6 +160,16 @@ components: type: string literal: type: string + Translated: + properties: + success: + type: boolean + example: true + data: + type: object + properties: + resourceUri: + type: string ResourceRelationResource: description: 'A resource related to another resources' type: object @@ -224,6 +240,12 @@ components: application/json: schema: $ref: '#/components/schemas/Translatable' + TranslateResponse: + description: The resource is translated + content: + application/json: + schema: + $ref: '#/components/schemas/Translated' ResourceRelationsResponse: description: Bad request content: diff --git a/models/classes/Translation/Service/ResourceTranslatableRetriever.php b/models/classes/Translation/Service/ResourceTranslatableRetriever.php index 071d79e4fa..43b389835a 100644 --- a/models/classes/Translation/Service/ResourceTranslatableRetriever.php +++ b/models/classes/Translation/Service/ResourceTranslatableRetriever.php @@ -22,39 +22,59 @@ namespace oat\tao\model\Translation\Service; -use InvalidArgumentException; +use oat\generis\model\data\Ontology; +use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceCollection; +use oat\tao\model\Translation\Exception\ResourceTranslationException; use oat\tao\model\Translation\Query\ResourceTranslatableQuery; use oat\tao\model\Translation\Repository\ResourceTranslatableRepository; use Psr\Http\Message\ServerRequestInterface; class ResourceTranslatableRetriever { + private Ontology $ontology; private ResourceTranslatableRepository $resourceTranslatableRepository; - public function __construct(ResourceTranslatableRepository $resourceTranslationRepository) - { + public function __construct( + Ontology $ontology, + ResourceTranslatableRepository $resourceTranslationRepository + ) { $this->resourceTranslatableRepository = $resourceTranslationRepository; + $this->ontology = $ontology; } public function getByRequest(ServerRequestInterface $request): ResourceCollection { $queryParams = $request->getQueryParams(); - $resourceType = $queryParams['resourceType'] ?? null; - $uniqueIds = $queryParams['uniqueIds'] ?? []; + $id = $queryParams['id'] ?? null; + + if (empty($id)) { + throw new ResourceTranslationException( 'Resource id is required'); + } + + $resource = $this->ontology->getResource($id); + + $parentClassIds = $resource->getParentClassesIds(); + $resourceType = array_pop($parentClassIds); if (empty($resourceType)) { - throw new InvalidArgumentException('Param resourceType is required'); + throw new ResourceTranslationException(sprintf( 'Resource %s must have a resource type', $id)); } - if (empty($uniqueIds)) { - throw new InvalidArgumentException('Param uniqueIds is required'); + $uniqueId = $resource->getUniquePropertyValue( + $this->ontology->getProperty(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER) + ); + + if (empty($uniqueId)) { + throw new ResourceTranslationException(sprintf( 'Resource %s must have a unique identifier', $id)); } return $this->resourceTranslatableRepository->find( new ResourceTranslatableQuery( $resourceType, - $uniqueIds + [ + (string)$uniqueId + ] ) ); } diff --git a/models/classes/Translation/Service/ResourceTranslationRetriever.php b/models/classes/Translation/Service/ResourceTranslationRetriever.php index 4a10411556..8f04d225ae 100644 --- a/models/classes/Translation/Service/ResourceTranslationRetriever.php +++ b/models/classes/Translation/Service/ResourceTranslationRetriever.php @@ -22,40 +22,58 @@ namespace oat\tao\model\Translation\Service; -use InvalidArgumentException; +use oat\generis\model\data\Ontology; +use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceCollection; +use oat\tao\model\Translation\Exception\ResourceTranslationException; use oat\tao\model\Translation\Query\ResourceTranslationQuery; use oat\tao\model\Translation\Repository\ResourceTranslationRepository; use Psr\Http\Message\ServerRequestInterface; class ResourceTranslationRetriever { + private Ontology $ontology; private ResourceTranslationRepository $resourceTranslationRepository; - public function __construct(ResourceTranslationRepository $resourceTranslationRepository) - { + public function __construct( + Ontology $ontology, + ResourceTranslationRepository $resourceTranslationRepository + ) { + $this->ontology = $ontology; $this->resourceTranslationRepository = $resourceTranslationRepository; } public function getByRequest(ServerRequestInterface $request): ResourceCollection { $queryParams = $request->getQueryParams(); - $resourceType = $queryParams['resourceType'] ?? null; - $uniqueId = $queryParams['uniqueId'] ?? null; $languageUri = $queryParams['languageUri'] ?? null; + $id = $queryParams['id'] ?? null; + + if (empty($id)) { + throw new ResourceTranslationException( 'Resource id is required'); + } + + $resource = $this->ontology->getResource($id); + + $parentClassIds = $resource->getParentClassesIds(); + $resourceType = array_pop($parentClassIds); if (empty($resourceType)) { - throw new InvalidArgumentException('Param resourceType is required'); + throw new ResourceTranslationException(sprintf( 'Resource %s must have a resource type', $id)); } + $uniqueId = $resource->getUniquePropertyValue( + $this->ontology->getProperty(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER) + ); + if (empty($uniqueId)) { - throw new InvalidArgumentException('Param uniqueId is required'); + throw new ResourceTranslationException(sprintf( 'Resource %s must have a unique identifier', $id)); } return $this->resourceTranslationRepository->find( new ResourceTranslationQuery( $resourceType, - $uniqueId, + (string)$uniqueId, $languageUri ) ); diff --git a/models/classes/Translation/Service/TranslationCreationService.php b/models/classes/Translation/Service/TranslationCreationService.php index d414d4907b..211136ddd4 100644 --- a/models/classes/Translation/Service/TranslationCreationService.php +++ b/models/classes/Translation/Service/TranslationCreationService.php @@ -77,28 +77,37 @@ public function addPostCreation(string $resourceType, callable $callable): void public function createByRequest(ServerRequestInterface $request): core_kernel_classes_Resource { $requestParams = $request->getParsedBody(); + $id = $requestParams['id'] ?? null; - $requiredParams = [ - 'resourceType', - 'uniqueId', - 'languageUri', - ]; - - foreach ($requiredParams as $requiredParam) { - if (empty($requestParams[$requiredParam])) { - throw new ResourceTranslationException( - sprintf( - 'Parameter %s is mandatory', - $requiredParam - ) - ); - } + if (empty($id)) { + throw new ResourceTranslationException('Resource id is required'); + } + + $resource = $this->ontology->getResource($id); + + $parentClassIds = $resource->getParentClassesIds(); + $resourceType = array_pop($parentClassIds); + + if (empty($resourceType)) { + throw new ResourceTranslationException(sprintf('Resource %s must have a resource type', $id)); + } + + $uniqueId = $resource->getUniquePropertyValue( + $this->ontology->getProperty(TaoOntology::PROPERTY_UNIQUE_IDENTIFIER) + ); + + if (empty($uniqueId)) { + throw new ResourceTranslationException(sprintf('Resource %s must have a unique identifier', $id)); + } + + if (empty($requestParams['languageUri'])) { + throw new ResourceTranslationException('Parameter languageUri is mandatory'); } return $this->create( new CreateTranslationCommand( - $requestParams['resourceType'], - $requestParams['uniqueId'], + $resourceType, + (string)$uniqueId, $requestParams['languageUri'] ) ); diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index 4240b81560..92f996cbeb 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -93,6 +93,7 @@ public function __invoke(ContainerConfigurator $configurator): void $services->set(ResourceTranslationRetriever::class, ResourceTranslationRetriever::class) ->args( [ + service(Ontology::SERVICE_ID), service(ResourceTranslationRepository::class) ] ) @@ -101,6 +102,7 @@ public function __invoke(ContainerConfigurator $configurator): void $services->set(ResourceTranslatableRetriever::class, ResourceTranslatableRetriever::class) ->args( [ + service(Ontology::SERVICE_ID), service(ResourceTranslatableRepository::class) ] ) diff --git a/test/unit/models/classes/Translation/Service/ResourceTranslatableRetrieverTest.php b/test/unit/models/classes/Translation/Service/ResourceTranslatableRetrieverTest.php index d0ad69fbd8..cbf322b201 100644 --- a/test/unit/models/classes/Translation/Service/ResourceTranslatableRetrieverTest.php +++ b/test/unit/models/classes/Translation/Service/ResourceTranslatableRetrieverTest.php @@ -24,8 +24,12 @@ namespace oat\tao\test\unit\model\Translation\Service; -use InvalidArgumentException; +use core_kernel_classes_Property; +use core_kernel_classes_Resource; +use oat\generis\model\data\Ontology; +use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceCollection; +use oat\tao\model\Translation\Exception\ResourceTranslationException; use oat\tao\model\Translation\Query\ResourceTranslatableQuery; use oat\tao\model\Translation\Repository\ResourceTranslatableRepository; use oat\tao\model\Translation\Service\ResourceTranslatableRetriever; @@ -40,14 +44,18 @@ class ResourceTranslatableRetrieverTest extends TestCase /** @var ResourceTranslatableRepository|MockObject */ private $resourceTranslatableRepository; + /** @var Ontology|MockObject */ + private $ontology; + /** @var MockObject|ServerRequestInterface */ private $request; public function setUp(): void { + $this->ontology = $this->createMock(Ontology::class); $this->resourceTranslatableRepository = $this->createMock(ResourceTranslatableRepository::class); $this->request = $this->createMock(ServerRequestInterface::class); - $this->sut = new ResourceTranslatableRetriever($this->resourceTranslatableRepository); + $this->sut = new ResourceTranslatableRetriever($this->ontology, $this->resourceTranslatableRepository); } public function testGetByRequest(): void @@ -56,11 +64,12 @@ public function testGetByRequest(): void ->method('getQueryParams') ->willReturn( [ - 'resourceType' => 'resourceType', - 'uniqueIds' => ['uniqueId'], + 'id' => ['id'], ] ); + $this->mockResource([TaoOntology::CLASS_URI_ITEM], 'uniqueId'); + $result = new ResourceCollection(); $this->resourceTranslatableRepository @@ -68,7 +77,7 @@ public function testGetByRequest(): void ->method('find') ->with( new ResourceTranslatableQuery( - 'resourceType', + TaoOntology::CLASS_URI_ITEM, ['uniqueId'] ) ) @@ -77,31 +86,71 @@ public function testGetByRequest(): void $this->assertSame($result, $this->sut->getByRequest($this->request)); } - public function testGetByRequestRequiresResourceType(): void + public function testGetByRequestRequiresResourceId(): void { $this->request->expects($this->once()) ->method('getQueryParams') ->willReturn([]); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Param resourceType is required'); + $this->expectException(ResourceTranslationException::class); + $this->expectExceptionMessage('Resource id is required'); $this->sut->getByRequest($this->request); } - public function testGetByRequestRequiresUniqueIds(): void + public function testGetByRequestRequiresResourceType(): void + { + $this->request->expects($this->once()) + ->method('getQueryParams') + ->willReturn(['id' => 'id']); + + $this->mockResource([], 'uniqueId'); + + $this->expectException(ResourceTranslationException::class); + $this->expectExceptionMessage('Resource id must have a resource type'); + + $this->sut->getByRequest($this->request); + } + + public function testGetByRequestRequiresUniqueId(): void { $this->request->expects($this->once()) ->method('getQueryParams') ->willReturn( [ - 'resourceType' => 'resourceType', + 'id' => 'id', ] ); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Param uniqueIds is required'); + $this->mockResource([TaoOntology::CLASS_URI_ITEM], ''); + + $this->expectException(ResourceTranslationException::class); + $this->expectExceptionMessage('Resource id must have a unique identifier'); $this->sut->getByRequest($this->request); } + + private function mockResource(array $classIds, string $uniqueId): core_kernel_classes_Resource + { + $resource = $this->createMock(core_kernel_classes_Resource::class); + + $resource + ->method('getParentClassesIds') + ->willReturn($classIds); + + $resource + ->method('getUniquePropertyValue') + ->willReturn($uniqueId); + + $this->ontology + ->expects($this->once()) + ->method('getResource') + ->willReturn($resource); + + $this->ontology + ->method('getProperty') + ->willReturn($this->createMock(core_kernel_classes_Property::class)); + + return $resource; + } } From c9d15a3047d324822b27e5412d3e63d3614548e3 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 12 Sep 2024 11:22:56 +0200 Subject: [PATCH 41/50] chore: add missing unit tests cs fixes --- .../Service/ResourceTranslatableRetriever.php | 6 +- .../Service/ResourceTranslationRetriever.php | 6 +- .../ResourceTranslationRetrieverTest.php | 70 ++++++++++++++++--- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/models/classes/Translation/Service/ResourceTranslatableRetriever.php b/models/classes/Translation/Service/ResourceTranslatableRetriever.php index 43b389835a..db39b69a1d 100644 --- a/models/classes/Translation/Service/ResourceTranslatableRetriever.php +++ b/models/classes/Translation/Service/ResourceTranslatableRetriever.php @@ -49,7 +49,7 @@ public function getByRequest(ServerRequestInterface $request): ResourceCollectio $id = $queryParams['id'] ?? null; if (empty($id)) { - throw new ResourceTranslationException( 'Resource id is required'); + throw new ResourceTranslationException('Resource id is required'); } $resource = $this->ontology->getResource($id); @@ -58,7 +58,7 @@ public function getByRequest(ServerRequestInterface $request): ResourceCollectio $resourceType = array_pop($parentClassIds); if (empty($resourceType)) { - throw new ResourceTranslationException(sprintf( 'Resource %s must have a resource type', $id)); + throw new ResourceTranslationException(sprintf('Resource %s must have a resource type', $id)); } $uniqueId = $resource->getUniquePropertyValue( @@ -66,7 +66,7 @@ public function getByRequest(ServerRequestInterface $request): ResourceCollectio ); if (empty($uniqueId)) { - throw new ResourceTranslationException(sprintf( 'Resource %s must have a unique identifier', $id)); + throw new ResourceTranslationException(sprintf('Resource %s must have a unique identifier', $id)); } return $this->resourceTranslatableRepository->find( diff --git a/models/classes/Translation/Service/ResourceTranslationRetriever.php b/models/classes/Translation/Service/ResourceTranslationRetriever.php index 8f04d225ae..ae78fd4335 100644 --- a/models/classes/Translation/Service/ResourceTranslationRetriever.php +++ b/models/classes/Translation/Service/ResourceTranslationRetriever.php @@ -50,7 +50,7 @@ public function getByRequest(ServerRequestInterface $request): ResourceCollectio $id = $queryParams['id'] ?? null; if (empty($id)) { - throw new ResourceTranslationException( 'Resource id is required'); + throw new ResourceTranslationException('Resource id is required'); } $resource = $this->ontology->getResource($id); @@ -59,7 +59,7 @@ public function getByRequest(ServerRequestInterface $request): ResourceCollectio $resourceType = array_pop($parentClassIds); if (empty($resourceType)) { - throw new ResourceTranslationException(sprintf( 'Resource %s must have a resource type', $id)); + throw new ResourceTranslationException(sprintf('Resource %s must have a resource type', $id)); } $uniqueId = $resource->getUniquePropertyValue( @@ -67,7 +67,7 @@ public function getByRequest(ServerRequestInterface $request): ResourceCollectio ); if (empty($uniqueId)) { - throw new ResourceTranslationException(sprintf( 'Resource %s must have a unique identifier', $id)); + throw new ResourceTranslationException(sprintf('Resource %s must have a unique identifier', $id)); } return $this->resourceTranslationRepository->find( diff --git a/test/unit/models/classes/Translation/Service/ResourceTranslationRetrieverTest.php b/test/unit/models/classes/Translation/Service/ResourceTranslationRetrieverTest.php index 83925dd179..a3acbd6748 100644 --- a/test/unit/models/classes/Translation/Service/ResourceTranslationRetrieverTest.php +++ b/test/unit/models/classes/Translation/Service/ResourceTranslationRetrieverTest.php @@ -24,8 +24,13 @@ namespace oat\tao\test\unit\model\Translation\Service; +use core_kernel_classes_Property; +use core_kernel_classes_Resource; use InvalidArgumentException; +use oat\generis\model\data\Ontology; +use oat\tao\model\TaoOntology; use oat\tao\model\Translation\Entity\ResourceCollection; +use oat\tao\model\Translation\Exception\ResourceTranslationException; use oat\tao\model\Translation\Query\ResourceTranslationQuery; use oat\tao\model\Translation\Repository\ResourceTranslationRepository; use oat\tao\model\Translation\Service\ResourceTranslationRetriever; @@ -37,6 +42,9 @@ class ResourceTranslationStatusServiceTest extends TestCase { private ResourceTranslationRetriever $sut; + /** @var Ontology|MockObject */ + private $ontology; + /** @var ResourceTranslationRepository|MockObject */ private $resourceTranslationRepository; @@ -45,9 +53,10 @@ class ResourceTranslationStatusServiceTest extends TestCase public function setUp(): void { + $this->ontology = $this->createMock(Ontology::class); $this->resourceTranslationRepository = $this->createMock(ResourceTranslationRepository::class); $this->request = $this->createMock(ServerRequestInterface::class); - $this->sut = new ResourceTranslationRetriever($this->resourceTranslationRepository); + $this->sut = new ResourceTranslationRetriever($this->ontology, $this->resourceTranslationRepository); } public function testGetByRequest(): void @@ -56,11 +65,12 @@ public function testGetByRequest(): void ->method('getQueryParams') ->willReturn( [ - 'resourceType' => 'resourceType', - 'uniqueId' => 'uniqueId', + 'id' => 'id', ] ); + $this->mockResource([TaoOntology::CLASS_URI_ITEM], 'uniqueId'); + $result = new ResourceCollection(); $this->resourceTranslationRepository @@ -68,7 +78,7 @@ public function testGetByRequest(): void ->method('find') ->with( new ResourceTranslationQuery( - 'resourceType', + TaoOntology::CLASS_URI_ITEM, 'uniqueId', null ) @@ -78,14 +88,28 @@ public function testGetByRequest(): void $this->assertSame($result, $this->sut->getByRequest($this->request)); } - public function testGetByRequestRequiresResourceType(): void + public function testGetByRequestRequiresResourceId(): void { $this->request->expects($this->once()) ->method('getQueryParams') ->willReturn([]); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Param resourceType is required'); + $this->expectException(ResourceTranslationException::class); + $this->expectExceptionMessage('Resource id is required'); + + $this->sut->getByRequest($this->request); + } + + public function testGetByRequestRequiresResourceType(): void + { + $this->request->expects($this->once()) + ->method('getQueryParams') + ->willReturn(['id' => 'id']); + + $this->mockResource([], 'uniqueId'); + + $this->expectException(ResourceTranslationException::class); + $this->expectExceptionMessage('Resource id must have a resource type'); $this->sut->getByRequest($this->request); } @@ -96,13 +120,39 @@ public function testGetByRequestRequiresUniqueId(): void ->method('getQueryParams') ->willReturn( [ - 'resourceType' => 'resourceType', + 'id' => 'id', ] ); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Param uniqueId is required'); + $this->mockResource([TaoOntology::CLASS_URI_ITEM], ''); + + $this->expectException(ResourceTranslationException::class); + $this->expectExceptionMessage('Resource id must have a unique identifier'); $this->sut->getByRequest($this->request); } + + private function mockResource(array $classIds, string $uniqueId): core_kernel_classes_Resource + { + $resource = $this->createMock(core_kernel_classes_Resource::class); + + $resource + ->method('getParentClassesIds') + ->willReturn($classIds); + + $resource + ->method('getUniquePropertyValue') + ->willReturn($uniqueId); + + $this->ontology + ->expects($this->once()) + ->method('getResource') + ->willReturn($resource); + + $this->ontology + ->method('getProperty') + ->willReturn($this->createMock(core_kernel_classes_Property::class)); + + return $resource; + } } From d8d7ae6df2a18fb6e5a14167b33067ec61d4caa3 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 12 Sep 2024 11:24:58 +0200 Subject: [PATCH 42/50] chore: remove rules from non-translator user --- manifest.php | 1 - migrations/Version202409040743452141_tao.php | 18 ------------------ 2 files changed, 19 deletions(-) diff --git a/manifest.php b/manifest.php index 4d92c7f509..00d6625fe1 100755 --- a/manifest.php +++ b/manifest.php @@ -309,7 +309,6 @@ [AccessRule::GRANT, TaoRoles::BASE_USER, ['ext' => 'tao', 'mod' => 'File', 'act' => 'accessFile']], [AccessRule::GRANT, TaoRoles::BASE_USER, ['ext' => 'tao', 'mod' => 'Log', 'act' => 'log']], [AccessRule::GRANT, TaoRoles::BASE_USER, ['ext' => 'tao', 'mod' => 'TaskQueueWebApi']], - [AccessRule::GRANT, TaoRoles::BACK_OFFICE, ['ext' => 'tao', 'mod' => 'Translation']], [AccessRule::GRANT, TaoRoles::BACK_OFFICE, ['ext' => 'tao', 'mod' => 'Languages', 'act' => 'index']], [AccessRule::GRANT, TaoRoles::BACK_OFFICE, ['ext' => 'tao', 'mod' => 'ResourceRelations', 'act' => 'index']], [AccessRule::GRANT, TaoRoles::BACK_OFFICE, ['ext' => 'tao', 'mod' => 'File', 'act' => 'upload']], diff --git a/migrations/Version202409040743452141_tao.php b/migrations/Version202409040743452141_tao.php index d5e5de6283..73c630b358 100644 --- a/migrations/Version202409040743452141_tao.php +++ b/migrations/Version202409040743452141_tao.php @@ -6,8 +6,6 @@ use Doctrine\DBAL\Schema\Schema; use oat\oatbox\reporting\Report; -use oat\tao\model\accessControl\func\AccessRule; -use oat\tao\model\accessControl\func\AclProxy; use oat\tao\model\user\TaoRoles; use oat\tao\scripts\tools\migrations\AbstractMigration; use oat\tao\scripts\update\OntologyUpdater; @@ -23,25 +21,9 @@ public function up(Schema $schema): void { OntologyUpdater::syncModels(); $this->addReport(Report::createSuccess('Ontology models successfully synchronized')); - - AclProxy::applyRule($this->getRule()); - $this->addReport(Report::createSuccess('Applied access for role ' . TaoRoles::BACK_OFFICE)); } public function down(Schema $schema): void { - AclProxy::revokeRule($this->getRule()); - } - - private function getRule(): AccessRule - { - return new AccessRule( - AccessRule::GRANT, - TaoRoles::BACK_OFFICE, - [ - 'ext' => 'tao', - 'mod' => 'Translation' - ] - ); } } From 6315e5d1fa40122d7ad228379f805ffcef115554 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 12 Sep 2024 13:48:23 +0200 Subject: [PATCH 43/50] chore: add PR suggestions --- .../Translation/Service/ResourceMetadataPopulateService.php | 5 +++-- models/classes/menu/SectionVisibilityFilter.php | 2 +- .../Service/ResourceMetadataPopulateServiceTest.php | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/models/classes/Translation/Service/ResourceMetadataPopulateService.php b/models/classes/Translation/Service/ResourceMetadataPopulateService.php index a5830fbe9b..2165126f35 100644 --- a/models/classes/Translation/Service/ResourceMetadataPopulateService.php +++ b/models/classes/Translation/Service/ResourceMetadataPopulateService.php @@ -25,6 +25,7 @@ use core_kernel_classes_Literal; use core_kernel_classes_Resource; use oat\generis\model\data\Ontology; +use oat\generis\model\OntologyRdf; use oat\tao\model\Translation\Entity\AbstractResource; class ResourceMetadataPopulateService @@ -39,13 +40,13 @@ public function __construct(Ontology $ontology) public function addMetadata(string $resourceType, string $metadataUri): void { - $this->metadata[$resourceType] = empty($this->metadata[$resourceType]) ? [] : $this->metadata[$resourceType]; + $this->metadata[$resourceType] ??= []; $this->metadata[$resourceType] = array_unique(array_merge($this->metadata[$resourceType], [$metadataUri])); } public function populate(AbstractResource $resource, core_kernel_classes_Resource $originResource): void { - $valueProperty = $this->ontology->getProperty('http://www.w3.org/1999/02/22-rdf-syntax-ns#value'); + $valueProperty = $this->ontology->getProperty(OntologyRdf::RDF_VALUE); $parentClasses = $originResource->getParentClassesIds(); $resourceType = array_pop($parentClasses); diff --git a/models/classes/menu/SectionVisibilityFilter.php b/models/classes/menu/SectionVisibilityFilter.php index a2c932cf21..4e19bc0cdd 100644 --- a/models/classes/menu/SectionVisibilityFilter.php +++ b/models/classes/menu/SectionVisibilityFilter.php @@ -70,7 +70,7 @@ public function isVisible(string $sectionPath): bool $userSettings->getSetting( UserSettingsInterface::INTERFACE_MODE ) === GenerisRdf::PROPERTY_USER_INTERFACE_MODE_SIMPLE - && in_array($sectionPath, self::SIMPLE_INTERFACE_MODE_HIDDEN_SECTIONS) + && in_array($sectionPath, self::SIMPLE_INTERFACE_MODE_HIDDEN_SECTIONS, true) ) { return false; } diff --git a/test/unit/models/classes/Translation/Service/ResourceMetadataPopulateServiceTest.php b/test/unit/models/classes/Translation/Service/ResourceMetadataPopulateServiceTest.php index b199c632db..d90db1b6e8 100644 --- a/test/unit/models/classes/Translation/Service/ResourceMetadataPopulateServiceTest.php +++ b/test/unit/models/classes/Translation/Service/ResourceMetadataPopulateServiceTest.php @@ -28,6 +28,7 @@ use core_kernel_classes_Property; use core_kernel_classes_Resource; use oat\generis\model\data\Ontology; +use oat\generis\model\OntologyRdf; use oat\tao\model\Translation\Entity\AbstractResource; use oat\tao\model\Translation\Service\ResourceMetadataPopulateService; use PHPUnit\Framework\MockObject\MockObject; @@ -58,7 +59,7 @@ public function testPopulateAddsMetadataToResource(): void { $resourceType = 'testResourceType'; $metadataUri = 'http://example.com/metadata'; - $valuePropertyUri = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'; + $valuePropertyUri = OntologyRdf::RDF_VALUE; $value = 'testValue'; $literalValue = 'testLiteral'; $valueProperty = $this->createMock(core_kernel_classes_Property::class); From 965f4ea406ecf8c292a4cdd2aa72e50377fe18fe Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Thu, 12 Sep 2024 16:50:24 +0200 Subject: [PATCH 44/50] chore: allow update translation status --- actions/class.Translation.php | 30 ++++ doc/taoApi.yml | 23 +++ .../Command/UpdateTranslationCommand.php | 62 ++++++++ .../Service/TranslationUpdateService.php | 81 ++++++++++ .../TranslationServiceProvider.php | 11 ++ .../Command/UpdateTranslationCommandTest.php | 45 ++++++ .../Service/TranslationUpdateServiceTest.php | 147 ++++++++++++++++++ 7 files changed, 399 insertions(+) create mode 100644 models/classes/Translation/Command/UpdateTranslationCommand.php create mode 100644 models/classes/Translation/Service/TranslationUpdateService.php create mode 100644 test/unit/models/classes/Translation/Command/UpdateTranslationCommandTest.php create mode 100644 test/unit/models/classes/Translation/Service/TranslationUpdateServiceTest.php diff --git a/actions/class.Translation.php b/actions/class.Translation.php index 8478186c3e..b7840c6ded 100644 --- a/actions/class.Translation.php +++ b/actions/class.Translation.php @@ -21,14 +21,39 @@ declare(strict_types=1); use oat\tao\model\http\HttpJsonResponseTrait; +use oat\tao\model\Translation\Command\UpdateTranslationCommand; use oat\tao\model\Translation\Service\ResourceTranslationRetriever; use oat\tao\model\Translation\Service\ResourceTranslatableRetriever; use oat\tao\model\Translation\Service\TranslationCreationService; +use oat\tao\model\Translation\Service\TranslationUpdateService; class tao_actions_Translation extends tao_actions_CommonModule { use HttpJsonResponseTrait; + /** + * @requiresRight id WRITE + */ + public function update(): void + { + try { + $resource = $this->getTranslationUpdateService()->update( + new UpdateTranslationCommand( + $this->getRequestParameter('id'), + $this->getRequestParameter('progress'), + ) + ); + + $this->setSuccessJsonResponse( + [ + 'resourceUri' => $resource->getUri() + ] + ); + } catch (Throwable $exception) { + $this->setErrorJsonResponse($exception->getMessage()); + } + } + /** * @requiresRight id WRITE */ @@ -89,4 +114,9 @@ private function getTranslationCreationService(): TranslationCreationService { return $this->getServiceManager()->getContainer()->get(TranslationCreationService::class); } + + private function getTranslationUpdateService(): TranslationUpdateService + { + return $this->getServiceManager()->getContainer()->get(TranslationUpdateService::class); + } } diff --git a/doc/taoApi.yml b/doc/taoApi.yml index 0ad039f294..c317cb667d 100644 --- a/doc/taoApi.yml +++ b/doc/taoApi.yml @@ -5,6 +5,29 @@ info: version: v1 paths: + /tao/Translation/update: + post: + summary: Return a list of translations for a given translatable resource + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + id: + type: string + description: The resource URI + progress: + type: string + description: The progress URI + responses: + 200: + $ref: '#/components/responses/TranslateResponse' + 400: + $ref: '#/components/responses/BadRequestResponse' + 500: + $ref: '#/components/responses/InternalServerErrorResponse' /tao/Translation/translations: get: summary: Return a list of translations for a given translatable resource diff --git a/models/classes/Translation/Command/UpdateTranslationCommand.php b/models/classes/Translation/Command/UpdateTranslationCommand.php new file mode 100644 index 0000000000..48a4fd0cd6 --- /dev/null +++ b/models/classes/Translation/Command/UpdateTranslationCommand.php @@ -0,0 +1,62 @@ +resourceUri = $resourceUri; + $this->progressUri = $progressUri; + } + + public function getResourceUri(): string + { + return $this->resourceUri; + } + + public function getProgressUri(): string + { + return $this->progressUri; + } +} diff --git a/models/classes/Translation/Service/TranslationUpdateService.php b/models/classes/Translation/Service/TranslationUpdateService.php new file mode 100644 index 0000000000..cb51957bf3 --- /dev/null +++ b/models/classes/Translation/Service/TranslationUpdateService.php @@ -0,0 +1,81 @@ +ontology = $ontology; + $this->logger = $logger; + } + + public function update(UpdateTranslationCommand $command): core_kernel_classes_Resource + { + try { + $instance = $this->ontology->getResource($command->getResourceUri()); + + $translationType = $instance->getOnePropertyValue( + $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_TYPE) + ); + + if ($translationType->getUri() !== TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION) { + throw new ResourceTranslationException( + sprintf( + 'Resource %s is not a translation', + $command->getResourceUri() + ) + ); + } + + $instance->editPropertyValues( + $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_PROGRESS), + $command->getProgressUri() + ); + + return $instance; + } catch (Throwable $exception) { + $this->logger->error( + sprintf( + 'Could not update translation status of [resourceUri=%s] (%s): %s', + $command->getResourceUri(), + get_class($exception), + $exception->getMessage() + ) + ); + + throw $exception; + } + } +} diff --git a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php index 92f996cbeb..dcafea5a52 100644 --- a/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php +++ b/models/classes/Translation/ServiceProvider/TranslationServiceProvider.php @@ -37,6 +37,7 @@ use oat\tao\model\Translation\Service\ResourceTranslatableRetriever; use oat\tao\model\Translation\Service\ResourceTranslationRetriever; use oat\tao\model\Translation\Service\TranslationCreationService; +use oat\tao\model\Translation\Service\TranslationUpdateService; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use function Symfony\Component\DependencyInjection\Loader\Configurator\service; @@ -126,5 +127,15 @@ public function __invoke(ContainerConfigurator $configurator): void ] ) ->public(); + + $services + ->set(TranslationUpdateService::class, TranslationUpdateService::class) + ->args( + [ + service(Ontology::SERVICE_ID), + service(LoggerService::SERVICE_ID), + ] + ) + ->public(); } } diff --git a/test/unit/models/classes/Translation/Command/UpdateTranslationCommandTest.php b/test/unit/models/classes/Translation/Command/UpdateTranslationCommandTest.php new file mode 100644 index 0000000000..42deec4a4f --- /dev/null +++ b/test/unit/models/classes/Translation/Command/UpdateTranslationCommandTest.php @@ -0,0 +1,45 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\model\Translation\Command; + +use oat\tao\model\TaoOntology; +use oat\tao\model\Translation\Command\UpdateTranslationCommand; +use PHPUnit\Framework\TestCase; + +class UpdateTranslationCommandTest extends TestCase +{ + public function testConstructorAndGetters(): void + { + $resourceUri = 'http://example.com/resource/1'; + + $command = new UpdateTranslationCommand( + $resourceUri, + TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED + ); + + $this->assertSame($resourceUri, $command->getResourceUri()); + $this->assertSame(TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED, $command->getProgressUri()); + } +} diff --git a/test/unit/models/classes/Translation/Service/TranslationUpdateServiceTest.php b/test/unit/models/classes/Translation/Service/TranslationUpdateServiceTest.php new file mode 100644 index 0000000000..94ad7ea569 --- /dev/null +++ b/test/unit/models/classes/Translation/Service/TranslationUpdateServiceTest.php @@ -0,0 +1,147 @@ + + */ + +declare(strict_types=1); + +namespace oat\tao\test\unit\models\classes\Translation\Service; + +use core_kernel_classes_Property; +use core_kernel_classes_Resource; +use oat\generis\model\data\Ontology; +use oat\tao\model\TaoOntology; +use oat\tao\model\Translation\Command\UpdateTranslationCommand; +use oat\tao\model\Translation\Exception\ResourceTranslationException; +use oat\tao\model\Translation\Service\TranslationUpdateService; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; + +class TranslationUpdateServiceTest extends TestCase +{ + private TranslationUpdateService $service; + + /** @var Ontology|MockObject */ + private $ontology; + + /** @var LoggerInterface|MockObject */ + private $logger; + + protected function setUp(): void + { + $this->ontology = $this->createMock(Ontology::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->service = new TranslationUpdateService($this->ontology, $this->logger); + } + + public function testUpdateSuccess(): void + { + $typeProperty = $this->createMock(core_kernel_classes_Property::class); + $progressProperty = $this->createMock(core_kernel_classes_Property::class); + + $translationType = $this->createMock(core_kernel_classes_Resource::class); + $translationType + ->method('getUri') + ->willReturn(TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_TRANSLATION); + + $resource = $this->createMock(core_kernel_classes_Resource::class); + $resource + ->method('getOnePropertyValue') + ->willReturn($translationType); + + $resource + ->expects($this->once()) + ->method('editPropertyValues') + ->with( + $progressProperty, + TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED + ); + + $this->ontology + ->method('getResource') + ->willReturn($resource); + + $this->ontology + ->method('getProperty') + ->willReturnMap( + [ + [ + TaoOntology::PROPERTY_TRANSLATION_TYPE, + $typeProperty + ], + [ + TaoOntology::PROPERTY_TRANSLATION_PROGRESS, + $progressProperty + ], + ] + ); + + $this->assertSame( + $resource, + $this->service->update( + new UpdateTranslationCommand( + 'http://example.com/resource/1', + TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED + ) + ) + ); + } + + public function testOriginalCannotBeUpdated(): void + { + $typeProperty = $this->createMock(core_kernel_classes_Property::class); + + $translationType = $this->createMock(core_kernel_classes_Resource::class); + $translationType + ->method('getUri') + ->willReturn(TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL); + + $resource = $this->createMock(core_kernel_classes_Resource::class); + $resource + ->method('getOnePropertyValue') + ->willReturn($translationType); + + $this->ontology + ->method('getResource') + ->willReturn($resource); + + $this->ontology + ->method('getProperty') + ->willReturnMap( + [ + [ + TaoOntology::PROPERTY_TRANSLATION_TYPE, + $typeProperty + ] + ] + ); + + $this->expectException(ResourceTranslationException::class); + $this->expectExceptionMessage('Resource http://example.com/resource/1 is not a translation'); + + $this->service->update( + new UpdateTranslationCommand( + 'http://example.com/resource/1', + TaoOntology::PROPERTY_VALUE_TRANSLATION_PROGRESS_TRANSLATED + ) + ); + } +} From c5003fad4221b923b5c1eebc358415e10e2bbce0 Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Fri, 13 Sep 2024 09:55:03 +0300 Subject: [PATCH 45/50] chore: fix cs --- .../Form/Modifier/TranslationFormModifierTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/unit/models/classes/Translation/Form/Modifier/TranslationFormModifierTest.php b/test/unit/models/classes/Translation/Form/Modifier/TranslationFormModifierTest.php index b58fc5071a..4ec2adbf80 100644 --- a/test/unit/models/classes/Translation/Form/Modifier/TranslationFormModifierTest.php +++ b/test/unit/models/classes/Translation/Form/Modifier/TranslationFormModifierTest.php @@ -92,7 +92,12 @@ public function testModifyTranslationEnabled(bool $developerMode, ?string $type, $this->form ->expects($this->exactly(count($removeElements))) ->method('removeElement') - ->withConsecutive(...array_map(static fn ($element) => [tao_helpers_Uri::encode($element)], $removeElements)); + ->withConsecutive( + ...array_map( + static fn ($element) => [tao_helpers_Uri::encode($element)], + $removeElements + ) + ); $this->sut->modify($this->form); } From 8789fa71e6045ec32a66124ef80a20e5fa802806 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Fri, 13 Sep 2024 11:20:30 +0200 Subject: [PATCH 46/50] fix: add extra validation and allow multiple uniqueIds search --- .../Query/ResourceTranslationQuery.php | 10 ++++----- .../ResourceTranslationRepository.php | 21 +++++++++++-------- .../Service/ResourceTranslationRetriever.php | 2 +- .../Service/TranslationCreationService.php | 14 ++++++++++++- .../Service/TranslationUpdateService.php | 9 ++++++++ 5 files changed, 40 insertions(+), 16 deletions(-) diff --git a/models/classes/Translation/Query/ResourceTranslationQuery.php b/models/classes/Translation/Query/ResourceTranslationQuery.php index d009fc4334..a10c516876 100644 --- a/models/classes/Translation/Query/ResourceTranslationQuery.php +++ b/models/classes/Translation/Query/ResourceTranslationQuery.php @@ -25,13 +25,13 @@ class ResourceTranslationQuery { private string $resourceType; - private string $uniqueId; + private array $uniqueIds; private ?string $languageUri; - public function __construct(string $resourceType, string $uniqueId, string $languageUri = null) + public function __construct(string $resourceType, array $uniqueIds, string $languageUri = null) { $this->resourceType = $resourceType; - $this->uniqueId = $uniqueId; + $this->uniqueIds = $uniqueIds; $this->languageUri = $languageUri; } @@ -40,9 +40,9 @@ public function getResourceType(): string return $this->resourceType; } - public function getUniqueId(): string + public function getUniqueIds(): array { - return $this->uniqueId; + return $this->uniqueIds; } public function getLanguageUri(): ?string diff --git a/models/classes/Translation/Repository/ResourceTranslationRepository.php b/models/classes/Translation/Repository/ResourceTranslationRepository.php index 0a377cd38b..f5c48a32a8 100644 --- a/models/classes/Translation/Repository/ResourceTranslationRepository.php +++ b/models/classes/Translation/Repository/ResourceTranslationRepository.php @@ -60,18 +60,21 @@ public function __construct( public function find(ResourceTranslationQuery $query): ResourceCollection { - $uniqueId = $query->getUniqueId(); + $uniqueIds = $query->getUniqueIds(); $resources = $this->resourceTranslatableRepository->find( new ResourceTranslatableQuery( $query->getResourceType(), - [ - $uniqueId - ] + $uniqueIds ) ); if ($resources->count() === 0) { - throw new Exception(sprintf('Translation Origin Resource %s does not exist', $uniqueId)); + throw new Exception( + sprintf( + 'Translation Origin Resource [%s] does not exist', + implode(',', $uniqueIds) + ) + ); } /** @var ResourceTranslatable $originResource */ @@ -91,8 +94,8 @@ public function find(ResourceTranslationQuery $query): ResourceCollection ); $searchQuery->addCriterion( TaoOntology::PROPERTY_UNIQUE_IDENTIFIER, - SupportedOperatorHelper::EQUAL, - $uniqueId + SupportedOperatorHelper::IN, + $uniqueIds ); if ($query->getLanguageUri()) { @@ -119,8 +122,8 @@ public function find(ResourceTranslationQuery $query): ResourceCollection } catch (Throwable $exception) { $this->logger->warning( sprintf( - 'Cannot read translation status for [uniqueId=%s, translationResourceId=%s]: %s - %s', - $uniqueId, + 'Cannot read translation status for [uniqueIds=%s, translationResourceId=%s]: %s - %s', + $uniqueIds, $translationResource->getUri(), $exception->getMessage(), $exception->getTraceAsString() diff --git a/models/classes/Translation/Service/ResourceTranslationRetriever.php b/models/classes/Translation/Service/ResourceTranslationRetriever.php index ae78fd4335..c64d951e22 100644 --- a/models/classes/Translation/Service/ResourceTranslationRetriever.php +++ b/models/classes/Translation/Service/ResourceTranslationRetriever.php @@ -73,7 +73,7 @@ public function getByRequest(ServerRequestInterface $request): ResourceCollectio return $this->resourceTranslationRepository->find( new ResourceTranslationQuery( $resourceType, - (string)$uniqueId, + [(string)$uniqueId], $languageUri ) ); diff --git a/models/classes/Translation/Service/TranslationCreationService.php b/models/classes/Translation/Service/TranslationCreationService.php index 211136ddd4..d1ceaa87f8 100644 --- a/models/classes/Translation/Service/TranslationCreationService.php +++ b/models/classes/Translation/Service/TranslationCreationService.php @@ -76,6 +76,9 @@ public function addPostCreation(string $resourceType, callable $callable): void public function createByRequest(ServerRequestInterface $request): core_kernel_classes_Resource { + // @TODO If the resource is not a ORIGINAL, it should not be translatable + // @TODO Cannot create a translation using the original language + $requestParams = $request->getParsedBody(); $id = $requestParams['id'] ?? null; @@ -85,6 +88,15 @@ public function createByRequest(ServerRequestInterface $request): core_kernel_cl $resource = $this->ontology->getResource($id); + if (!$resource->exists()) { + throw new ResourceTranslationException( + sprintf( + 'Resource %s does not exist', + $id + ) + ); + } + $parentClassIds = $resource->getParentClassesIds(); $resourceType = array_pop($parentClassIds); @@ -138,7 +150,7 @@ private function doCreate(CreateTranslationCommand $command): core_kernel_classe $translations = $this->resourceTranslationRepository->find( new ResourceTranslationQuery( $command->getResourceType(), - $command->getUniqueId(), + [$command->getUniqueId()], $command->getLanguageUri() ) ); diff --git a/models/classes/Translation/Service/TranslationUpdateService.php b/models/classes/Translation/Service/TranslationUpdateService.php index cb51957bf3..7508fabdad 100644 --- a/models/classes/Translation/Service/TranslationUpdateService.php +++ b/models/classes/Translation/Service/TranslationUpdateService.php @@ -46,6 +46,15 @@ public function update(UpdateTranslationCommand $command): core_kernel_classes_R try { $instance = $this->ontology->getResource($command->getResourceUri()); + if (!$instance->exists()) { + throw new ResourceTranslationException( + sprintf( + 'Resource %s does not exist', + $command->getResourceUri() + ) + ); + } + $translationType = $instance->getOnePropertyValue( $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_TYPE) ); From 5c86a48020e68b453ecf840f8f20a91c95d2c130 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Fri, 13 Sep 2024 11:28:23 +0200 Subject: [PATCH 47/50] chore: update unit tests --- .../Translation/Query/ResourceTranslationQueryTest.php | 6 +++--- .../Repository/ResourceTranslationRepositoryTest.php | 10 +++++++--- .../Service/ResourceTranslationRetrieverTest.php | 2 +- .../Service/TranslationUpdateServiceTest.php | 8 ++++++++ 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/test/unit/models/classes/Translation/Query/ResourceTranslationQueryTest.php b/test/unit/models/classes/Translation/Query/ResourceTranslationQueryTest.php index c75684e3a1..9df704613e 100644 --- a/test/unit/models/classes/Translation/Query/ResourceTranslationQueryTest.php +++ b/test/unit/models/classes/Translation/Query/ResourceTranslationQueryTest.php @@ -36,10 +36,10 @@ public function testConstructorAndGetters(): void $uniqueId = 'id1'; $languageUri = TaoOntology::PROPERTY_LANGUAGE; - $query = new ResourceTranslationQuery($resourceType, $uniqueId, $languageUri); + $query = new ResourceTranslationQuery($resourceType, [$uniqueId], $languageUri); $this->assertSame($resourceType, $query->getResourceType()); - $this->assertSame($uniqueId, $query->getUniqueId()); + $this->assertSame([$uniqueId], $query->getUniqueIds()); $this->assertSame($languageUri, $query->getLanguageUri()); } @@ -47,7 +47,7 @@ public function testConstructorWithoutLanguageUri(): void { $query = new ResourceTranslationQuery( 'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject', - 'id1' + ['id1'] ); $this->assertNull($query->getLanguageUri()); } diff --git a/test/unit/models/classes/Translation/Repository/ResourceTranslationRepositoryTest.php b/test/unit/models/classes/Translation/Repository/ResourceTranslationRepositoryTest.php index 92c519ee6e..37041b261c 100644 --- a/test/unit/models/classes/Translation/Repository/ResourceTranslationRepositoryTest.php +++ b/test/unit/models/classes/Translation/Repository/ResourceTranslationRepositoryTest.php @@ -99,14 +99,18 @@ protected function setUp(): void public function testFindReturnsResourceCollection(): void { $resourceType = 'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject'; - $uniqueId = 'id1'; + $uniqueIds = ['id1']; $translatable1 = $this->createMock(ResourceTranslatable::class); $translationResource1 = $this->createMock(core_kernel_classes_Resource::class); $translation1 = $this->createMock(ResourceTranslation::class); $query = $this->createMock(ResourceTranslationQuery::class); - $query->method('getResourceType')->willReturn($resourceType); - $query->method('getUniqueId')->willReturn($uniqueId); + $query + ->method('getResourceType') + ->willReturn($resourceType); + $query + ->method('getUniqueIds') + ->willReturn($uniqueIds); $this->resourceTranslatableRepository ->method('find') diff --git a/test/unit/models/classes/Translation/Service/ResourceTranslationRetrieverTest.php b/test/unit/models/classes/Translation/Service/ResourceTranslationRetrieverTest.php index a3acbd6748..a86b716bd0 100644 --- a/test/unit/models/classes/Translation/Service/ResourceTranslationRetrieverTest.php +++ b/test/unit/models/classes/Translation/Service/ResourceTranslationRetrieverTest.php @@ -79,7 +79,7 @@ public function testGetByRequest(): void ->with( new ResourceTranslationQuery( TaoOntology::CLASS_URI_ITEM, - 'uniqueId', + ['uniqueId'], null ) ) diff --git a/test/unit/models/classes/Translation/Service/TranslationUpdateServiceTest.php b/test/unit/models/classes/Translation/Service/TranslationUpdateServiceTest.php index 94ad7ea569..fecc72c129 100644 --- a/test/unit/models/classes/Translation/Service/TranslationUpdateServiceTest.php +++ b/test/unit/models/classes/Translation/Service/TranslationUpdateServiceTest.php @@ -67,6 +67,10 @@ public function testUpdateSuccess(): void ->method('getOnePropertyValue') ->willReturn($translationType); + $resource + ->method('exists') + ->willReturn(true); + $resource ->expects($this->once()) ->method('editPropertyValues') @@ -119,6 +123,10 @@ public function testOriginalCannotBeUpdated(): void ->method('getOnePropertyValue') ->willReturn($translationType); + $resource + ->method('exists') + ->willReturn(true); + $this->ontology ->method('getResource') ->willReturn($resource); From 03d8a2904191b9cdb4a62636b5226f799ce55e40 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Fri, 13 Sep 2024 11:41:46 +0200 Subject: [PATCH 48/50] chore: can only translate original resource --- .../Service/TranslationCreationService.php | 26 ++++++++++++++++--- .../TranslationCreationServiceTest.php | 2 +- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/models/classes/Translation/Service/TranslationCreationService.php b/models/classes/Translation/Service/TranslationCreationService.php index d1ceaa87f8..c55e9a0dc2 100644 --- a/models/classes/Translation/Service/TranslationCreationService.php +++ b/models/classes/Translation/Service/TranslationCreationService.php @@ -76,9 +76,6 @@ public function addPostCreation(string $resourceType, callable $callable): void public function createByRequest(ServerRequestInterface $request): core_kernel_classes_Resource { - // @TODO If the resource is not a ORIGINAL, it should not be translatable - // @TODO Cannot create a translation using the original language - $requestParams = $request->getParsedBody(); $id = $requestParams['id'] ?? null; @@ -97,6 +94,20 @@ public function createByRequest(ServerRequestInterface $request): core_kernel_cl ); } + /** @var core_kernel_classes_Resource $translationType */ + $translationType = $resource->getUniquePropertyValue( + $this->ontology->getProperty(TaoOntology::PROPERTY_TRANSLATION_TYPE) + ); + + if ($translationType->getUri() !== TaoOntology::PROPERTY_VALUE_TRANSLATION_TYPE_ORIGINAL) { + throw new ResourceTranslationException( + sprintf( + 'Resource %s is not the original', + $id + ) + ); + } + $parentClassIds = $resource->getParentClassesIds(); $resourceType = array_pop($parentClassIds); @@ -203,6 +214,15 @@ private function doCreate(CreateTranslationCommand $command): core_kernel_classe /** @var ResourceTranslatable $resource */ $resource = $resources->current(); + if ($resource->getLanguageUri() === $language->getUri()) { + throw new ResourceTranslationException( + sprintf( + 'Cannot translate to original language %s', + $command->getLanguageUri() + ) + ); + } + $instance = $this->ontology->getResource($resource->getResourceUri()); $types = $instance->getTypes(); $type = array_pop($types); diff --git a/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php b/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php index 466491f477..ff093b2f7d 100644 --- a/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php +++ b/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php @@ -104,7 +104,7 @@ public function testCreate(): void $language = $this->createMock(Language::class); $language - ->expects($this->exactly(2)) + ->expects($this->exactly(3)) ->method('getUri') ->willReturn($languageUri); $language From 804ac9532f34cf166f54ed2331315fd560f45551 Mon Sep 17 00:00:00 2001 From: Andrei Shapiro Date: Fri, 13 Sep 2024 12:56:06 +0300 Subject: [PATCH 49/50] chore: add language prefix to tao ontology --- models/classes/TaoOntology.php | 1 + 1 file changed, 1 insertion(+) diff --git a/models/classes/TaoOntology.php b/models/classes/TaoOntology.php index d87c454079..73a2ae426f 100644 --- a/models/classes/TaoOntology.php +++ b/models/classes/TaoOntology.php @@ -140,4 +140,5 @@ interface TaoOntology public const PROPERTY_UNIQUE_IDENTIFIER = 'http://www.tao.lu/Ontologies/TAO.rdf#UniqueIdentifier'; public const PROPERTY_LANGUAGE = 'http://www.tao.lu/Ontologies/TAO.rdf#Language'; + public const LANGUAGE_PREFIX = 'http://www.tao.lu/Ontologies/TAO.rdf#Lang'; } From 26236938c0d58609806a51fa55b6d3970a8e9b36 Mon Sep 17 00:00:00 2001 From: Gabriel Felipe Soares Date: Fri, 13 Sep 2024 12:00:02 +0200 Subject: [PATCH 50/50] fix: validate the only ready for translate resources are translated --- .../Entity/ResourceTranslatable.php | 5 ++ .../Service/TranslationCreationService.php | 15 ++++-- .../TranslationCreationServiceTest.php | 54 +++++++++++++++++-- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/models/classes/Translation/Entity/ResourceTranslatable.php b/models/classes/Translation/Entity/ResourceTranslatable.php index 3821fc3b18..c66619aaca 100644 --- a/models/classes/Translation/Entity/ResourceTranslatable.php +++ b/models/classes/Translation/Entity/ResourceTranslatable.php @@ -30,4 +30,9 @@ public function getStatusUri(): ?string { return $this->getMetadataValue(TaoOntology::PROPERTY_TRANSLATION_STATUS); } + + public function isReadyForTranslation(): bool + { + return $this->getStatusUri() === TaoOntology::PROPERTY_VALUE_TRANSLATION_STATUS_READY; + } } diff --git a/models/classes/Translation/Service/TranslationCreationService.php b/models/classes/Translation/Service/TranslationCreationService.php index c55e9a0dc2..add93e8f83 100644 --- a/models/classes/Translation/Service/TranslationCreationService.php +++ b/models/classes/Translation/Service/TranslationCreationService.php @@ -192,6 +192,18 @@ private function doCreate(CreateTranslationCommand $command): core_kernel_classe ); } + /** @var ResourceTranslatable $resource */ + $resource = $resources->current(); + + if (!$resource->isReadyForTranslation()) { + throw new ResourceTranslationException( + sprintf( + 'Resource [uniqueId=%s] is not ready for translation', + $command->getUniqueId() + ) + ); + } + $existingLanguages = $this->languageRepository->findAvailableLanguagesByUsage(); $language = null; @@ -211,9 +223,6 @@ private function doCreate(CreateTranslationCommand $command): core_kernel_classe ); } - /** @var ResourceTranslatable $resource */ - $resource = $resources->current(); - if ($resource->getLanguageUri() === $language->getUri()) { throw new ResourceTranslationException( sprintf( diff --git a/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php b/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php index ff093b2f7d..a759f9facc 100644 --- a/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php +++ b/test/unit/models/classes/Translation/Service/TranslationCreationServiceTest.php @@ -95,12 +95,18 @@ public function testCreate(): void $uniqueId = 'id1'; $languageUri = 'http://www.tao.lu/Ontologies/TAO.rdf#Langpt-BR'; + $translatable = $this->createMock(ResourceTranslatable::class); + $languageProperty = $this->createMock(core_kernel_classes_Property::class); $translationTypeProperty = $this->createMock(core_kernel_classes_Property::class); $translationProgressProperty = $this->createMock(core_kernel_classes_Property::class); $resourceCollection = new ResourceCollection(); - $translatableCollection = new ResourceCollection($this->createMock(ResourceTranslatable::class)); + $translatableCollection = new ResourceCollection($translatable); + + $translatable + ->method('isReadyForTranslation') + ->willReturn(true); $language = $this->createMock(Language::class); $language @@ -198,10 +204,16 @@ public function testCreate(): void public function testCreateWillFailIfTranslationAlreadyExists(): void { + $translatable = $this->createMock(ResourceTranslatable::class); + + $translatable + ->method('isReadyForTranslation') + ->willReturn(true); + $this->resourceTranslationRepository ->expects($this->once()) ->method('find') - ->willReturn(new ResourceCollection($this->createMock(ResourceTranslation::class))); + ->willReturn(new ResourceCollection($translatable)); $this->expectException(ResourceTranslationException::class); $this->expectExceptionMessage( @@ -243,6 +255,12 @@ public function testCreateWillFailIfResourceDoesNotExist(): void public function testCreateWillFailIfLanguageDoesNotExist(): void { + $translatable = $this->createMock(ResourceTranslatable::class); + + $translatable + ->method('isReadyForTranslation') + ->willReturn(true); + $this->resourceTranslationRepository ->expects($this->once()) ->method('find') @@ -251,7 +269,7 @@ public function testCreateWillFailIfLanguageDoesNotExist(): void $this->resourceTranslatableRepository ->expects($this->once()) ->method('find') - ->willReturn(new ResourceCollection($this->createMock(ResourceTranslatable::class))); + ->willReturn(new ResourceCollection($translatable)); $this->languageRepository ->expects($this->once()) @@ -269,4 +287,34 @@ public function testCreateWillFailIfLanguageDoesNotExist(): void ) ); } + + public function testCreateWillFailIfResourceIsNotReadyForTranslation(): void + { + $translatable = $this->createMock(ResourceTranslatable::class); + + $translatable + ->method('isReadyForTranslation') + ->willReturn(false); + + $this->resourceTranslationRepository + ->expects($this->once()) + ->method('find') + ->willReturn(new ResourceCollection()); + + $this->resourceTranslatableRepository + ->expects($this->once()) + ->method('find') + ->willReturn(new ResourceCollection($translatable)); + + $this->expectException(ResourceTranslationException::class); + $this->expectExceptionMessage('Resource [uniqueId=id1] is not ready for translation'); + + $this->service->create( + new CreateTranslationCommand( + TaoOntology::CLASS_URI_ITEM, + 'id1', + 'http://www.tao.lu/Ontologies/TAO.rdf#Langpt-BR' + ) + ); + } }