diff --git a/config/definition.php b/config/definition.php index be237c6..99dd6ef 100644 --- a/config/definition.php +++ b/config/definition.php @@ -23,6 +23,12 @@ ->booleanNode('property_path')->defaultTrue()->end() ->end() ->end() + ->arrayNode('message_resolver') + ->addDefaultsIfNotSet() + ->children() + ->booleanNode('doctrine_type')->defaultTrue()->end() + ->end() + ->end() ->end() ->end() ; diff --git a/config/services/message_resolver.php b/config/services/message_resolver.php new file mode 100644 index 0000000..ed131de --- /dev/null +++ b/config/services/message_resolver.php @@ -0,0 +1,19 @@ +services() + ->set(ChainMessageResolver::class) + ->arg('$messageResolvers', tagged_iterator('sbsedv_form.message_resolver')) + + ->alias(MessageResolverInterface::class, ChainMessageResolver::class) + + ->set(DoctrineTypeMessageResolver::class) + ->tag('sbsedv_form.message_resolver', ['priority' => -100]) + ; +}; diff --git a/config/services/normalizers.php b/config/services/normalizers.php index 43e5edb..63554a1 100644 --- a/config/services/normalizers.php +++ b/config/services/normalizers.php @@ -3,6 +3,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; use SBSEDV\Bundle\FormBundle\CauseResolver\CauseResolverInterface; +use SBSEDV\Bundle\FormBundle\MessageResolver\MessageResolverInterface; use SBSEDV\Bundle\FormBundle\ParamResolver\ParamResolverInterface; use SBSEDV\Bundle\FormBundle\Serializer\Normalizer\FormErrorNormalizer; use SBSEDV\Bundle\FormBundle\Serializer\Normalizer\UnsubmittedFormNormalizer; @@ -20,6 +21,7 @@ ->args([ '$causeResolver' => service(CauseResolverInterface::class), '$paramResolver' => service(ParamResolverInterface::class), + '$messageResolver' => service(MessageResolverInterface::class), ]) ->tag('serializer.normalizer', ['priority' => 0]) ; diff --git a/src/CauseResolver/ChainCauseResolver.php b/src/CauseResolver/ChainCauseResolver.php index 57fac96..cdd1a8b 100644 --- a/src/CauseResolver/ChainCauseResolver.php +++ b/src/CauseResolver/ChainCauseResolver.php @@ -10,7 +10,7 @@ class ChainCauseResolver implements CauseResolverInterface * @param iterable $causeResolvers */ public function __construct( - private iterable $causeResolvers + private readonly iterable $causeResolvers ) { } diff --git a/src/Form/DataTransformer/BooleanTypeToBooleanDataTransformer.php b/src/Form/DataTransformer/BooleanTypeToBooleanDataTransformer.php index dba290a..9ccf7a5 100644 --- a/src/Form/DataTransformer/BooleanTypeToBooleanDataTransformer.php +++ b/src/Form/DataTransformer/BooleanTypeToBooleanDataTransformer.php @@ -11,9 +11,9 @@ class BooleanTypeToBooleanDataTransformer implements DataTransformerInterface { public function __construct( - private array $trueValues, - private array $falseValues, - private ?bool $default = null + private readonly array $trueValues, + private readonly array $falseValues, + private readonly ?bool $default = null ) { } diff --git a/src/Form/DataTransformer/CapitalizeStringDataTransformer.php b/src/Form/DataTransformer/CapitalizeStringDataTransformer.php index b9a8499..d5acc10 100644 --- a/src/Form/DataTransformer/CapitalizeStringDataTransformer.php +++ b/src/Form/DataTransformer/CapitalizeStringDataTransformer.php @@ -11,7 +11,7 @@ class CapitalizeStringDataTransformer implements DataTransformerInterface { public function __construct( - private ?string $encoding = null + private readonly ?string $encoding = null ) { } diff --git a/src/Form/DataTransformer/UppercaseStringDataTransformer.php b/src/Form/DataTransformer/UppercaseStringDataTransformer.php index 2662eb4..8e630e2 100644 --- a/src/Form/DataTransformer/UppercaseStringDataTransformer.php +++ b/src/Form/DataTransformer/UppercaseStringDataTransformer.php @@ -10,7 +10,7 @@ class UppercaseStringDataTransformer implements DataTransformerInterface { public function __construct( - private ?string $encoding = null + private readonly ?string $encoding = null ) { } diff --git a/src/Form/DataTransformer/UuidToStringDataTransformer.php b/src/Form/DataTransformer/UuidToStringDataTransformer.php index 283504f..13e8ec2 100644 --- a/src/Form/DataTransformer/UuidToStringDataTransformer.php +++ b/src/Form/DataTransformer/UuidToStringDataTransformer.php @@ -15,7 +15,7 @@ class UuidToStringDataTransformer implements DataTransformerInterface protected const NIL = '00000000-0000-0000-0000-000000000000'; public function __construct( - private bool $convertNilToNull = false + private readonly bool $convertNilToNull = false ) { } diff --git a/src/Form/FormProcessor.php b/src/Form/FormProcessor.php index 7666b99..b15d981 100644 --- a/src/Form/FormProcessor.php +++ b/src/Form/FormProcessor.php @@ -8,7 +8,7 @@ class FormProcessor implements FormProcessorInterface { - private PropertyAccessorInterface $propertyAccessor; + private readonly PropertyAccessorInterface $propertyAccessor; public function __construct(?PropertyAccessorInterface $propertyAccessor) { diff --git a/src/Form/Type/BooleanType.php b/src/Form/Type/BooleanType.php index 7c6f025..b0a975f 100644 --- a/src/Form/Type/BooleanType.php +++ b/src/Form/Type/BooleanType.php @@ -11,7 +11,7 @@ class BooleanType extends AbstractType { public function __construct( - private TranslatorInterface $translator + readonly TranslatorInterface $translator ) { } diff --git a/src/MessageResolver/ChainMessageResolver.php b/src/MessageResolver/ChainMessageResolver.php new file mode 100644 index 0000000..f3d4dd7 --- /dev/null +++ b/src/MessageResolver/ChainMessageResolver.php @@ -0,0 +1,29 @@ + $messageResolvers + */ + public function __construct( + private readonly iterable $messageResolvers + ) { + } + + public function resolveMessage(FormError $formError): ?string + { + foreach ($this->messageResolvers as $messageResolver) { + $msg = $messageResolver->resolveMessage($formError); + + if (null !== $msg) { + return $msg; + } + } + + return null; + } +} diff --git a/src/MessageResolver/DoctrineTypeMessageResolver.php b/src/MessageResolver/DoctrineTypeMessageResolver.php new file mode 100644 index 0000000..1f8f400 --- /dev/null +++ b/src/MessageResolver/DoctrineTypeMessageResolver.php @@ -0,0 +1,28 @@ +getOrigin()?->getConfig()->getType()->getInnerType(); + $cause = $formError->getCause(); + + // Incase the "multiple" option is used and an invalid id is supplied + if (!$type instanceof DoctrineType || !$cause instanceof TransformationFailedException || !\str_starts_with($cause->getMessage(), 'The choices "')) { + return null; + } + + // Currently this will always be NULL, someday symfony will maybe add translations for that error + if (null !== $cause->getInvalidMessage()) { + return \strtr($cause->getInvalidMessage(), $cause->getInvalidMessageParameters()); + } + + return $cause->getMessage(); + } +} diff --git a/src/MessageResolver/MessageResolverInterface.php b/src/MessageResolver/MessageResolverInterface.php new file mode 100644 index 0000000..7619ef2 --- /dev/null +++ b/src/MessageResolver/MessageResolverInterface.php @@ -0,0 +1,17 @@ + $paramResolvers */ public function __construct( - private iterable $paramResolvers + private readonly iterable $paramResolvers ) { } diff --git a/src/SBSEDVFormBundle.php b/src/SBSEDVFormBundle.php index 6a07533..929d964 100644 --- a/src/SBSEDVFormBundle.php +++ b/src/SBSEDVFormBundle.php @@ -14,9 +14,18 @@ public function loadExtension(array $config, ContainerConfigurator $container, C $container->import('../config/services/cause_resolver.php'); $container->import('../config/services/form_types.php'); $container->import('../config/services/form_processor.php'); + $container->import('../config/services/message_resolver.php'); $container->import('../config/services/normalizers.php'); $container->import('../config/services/param_resolver.php'); + $builder + ->registerForAutoconfiguration(MessageResolver\MessageResolverInterface::class) + ->addTag('sbsedv_form.message_resolver') + ; + if (!$config['message_resolver']['doctrine_type']) { + $container->services()->remove(MessageResolver\DoctrineTypeMessageResolver::class); + } + $builder ->registerForAutoconfiguration(CauseResolver\CauseResolverInterface::class) ->addTag('sbsedv_form.cause_resolver') diff --git a/src/Serializer/Normalizer/FormErrorNormalizer.php b/src/Serializer/Normalizer/FormErrorNormalizer.php index b545138..8778fa8 100644 --- a/src/Serializer/Normalizer/FormErrorNormalizer.php +++ b/src/Serializer/Normalizer/FormErrorNormalizer.php @@ -3,13 +3,13 @@ namespace SBSEDV\Bundle\FormBundle\Serializer\Normalizer; use SBSEDV\Bundle\FormBundle\CauseResolver\CauseResolverInterface; +use SBSEDV\Bundle\FormBundle\MessageResolver\MessageResolverInterface; use SBSEDV\Bundle\FormBundle\ParamResolver\ParamResolverInterface; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormInterface; -use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -class FormErrorNormalizer implements NormalizerInterface, CacheableSupportsMethodInterface +class FormErrorNormalizer implements NormalizerInterface { /** The value will be used as the normalized "message" key (e.g. "msg"). */ public const CONTEXT_MESSAGE_KEY = 'form_error.message_key'; @@ -19,13 +19,13 @@ class FormErrorNormalizer implements NormalizerInterface, CacheableSupportsMetho public const CONTEXT_CAUSE_KEY = 'form_error.cause_key'; /** The value will be used as the normalized "type" key */ public const CONTEXT_TYPE_KEY = 'form_error.type_key'; - /** The value that will appear under the "type" key. */ public const CONTEXT_ERROR_TYPE = 'form_error.type'; public function __construct( - private CauseResolverInterface $causeResolver, - private ParamResolverInterface $paramResolver + private readonly CauseResolverInterface $causeResolver, + private readonly ParamResolverInterface $paramResolver, + private readonly MessageResolverInterface $messageResolver ) { } @@ -53,7 +53,7 @@ public function normalize(mixed $object, string $format = null, array $context = } $error = [ - $messageKey => $formError->getMessage(), + $messageKey => $this->messageResolver->resolveMessage($formError) ?? $formError->getMessage(), $typeKey => $errorType, ]; diff --git a/src/Serializer/Normalizer/UnsubmittedFormNormalizer.php b/src/Serializer/Normalizer/UnsubmittedFormNormalizer.php index b49fcef..f5d3703 100644 --- a/src/Serializer/Normalizer/UnsubmittedFormNormalizer.php +++ b/src/Serializer/Normalizer/UnsubmittedFormNormalizer.php @@ -3,11 +3,10 @@ namespace SBSEDV\Bundle\FormBundle\Serializer\Normalizer; use Symfony\Component\Form\FormInterface; -use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Contracts\Translation\TranslatorInterface; -class UnsubmittedFormNormalizer implements NormalizerInterface, CacheableSupportsMethodInterface +class UnsubmittedFormNormalizer implements NormalizerInterface { /** The value will be used as the normalized "message" key (e.g. "msg"). */ public const CONTEXT_MESSAGE_KEY = 'form_error.message_key'; @@ -16,7 +15,7 @@ class UnsubmittedFormNormalizer implements NormalizerInterface, CacheableSupport public const CONTEXT_ERROR_TYPE = 'form_error.type'; public function __construct( - private TranslatorInterface $translator + private readonly TranslatorInterface $translator ) { }