Skip to content

Commit

Permalink
feat: Improved *locale* management by storing _translation into Req…
Browse files Browse the repository at this point in the history
…uest attributes during LocaleSubscriber
  • Loading branch information
roadiz-ci committed Feb 13, 2024
1 parent 58ccc8d commit b27b65a
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 141 deletions.
7 changes: 7 additions & 0 deletions src/Api/Controller/GetWebResponseByPathController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use RZ\Roadiz\Core\AbstractEntities\PersistableInterface;
use RZ\Roadiz\CoreBundle\Api\DataTransformer\WebResponseDataTransformerInterface;
use RZ\Roadiz\CoreBundle\Api\Model\WebResponseInterface;
use RZ\Roadiz\CoreBundle\Entity\NodesSources;
use RZ\Roadiz\CoreBundle\Entity\Redirection;
use RZ\Roadiz\CoreBundle\NodeType\ApiResourceOperationNameGenerator;
use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface;
Expand Down Expand Up @@ -58,6 +59,12 @@ public function __invoke(?Request $request): ?WebResponseInterface
$request->attributes->set('_api_operation_name', $operationName);
$request->attributes->set('_api_resource_class', $resourceClass);
$request->attributes->set('_stateless', true);

if ($resource instanceof NodesSources) {
$request->attributes->set('_translation', $resource->getTranslation());
$request->attributes->set('_locale', $resource->getTranslation()->getPreferredLocale());
}

