Skip to content

Commit

Permalink
Merge pull request #4098 from oat-sa/feat/ADF-1783/translate-resources
Browse files Browse the repository at this point in the history
feat: add possibility to translate resources agnostically
  • Loading branch information
gabrielfs7 authored Sep 12, 2024
2 parents 6bbba71 + 49e0242 commit c4dd57d
Show file tree
Hide file tree
Showing 7 changed files with 650 additions and 1 deletion.
21 changes: 21 additions & 0 deletions actions/class.Translation.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
}
}
52 changes: 52 additions & 0 deletions models/classes/Translation/Command/CreateTranslationCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* 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) 2024 (original work) Open Assessment Technologies SA;
*/

declare(strict_types=1);

namespace oat\tao\model\Translation\Command;

class CreateTranslationCommand
{
private string $resourceType;
private string $uniqueId;
private string $languageUri;

public function __construct(string $resourceType, string $uniqueId, string $languageUri)
{
$this->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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
230 changes: 230 additions & 0 deletions models/classes/Translation/Service/TranslationCreationService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
<?php

/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* 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) 2024 (original work) Open Assessment Technologies SA;
*/

declare(strict_types=1);

namespace oat\tao\model\Translation\Service;

use core_kernel_classes_Resource;
use oat\generis\model\data\Ontology;
use oat\tao\model\Language\Business\Contract\LanguageRepositoryInterface;
use oat\tao\model\Language\Language;
use oat\tao\model\OntologyClassService;
use oat\tao\model\TaoOntology;
use oat\tao\model\Translation\Command\CreateTranslationCommand;
use oat\tao\model\Translation\Entity\ResourceTranslatable;
use oat\tao\model\Translation\Exception\ResourceTranslationException;
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 Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;
use Throwable;

class TranslationCreationService
{
private Ontology $ontology;
private ResourceTranslatableRepository $resourceTranslatableRepository;
private ResourceTranslationRepository $resourceTranslationRepository;
private LanguageRepositoryInterface $languageRepository;
private LoggerInterface $logger;
private array $ontologyClassServices;
private array $callables;

public function __construct(
Ontology $ontology,
ResourceTranslatableRepository $resourceTranslatableRepository,
ResourceTranslationRepository $resourceTranslationRepository,
LanguageRepositoryInterface $languageRepository,
LoggerInterface $logger
) {
$this->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
)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

/**
Expand Down Expand Up @@ -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();
}
}
Loading

0 comments on commit c4dd57d

Please sign in to comment.