-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
minor #15501 [API] Automatically add a default translation to transla…
…tables (NoResponseMate) This PR was merged into the 1.13 branch. Discussion ---------- | Q | A | |-----------------|--------------------------------------------------------------| | Branch? | 1.13 | | Bug fix? | kinda | | New feature? | no? | | BC breaks? | no | | Deprecations? | no | | Related tickets | - | | License | MIT | Commits ------- [API] Automatically add a default translation to translatables [API] Adjust tests after missing translation validation kicked in [API] Less naive default translation checking
- Loading branch information
Showing
18 changed files
with
376 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
src/Sylius/Bundle/ApiBundle/Serializer/TranslatableDenormalizer.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Sylius package. | ||
* | ||
* (c) Sylius Sp. z o.o. | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sylius\Bundle\ApiBundle\Serializer; | ||
|
||
use Sylius\Component\Resource\Model\TranslatableInterface; | ||
use Sylius\Component\Resource\Translation\Provider\TranslationLocaleProviderInterface; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface; | ||
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface; | ||
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait; | ||
|
||
/** @experimental */ | ||
final class TranslatableDenormalizer implements ContextAwareDenormalizerInterface, DenormalizerAwareInterface | ||
{ | ||
use DenormalizerAwareTrait; | ||
|
||
private const ALREADY_CALLED = 'sylius_translatable_denormalizer_already_called_for_%s'; | ||
|
||
public function __construct( | ||
private TranslationLocaleProviderInterface $localeProvider, | ||
) { | ||
} | ||
|
||
public function denormalize(mixed $data, string $type, string $format = null, array $context = []) | ||
{ | ||
$context[self::getAlreadyCalledKey($type)] = true; | ||
|
||
$defaultLocaleCode = $this->localeProvider->getDefaultLocaleCode(); | ||
|
||
if (!$this->hasDefaultTranslation($data['translations'] ?? [], $defaultLocaleCode)) { | ||
$data['translations'][$defaultLocaleCode] = [ | ||
'locale' => $defaultLocaleCode, | ||
]; | ||
} | ||
|
||
return $this->denormalizer->denormalize($data, $type, $format, $context); | ||
} | ||
|
||
public function supportsDenormalization(mixed $data, string $type, string $format = null, array $context = []): bool | ||
{ | ||
return | ||
Request::METHOD_POST === ($context[ContextKeys::HTTP_REQUEST_METHOD_TYPE] ?? null) && | ||
!isset($context[self::getAlreadyCalledKey($type)]) && | ||
is_a($type, TranslatableInterface::class, true) | ||
; | ||
} | ||
|
||
private static function getAlreadyCalledKey(string $class): string | ||
{ | ||
return sprintf(self::ALREADY_CALLED, $class); | ||
} | ||
|
||
private function hasDefaultTranslation(array $translations, string $defaultLocale): bool | ||
{ | ||
return | ||
isset($translations[$defaultLocale]['locale']) && | ||
$defaultLocale === $translations[$defaultLocale]['locale'] | ||
; | ||
} | ||
} |
186 changes: 186 additions & 0 deletions
186
src/Sylius/Bundle/ApiBundle/spec/Serializer/TranslatableDenormalizerSpec.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Sylius package. | ||
* | ||
* (c) Sylius Sp. z o.o. | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace spec\Sylius\Bundle\ApiBundle\Serializer; | ||
|
||
use PhpSpec\ObjectBehavior; | ||
use Sylius\Bundle\ApiBundle\Serializer\ContextKeys; | ||
use Sylius\Component\Resource\Model\TranslatableInterface; | ||
use Sylius\Component\Resource\Translation\Provider\TranslationLocaleProviderInterface; | ||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; | ||
|
||
final class TranslatableDenormalizerSpec extends ObjectBehavior | ||
{ | ||
function let( | ||
DenormalizerInterface $denormalizer, | ||
TranslationLocaleProviderInterface $localeProvider, | ||
): void { | ||
$this->beConstructedWith($localeProvider); | ||
|
||
$this->setDenormalizer($denormalizer); | ||
} | ||
|
||
function it_only_supports_translatable_resource(): void | ||
{ | ||
$this->supportsDenormalization([], TranslatableInterface::class, null, [ | ||
ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'PUT', | ||
])->shouldReturn(false); | ||
|
||
$this->supportsDenormalization([], TranslatableInterface::class, null, [ | ||
'sylius_translatable_denormalizer_already_called_for_Sylius\Component\Resource\Model\TranslatableInterface' => true, | ||
ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST', | ||
])->shouldReturn(false); | ||
|
||
$this->supportsDenormalization([], \stdClass::class, null, [ | ||
ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST', | ||
])->shouldReturn(false); | ||
} | ||
|
||
function it_does_nothing_when_data_contains_a_translation_in_default_locale( | ||
DenormalizerInterface $denormalizer, | ||
TranslationLocaleProviderInterface $localeProvider, | ||
): void { | ||
$data = ['translations' => ['en' => ['locale' => 'en']]]; | ||
|
||
$localeProvider->getDefaultLocaleCode()->willReturn('en'); | ||
|
||
$denormalizer->denormalize($data, TranslatableInterface::class, null, [ | ||
'sylius_translatable_denormalizer_already_called_for_Sylius\Component\Resource\Model\TranslatableInterface' => true, | ||
ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST', | ||
])->shouldBeCalled()->willReturn($data); | ||
|
||
$this | ||
->denormalize($data, TranslatableInterface::class, null, [ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST']) | ||
->shouldReturn($data) | ||
; | ||
} | ||
|
||
function it_adds_default_translation_when_no_translations_passed_in_data( | ||
DenormalizerInterface $denormalizer, | ||
TranslationLocaleProviderInterface $localeProvider, | ||
): void { | ||
$localeProvider->getDefaultLocaleCode()->willReturn('en'); | ||
|
||
$updatedData = ['translations' => ['en' => ['locale' => 'en']]]; | ||
|
||
$denormalizer->denormalize($updatedData, TranslatableInterface::class, null, [ | ||
'sylius_translatable_denormalizer_already_called_for_Sylius\Component\Resource\Model\TranslatableInterface' => true, | ||
ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST', | ||
])->shouldBeCalled()->willReturn($updatedData); | ||
|
||
$this | ||
->denormalize([], TranslatableInterface::class, null, [ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST']) | ||
->shouldReturn($updatedData) | ||
; | ||
} | ||
|
||
function it_adds_default_translation_when_no_translation_passed_for_default_locale_in_data( | ||
DenormalizerInterface $denormalizer, | ||
TranslationLocaleProviderInterface $localeProvider, | ||
): void { | ||
$localeProvider->getDefaultLocaleCode()->willReturn('en'); | ||
|
||
$originalData = ['translations' => ['en' => []]]; | ||
$updatedData = ['translations' => ['en' => ['locale' => 'en']]]; | ||
|
||
$denormalizer->denormalize($updatedData, TranslatableInterface::class, null, [ | ||
'sylius_translatable_denormalizer_already_called_for_Sylius\Component\Resource\Model\TranslatableInterface' => true, | ||
ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST', | ||
])->shouldBeCalled()->willReturn($updatedData); | ||
|
||
$this | ||
->denormalize($originalData, TranslatableInterface::class, null, [ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST']) | ||
->shouldReturn($updatedData) | ||
; | ||
} | ||
|
||
function it_adds_default_translation_when_passed_default_translation_has_empty_locale( | ||
DenormalizerInterface $denormalizer, | ||
TranslationLocaleProviderInterface $localeProvider, | ||
): void { | ||
$localeProvider->getDefaultLocaleCode()->willReturn('en'); | ||
|
||
$originalData = ['translations' => ['en' => ['locale' => '']]]; | ||
$updatedData = ['translations' => ['en' => ['locale' => 'en']]]; | ||
|
||
$denormalizer->denormalize($updatedData, TranslatableInterface::class, null, [ | ||
'sylius_translatable_denormalizer_already_called_for_Sylius\Component\Resource\Model\TranslatableInterface' => true, | ||
ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST', | ||
])->shouldBeCalled()->willReturn($updatedData); | ||
|
||
$this | ||
->denormalize($originalData, TranslatableInterface::class, null, [ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST']) | ||
->shouldReturn($updatedData) | ||
; | ||
} | ||
|
||
function it_adds_default_translation_when_passed_default_translation_has_null_locale( | ||
DenormalizerInterface $denormalizer, | ||
TranslationLocaleProviderInterface $localeProvider, | ||
): void { | ||
$localeProvider->getDefaultLocaleCode()->willReturn('en'); | ||
|
||
$originalData = ['translations' => ['en' => ['locale' => null]]]; | ||
$updatedData = ['translations' => ['en' => ['locale' => 'en']]]; | ||
|
||
$denormalizer->denormalize($updatedData, TranslatableInterface::class, null, [ | ||
'sylius_translatable_denormalizer_already_called_for_Sylius\Component\Resource\Model\TranslatableInterface' => true, | ||
ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST', | ||
])->shouldBeCalled()->willReturn($updatedData); | ||
|
||
$this | ||
->denormalize($originalData, TranslatableInterface::class, null, [ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST']) | ||
->shouldReturn($updatedData) | ||
; | ||
} | ||
|
||
function it_adds_default_translation_when_passed_default_translation_has_mismatched_locale( | ||
DenormalizerInterface $denormalizer, | ||
TranslationLocaleProviderInterface $localeProvider, | ||
): void { | ||
$localeProvider->getDefaultLocaleCode()->willReturn('en'); | ||
|
||
$originalData = ['translations' => ['en' => ['locale' => 'fr']]]; | ||
$updatedData = ['translations' => ['en' => ['locale' => 'en']]]; | ||
|
||
$denormalizer->denormalize($updatedData, TranslatableInterface::class, null, [ | ||
'sylius_translatable_denormalizer_already_called_for_Sylius\Component\Resource\Model\TranslatableInterface' => true, | ||
ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST', | ||
])->shouldBeCalled()->willReturn($updatedData); | ||
|
||
$this | ||
->denormalize($originalData, TranslatableInterface::class, null, [ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST']) | ||
->shouldReturn($updatedData) | ||
; | ||
} | ||
|
||
function it_adds_default_translation_when_no_translation_in_default_locale_passed_in_data( | ||
DenormalizerInterface $denormalizer, | ||
TranslationLocaleProviderInterface $localeProvider, | ||
): void { | ||
$localeProvider->getDefaultLocaleCode()->willReturn('en'); | ||
|
||
$originalData = ['translations' => ['pl' => ['locale' => 'pl']]]; | ||
$updatedData = ['translations' => ['en' => ['locale' => 'en'], 'pl' => ['locale' => 'pl']]]; | ||
|
||
$denormalizer->denormalize($updatedData, TranslatableInterface::class, null, [ | ||
'sylius_translatable_denormalizer_already_called_for_Sylius\Component\Resource\Model\TranslatableInterface' => true, | ||
ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST', | ||
])->shouldBeCalled()->willReturn($updatedData); | ||
|
||
$this | ||
->denormalize($originalData, TranslatableInterface::class, null, [ContextKeys::HTTP_REQUEST_METHOD_TYPE => 'POST']) | ||
->shouldReturn($updatedData) | ||
; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.