From f7687fb5eb644679e50273a4502f7a756b20ba21 Mon Sep 17 00:00:00 2001 From: zyberspace Date: Sun, 20 Oct 2024 12:39:54 +0200 Subject: [PATCH] Support symfony TranslatableInterface in enum fields --- docs/reference/field_types.rst | 58 +++++++++++++++++-- .../views/CRUD/display_enum.html.twig | 3 + tests/Fixtures/Enum/TranslatableSuit.php | 35 +++++++++++ .../render-element-extension-test.en.yaml | 6 ++ .../Extension/RenderElementExtensionTest.php | 19 ++++++ 5 files changed, 116 insertions(+), 5 deletions(-) create mode 100644 tests/Fixtures/Enum/TranslatableSuit.php diff --git a/docs/reference/field_types.rst b/docs/reference/field_types.rst index ad8e6e377e..9e1cef7391 100644 --- a/docs/reference/field_types.rst +++ b/docs/reference/field_types.rst @@ -16,7 +16,7 @@ Fieldtype Description ``FieldDescriptionInterface::TYPE_DATETIME`` display a formatted date and time. Accepts the options ``format`` and ``timezone`` ``FieldDescriptionInterface::TYPE_STRING`` display a text ``FieldDescriptionInterface::TYPE_EMAIL`` display a mailto link. Accepts the options ``as_string``, ``subject`` and ``body`` -``FieldDescriptionInterface::TYPE_ENUM`` display the name of a backed enum +``FieldDescriptionInterface::TYPE_ENUM`` display an enum ``FieldDescriptionInterface::TYPE_TEXTAREA`` display a textarea ``FieldDescriptionInterface::TYPE_TRANS`` translate the value with a provided ``value_translation_domain`` and ``format`` (sprintf format) option ``FieldDescriptionInterface::TYPE_FLOAT`` display a number @@ -199,13 +199,61 @@ The ``FieldDescriptionInterface::TYPE_CHOICE`` field type also supports multiple You can use the following options: -====================================== ============================================================== +====================================== ======================================================================== Option Description -====================================== ============================================================== +====================================== ======================================================================== **use_value** Determines if the field must show the value or the case' name. ``false`` by default. -**enum_translation_domain** Translation domain. -====================================== ============================================================== + + *Ignored if the enum implements Symfony's* ``TranslatableInterface`` *.* +**enum_translation_domain** | Translation domain. If set, the enum value or case' name will be send + to the translator. + | ``{{ value|trans({}, translation_domain) }}`` + + *Ignored if the enum implements Symfony's* ``TranslatableInterface`` *.* +====================================== ======================================================================== + +.. note:: + + If the enum implements Symfony's ``TranslatableInterface`` the options above will be ignored and the enum's + ``trans()`` method will be used instead to display the enum. + + This provides full compatibility with symfony's + `EnumType `_ form type: + + .. code-block:: php + + protected function configureListFields(ListMapper $list): void + { + $list + // Sonata Admin will select the `FieldDescriptionInterface::TYPE_ENUM` + // field type automatically. If the enum implements `TranslatableInterface`, + // the `trans()` method will be used to render its value. + ->add('saluation') + ; + } + + protected function configureFormFields(FormMapper $form): void + { + $form + // Symfony's EnumType form field will automatically detect the usage of + // the `TranslatableInterface` and use the enum's `trans()` method to + // render the choice labels. + ->add('salutation', EnumType::class, [ + 'class' => Salutation::class, + ]) + ; + } + + protected function configureShowFields(ShowMapper $show): void + { + $show + // Again, Sonata Admin will select the `FieldDescriptionInterface::TYPE_ENUM` + // field type automatically. If the enum implements `TranslatableInterface`, + // the `trans()` method will be used to render its value. + ->add('salutation') + ; + } ``FieldDescriptionInterface::TYPE_URL`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/Resources/views/CRUD/display_enum.html.twig b/src/Resources/views/CRUD/display_enum.html.twig index 0f1d3cd139..0a409f22d1 100644 --- a/src/Resources/views/CRUD/display_enum.html.twig +++ b/src/Resources/views/CRUD/display_enum.html.twig @@ -12,6 +12,9 @@ file that was distributed with this source code. {%- apply spaceless %} {% if value is null %}   + {% elseif value.trans is defined %} + {# Enum implements TranslatableInterface and therefore has direct control over how it should be displayed. #} + {{ value|trans }} {% else %} {% set value = use_value|default(false) ? value.value : value.name %} diff --git a/tests/Fixtures/Enum/TranslatableSuit.php b/tests/Fixtures/Enum/TranslatableSuit.php new file mode 100644 index 0000000000..3dc0269e0e --- /dev/null +++ b/tests/Fixtures/Enum/TranslatableSuit.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\AdminBundle\Tests\Fixtures\Enum; + +use Symfony\Contracts\Translation\TranslatableInterface; +use Symfony\Contracts\Translation\TranslatorInterface; + +enum TranslatableSuit: string implements TranslatableInterface +{ + case Hearts = 'hearts'; + case Diamonds = 'diamonds'; + case Clubs = 'clubs'; + case Spades = 'spades'; + + #[\Override] + public function trans(TranslatorInterface $translator, ?string $locale = null): string + { + return $translator->trans( + id: 'enum.suit.'.$this->value, + domain: 'render-element-extension-test', + locale: $locale, + ); + } +} diff --git a/tests/Fixtures/Resources/translations/render-element-extension-test.en.yaml b/tests/Fixtures/Resources/translations/render-element-extension-test.en.yaml index cc4c9e4981..1798b3da12 100644 --- a/tests/Fixtures/Resources/translations/render-element-extension-test.en.yaml +++ b/tests/Fixtures/Resources/translations/render-element-extension-test.en.yaml @@ -1,2 +1,8 @@ D: '[trans]D[/trans]' Diamonds: '[trans]Diamonds[/trans]' +enum: + suit: + hearts: '[trans]enum.suit.hearts[/trans]' + diamonds: '[trans]enum.suit.diamonds[/trans]' + clubs: '[trans]enum.suit.clubs[/trans]' + spades: '[trans]enum.suit.spades[/trans]' diff --git a/tests/Twig/Extension/RenderElementExtensionTest.php b/tests/Twig/Extension/RenderElementExtensionTest.php index 4fe9371a1c..9ccba3ee9b 100644 --- a/tests/Twig/Extension/RenderElementExtensionTest.php +++ b/tests/Twig/Extension/RenderElementExtensionTest.php @@ -22,6 +22,7 @@ use Sonata\AdminBundle\Templating\TemplateRegistryInterface; use Sonata\AdminBundle\Tests\Fixtures\Entity\FooToString; use Sonata\AdminBundle\Tests\Fixtures\Enum\Suit; +use Sonata\AdminBundle\Tests\Fixtures\Enum\TranslatableSuit; use Sonata\AdminBundle\Tests\Fixtures\StubFilesystemLoader; use Sonata\AdminBundle\Twig\Extension\RenderElementExtension; use Sonata\AdminBundle\Twig\Extension\XEditableExtension; @@ -1579,6 +1580,24 @@ class="x-editable" ], ]; + $elements[] = [ + ' [trans]enum.suit.hearts[/trans] ', + FieldDescriptionInterface::TYPE_ENUM, + TranslatableSuit::Hearts, + [], + ]; + + $elements[] = [ + ' [trans]enum.suit.spades[/trans] ', + FieldDescriptionInterface::TYPE_ENUM, + TranslatableSuit::Spades, + [ + // These values are ignored if the enum implements the TranslatableInterface + 'use_value' => false, + 'enum_translation_domain' => 'doesnt-exist', + ], + ]; + return $elements; }