return $this->webResponseDataTransformer->transform($resource, WebResponseInterface::class);
} catch (ResourceNotFoundException|ResourceClassNotFoundException $exception) {
throw $this->createNotFoundException($exception->getMessage(), $exception);
Expand Down
5 changes: 5 additions & 0 deletions src/Api/Controller/TranslationAwareControllerTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ abstract protected function getPreviewResolver(): PreviewResolverInterface;
protected function getTranslation(Request $request): TranslationInterface
{
$locale = $request->query->get('_locale');
$requestTranslation = $request->attributes->get('_translation');
if ($requestTranslation instanceof TranslationInterface) {
return $requestTranslation;
}

/** @var TranslationRepository $repository */
$repository = $this->getManagerRegistry()->getRepository(TranslationInterface::class);
if (!\is_string($locale) || $locale === '') {
Expand Down
112 changes: 16 additions & 96 deletions src/Controller/CustomFormController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,12 @@
use League\Flysystem\FilesystemException;
use Limenius\Liform\LiformInterface;
use Psr\Log\LoggerInterface;
use RZ\Roadiz\Core\AbstractEntities\TranslationInterface;
use RZ\Roadiz\CoreBundle\Bag\Settings;
use RZ\Roadiz\CoreBundle\CustomForm\CustomFormHelperFactory;
use RZ\Roadiz\CoreBundle\CustomForm\Message\CustomFormAnswerNotifyMessage;
use RZ\Roadiz\CoreBundle\Entity\CustomForm;
use RZ\Roadiz\CoreBundle\Exception\EntityAlreadyExistsException;
use RZ\Roadiz\CoreBundle\Form\Error\FormErrorSerializerInterface;
use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface;
use RZ\Roadiz\CoreBundle\Repository\TranslationRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
Expand All @@ -32,47 +29,22 @@
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\RateLimiter\RateLimiterFactory;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

final class CustomFormController extends AbstractController
{
private Settings $settingsBag;
private LoggerInterface $logger;
private TranslatorInterface $translator;
private CustomFormHelperFactory $customFormHelperFactory;
private LiformInterface $liform;
private SerializerInterface $serializer;
private FormErrorSerializerInterface $formErrorSerializer;
private ManagerRegistry $registry;
private RateLimiterFactory $customFormLimiter;
private PreviewResolverInterface $previewResolver;
private MessageBusInterface $messageBus;

public function __construct(
Settings $settingsBag,
LoggerInterface $logger,
TranslatorInterface $translator,
CustomFormHelperFactory $customFormHelperFactory,
LiformInterface $liform,
SerializerInterface $serializer,
FormErrorSerializerInterface $formErrorSerializer,
ManagerRegistry $registry,
RateLimiterFactory $customFormLimiter,
PreviewResolverInterface $previewResolver,
MessageBusInterface $messageBus,
private readonly Settings $settingsBag,
private readonly LoggerInterface $logger,
private readonly TranslatorInterface $translator,
private readonly CustomFormHelperFactory $customFormHelperFactory,
private readonly LiformInterface $liform,
private readonly SerializerInterface $serializer,
private readonly FormErrorSerializerInterface $formErrorSerializer,
private readonly ManagerRegistry $registry,
private readonly RateLimiterFactory $customFormLimiter,
private readonly MessageBusInterface $messageBus,
) {
$this->settingsBag = $settingsBag;
$this->logger = $logger;
$this->translator = $translator;
$this->customFormHelperFactory = $customFormHelperFactory;
$this->liform = $liform;
$this->serializer = $serializer;
$this->formErrorSerializer = $formErrorSerializer;
$this->registry = $registry;
$this->customFormLimiter = $customFormLimiter;
$this->previewResolver = $previewResolver;
$this->messageBus = $messageBus;
}

protected function validateCustomForm(?CustomForm $customForm): void
Expand All @@ -85,38 +57,6 @@ protected function validateCustomForm(?CustomForm $customForm): void
}
}

protected function getTranslationFromRequest(?Request $request): TranslationInterface
{
$locale = null;

if (null !== $request) {
$locale = $request->query->get('_locale');

/*
* If no _locale query param is defined check Accept-Language header
*/
if (null === $locale) {
$locale = $request->getPreferredLanguage($this->getTranslationRepository()->getAllLocales());
}
}
/*
* Then fallback to default CMS locale
*/
if (null === $locale) {
$translation = $this->getTranslationRepository()->findDefault();
} elseif ($this->previewResolver->isPreview()) {
$translation = $this->getTranslationRepository()
->findOneByLocaleOrOverrideLocale((string) $locale);
} else {
$translation = $this->getTranslationRepository()
->findOneAvailableByLocaleOrOverrideLocale((string) $locale);
}
if (null === $translation) {
throw new NotFoundHttpException('No translation for locale ' . $locale);
}
return $translation;
}

/**
* @param Request $request
* @param int $id
Expand All @@ -129,11 +69,6 @@ public function definitionAction(Request $request, int $id): JsonResponse
$this->validateCustomForm($customForm);

$helper = $this->customFormHelperFactory->createHelper($customForm);
$translation = $this->getTranslationFromRequest($request);
$request->setLocale($translation->getPreferredLocale());
if ($this->translator instanceof LocaleAwareInterface) {
$this->translator->setLocale($translation->getPreferredLocale());
}
$schema = json_encode($this->liform->transform($helper->getForm($request, false, false)));

return new JsonResponse(
Expand Down Expand Up @@ -169,12 +104,6 @@ public function postAction(Request $request, int $id): Response
$customForm = $this->registry->getRepository(CustomForm::class)->find($id);
$this->validateCustomForm($customForm);

$translation = $this->getTranslationFromRequest($request);
$request->setLocale($translation->getPreferredLocale());
if ($this->translator instanceof LocaleAwareInterface) {
$this->translator->setLocale($translation->getPreferredLocale());
}

$mixed = $this->prepareAndHandleCustomFormAssignation(
$request,
$customForm,
Expand Down Expand Up @@ -322,10 +251,13 @@ public function prepareAndHandleCustomFormAssignation(
['%name%' => $customFormsEntity->getDisplayName()]
);

$session = $request->getSession();
if ($session instanceof Session) {
$session->getFlashBag()->add('confirm', $msg);
if (!$request->attributes->getBoolean('_stateless') && $request->hasPreviousSession()) {
$session = $request->getSession();
if ($session instanceof Session) {
$session->getFlashBag()->add('confirm', $msg);
}
}

$this->logger->info($msg);

return $response;
Expand All @@ -338,16 +270,4 @@ public function prepareAndHandleCustomFormAssignation(
$assignation['formObject'] = $form;
return $assignation;
}

protected function getTranslationRepository(): TranslationRepository
{
$repository = $this->registry->getRepository(TranslationInterface::class);
if (!$repository instanceof TranslationRepository) {
throw new \RuntimeException(
'Translation repository must be instance of ' .
TranslationRepository::class
);
}
return $repository;
}
}
63 changes: 53 additions & 10 deletions src/EventSubscriber/LocaleSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@
use Doctrine\Persistence\ManagerRegistry;
use RZ\Roadiz\Core\AbstractEntities\TranslationInterface;
use RZ\Roadiz\CoreBundle\Entity\Translation;
use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface;
use RZ\Roadiz\CoreBundle\Repository\TranslationRepository;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Routing\RequestContextAwareInterface;

final class LocaleSubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly PreviewResolverInterface $previewResolver,
private readonly ManagerRegistry $managerRegistry,
private readonly RequestContextAwareInterface $router
) {
Expand All @@ -30,9 +34,40 @@ public static function getSubscribedEvents(): array
];
}

private function getRepository(): TranslationRepository
{
return $this->managerRegistry->getRepository(Translation::class);
}

private function getDefaultTranslation(): ?TranslationInterface
{
return $this->managerRegistry->getRepository(Translation::class)->findDefault();
return $this->getRepository()->findDefault();
}

private function supportsLocale(?string $locale): bool
{
if (null === $locale || $locale === '') {
return false;
}

if ($this->previewResolver->isPreview()) {
$locales = $this->getRepository()->getAllLocales();
} else {
$locales = $this->getRepository()->getAvailableLocales();
}
return \in_array(
$locale,
$locales,
true
);
}

private function getTranslationByLocale(string $locale): ?TranslationInterface
{
if ($this->previewResolver->isPreview()) {
return $this->getRepository()->findOneByLocaleOrOverrideLocale($locale);
}
return $this->getRepository()->findOneAvailableByLocaleOrOverrideLocale($locale);
}

public function onKernelRequest(RequestEvent $event): void
Expand All @@ -43,29 +78,37 @@ public function onKernelRequest(RequestEvent $event): void
/*
* Set default locale
*/
if (null !== $locale && $locale !== '') {
$this->setLocale($event, $locale);
if ($this->supportsLocale($locale)) {
$this->setTranslation($request, $this->getTranslationByLocale($locale));
return;
}

if (!$request->attributes->getBoolean('_stateless') && $request->hasPreviousSession()) {
$locale = $request->getSession()->get('_locale', null);
if (null !== $locale) {
$this->setLocale($event, $locale);
$sessionLocale = $request->getSession()->get('_locale', null);
if ($this->supportsLocale($sessionLocale)) {
$this->setTranslation($request, $this->getTranslationByLocale($sessionLocale));
return;
}
}

if (null !== $translation = $this->getDefaultTranslation()) {
$shortLocale = $translation->getLocale();
$this->setLocale($event, $shortLocale);
$this->setTranslation($request, $translation);
return;
}
}

private function setLocale(RequestEvent $event, string $locale): void
private function setTranslation(Request $request, ?TranslationInterface $translation): void
{
$event->getRequest()->setLocale($locale);
if (null === $translation) {
return;
}
$locale = $translation->getPreferredLocale();
/*
* Set current translation globally for controllers, utils, etc
*/
$request->attributes->set('_translation', $translation);
$request->attributes->set('_locale', $locale);
$request->setLocale($locale);
\Locale::setDefault($locale);
$this->router->getContext()->setParameter('_locale', $locale);
}
Expand Down
1 change: 0 additions & 1 deletion src/EventSubscriber/NodeNameSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ public static function getSubscribedEvents(): array
{
return [
NodesSourcesPreUpdatedEvent::class => ['onBeforeUpdate', 0],
'\RZ\Roadiz\Core\Events\NodesSources\NodesSourcesPreUpdatedEvent' => ['onBeforeUpdate', 0],
];
}

Expand Down
1 change: 0 additions & 1 deletion src/EventSubscriber/NodeRedirectionSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ public static function getSubscribedEvents(): array
{
return [
NodePathChangedEvent::class => 'redirectOldPaths',
'\RZ\Roadiz\Core\Events\Node\NodePathChangedEvent' => 'redirectOldPaths'
];
}

Expand Down
1 change: 0 additions & 1 deletion src/EventSubscriber/NodesSourcesUniversalSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public static function getSubscribedEvents(): array
{
return [
NodesSourcesUpdatedEvent::class => 'duplicateUniversalContents',
'\RZ\Roadiz\Core\Events\NodesSources\NodesSourcesUpdatedEvent' => 'duplicateUniversalContents',
];
}

Expand Down
11 changes: 0 additions & 11 deletions src/EventSubscriber/NodesSourcesUrlsCacheEventSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,28 +37,17 @@ public static function getSubscribedEvents(): array
{
return [
NodesSourcesCreatedEvent::class => 'onPurgeRequest',
'\RZ\Roadiz\Core\Events\NodesSources\NodesSourcesCreatedEvent' => 'onPurgeRequest',
NodesSourcesDeletedEvent::class => 'onPurgeRequest',
'\RZ\Roadiz\Core\Events\NodesSources\NodesSourcesDeletedEvent' => 'onPurgeRequest',
TranslationUpdatedEvent::class => 'onPurgeRequest',
'\RZ\Roadiz\Core\Events\Translation\TranslationUpdatedEvent' => 'onPurgeRequest',
TranslationDeletedEvent::class => 'onPurgeRequest',
'\RZ\Roadiz\Core\Events\Translation\TranslationDeletedEvent' => 'onPurgeRequest',
NodeDeletedEvent::class => 'onPurgeRequest',
'\RZ\Roadiz\Core\Events\Node\NodeDeletedEvent' => 'onPurgeRequest',
NodeUndeletedEvent::class => 'onPurgeRequest',
'\RZ\Roadiz\Core\Events\Node\NodeUndeletedEvent' => 'onPurgeRequest',
NodeUpdatedEvent::class => 'onPurgeRequest',
'\RZ\Roadiz\Core\Events\Node\NodeUpdatedEvent' => 'onPurgeRequest',
UrlAliasCreatedEvent::class => 'onPurgeRequest',
'\RZ\Roadiz\Core\Events\UrlAlias\UrlAliasCreatedEvent' => 'onPurgeRequest',
UrlAliasUpdatedEvent::class => 'onPurgeRequest',
'\RZ\Roadiz\Core\Events\UrlAlias\UrlAliasUpdatedEvent' => 'onPurgeRequest',
UrlAliasDeletedEvent::class => 'onPurgeRequest',
'\RZ\Roadiz\Core\Events\UrlAlias\UrlAliasDeletedEvent' => 'onPurgeRequest',
'workflow.node.completed' => 'onPurgeRequest',
CachePurgeRequestEvent::class => ['onPurgeRequest', 3],
'\RZ\Roadiz\Core\Events\Cache\CachePurgeRequestEvent' => ['onPurgeRequest', 3],
];
}

Expand Down
1 change: 0 additions & 1 deletion src/EventSubscriber/OPCacheEventSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ public static function getSubscribedEvents(): array
{
return [
CachePurgeRequestEvent::class => ['onPurgeRequest', 3],
'\RZ\Roadiz\Core\Events\Cache\CachePurgeRequestEvent' => ['onPurgeRequest', 3],
];
}

Expand Down
2 changes: 0 additions & 2 deletions src/EventSubscriber/ReverseProxyCacheEventSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ public static function getSubscribedEvents(): array
{
return [
CachePurgeRequestEvent::class => ['onBanRequest', 3],
'\RZ\Roadiz\Core\Events\Cache\CachePurgeRequestEvent' => ['onBanRequest', 3],
NodesSourcesUpdatedEvent::class => ['onPurgeRequest', 3],
'\RZ\Roadiz\Core\Events\NodesSources\NodesSourcesUpdatedEvent' => ['onPurgeRequest', 3],
'workflow.node.completed' => ['onNodeWorkflowCompleted', 3],
];
}
Expand Down
3 changes: 0 additions & 3 deletions src/EventSubscriber/RoleSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,8 @@ public static function getSubscribedEvents(): array
{
return [
PreCreatedRoleEvent::class => 'onRoleChanged',
'\RZ\Roadiz\Core\Events\Role\PreCreatedRoleEvent' => 'onRoleChanged',
PreUpdatedRoleEvent::class => 'onRoleChanged',
'\RZ\Roadiz\Core\Events\Role\PreUpdatedRoleEvent' => 'onRoleChanged',
PreDeletedRoleEvent::class => 'onRoleChanged',
'\RZ\Roadiz\Core\Events\Role\PreDeletedRoleEvent' => 'onRoleChanged',
];
}

Expand Down
Loading

0 comments on commit b27b65a

Please sign in to comment.