From 6de3bfbdd920b11f3c34d9c410dd7085e6339c57 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 13 Feb 2025 14:13:41 +0100 Subject: [PATCH 1/4] Allow to set the translation domain or disable translations on a per-constraint level --- .../Component/Validator/Constraints/NotBlank.php | 6 +++++- .../Validator/Constraints/NotBlankValidator.php | 1 + .../Validator/Violation/ConstraintViolationBuilder.php | 10 ++++++++++ .../Violation/ConstraintViolationBuilderInterface.php | 2 ++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/NotBlank.php b/src/Symfony/Component/Validator/Constraints/NotBlank.php index 725e7eede4216..9fa649ffcdd1c 100644 --- a/src/Symfony/Component/Validator/Constraints/NotBlank.php +++ b/src/Symfony/Component/Validator/Constraints/NotBlank.php @@ -31,6 +31,9 @@ class NotBlank extends Constraint ]; public string $message = 'This value should not be blank.'; + + public string|false|null $translationDomain = null; + public bool $allowNull = false; /** @var callable|null */ public $normalizer; @@ -41,7 +44,7 @@ class NotBlank extends Constraint * @param string[]|null $groups */ #[HasNamedArguments] - public function __construct(?array $options = null, ?string $message = null, ?bool $allowNull = null, ?callable $normalizer = null, ?array $groups = null, mixed $payload = null) + public function __construct(?array $options = null, ?string $message = null, ?bool $allowNull = null, ?callable $normalizer = null, ?array $groups = null, mixed $payload = null, string|false|null $translationDomain = null) { if (\is_array($options)) { trigger_deprecation('symfony/validator', '7.3', 'Passing an array of options to configure the "%s" constraint is deprecated, use named arguments instead.', static::class); @@ -50,6 +53,7 @@ public function __construct(?array $options = null, ?string $message = null, ?bo parent::__construct($options ?? [], $groups, $payload); $this->message = $message ?? $this->message; + $this->translationDomain = $translationDomain ?? $this->translationDomain; $this->allowNull = $allowNull ?? $this->allowNull; $this->normalizer = $normalizer ?? $this->normalizer; diff --git a/src/Symfony/Component/Validator/Constraints/NotBlankValidator.php b/src/Symfony/Component/Validator/Constraints/NotBlankValidator.php index 2b21b3f3c52e1..7f2adbed67367 100644 --- a/src/Symfony/Component/Validator/Constraints/NotBlankValidator.php +++ b/src/Symfony/Component/Validator/Constraints/NotBlankValidator.php @@ -39,6 +39,7 @@ public function validate(mixed $value, Constraint $constraint): void $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(NotBlank::IS_BLANK_ERROR) + ->setOrDisableTranslationDomain($constraint->translationDomain) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilder.php b/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilder.php index d89932a43dbf2..e291e3a4bcbfb 100644 --- a/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilder.php +++ b/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilder.php @@ -83,6 +83,16 @@ public function disableTranslation(): static return $this; } + /** + * @return $this + */ + public function setOrDisableTranslationDomain(string|false|null $translationDomain): static + { + $this->translationDomain = $translationDomain; + + return $this; + } + public function setInvalidValue(mixed $invalidValue): static { $this->invalidValue = $invalidValue; diff --git a/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilderInterface.php b/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilderInterface.php index 195dec924f08d..914d10ba513f4 100644 --- a/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilderInterface.php +++ b/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilderInterface.php @@ -20,6 +20,8 @@ * execution context. * * @author Bernhard Schussek + * + * @method $this setOrDisableTranslationDomain(string|false|null $translationDomain) */ interface ConstraintViolationBuilderInterface { From b3fcd08500e20f540e9773f032037fcc84886a46 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 13 Feb 2025 14:59:18 +0100 Subject: [PATCH 2/4] Add a CHANGELOG notice --- src/Symfony/Component/Validator/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index ae1ae20da804d..22f8cf087c508 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -13,6 +13,7 @@ CHANGELOG * Add support for multiple fields containing nested constraints in `Composite` constraints * Add the `stopOnFirstError` option to the `Unique` constraint to validate all elements * Add support for closures in the `When` constraint + * Add `translationDomain` to all constraints; setting it to `false` disables translations for the particular constraint 7.2 --- From e152d96ba3b109675cd2d20adc2c32ec83f5bd2b Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 13 Feb 2025 16:49:03 +0100 Subject: [PATCH 3/4] Update two tests --- .../Validator/Tests/Command/DebugCommandTest.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Validator/Tests/Command/DebugCommandTest.php index 660905eba27da..3498c2397d64f 100644 --- a/src/Symfony/Component/Validator/Tests/Command/DebugCommandTest.php +++ b/src/Symfony/Component/Validator/Tests/Command/DebugCommandTest.php @@ -55,7 +55,8 @@ public function testOutputWithClassArgument() | | | | "allowNull" => false, | | | | | "message" => "This value should not be blank.", | | | | | "normalizer" => null, | -| | | | "payload" => null | +| | | | "payload" => null, | +| | | | "translationDomain" => null | | | | | ] | | email | property options | | [ | | | | | "cascadeStrategy" => "None", | @@ -111,7 +112,8 @@ public function testOutputWithPathArgument() | | | | "allowNull" => false, | | | | | "message" => "This value should not be blank.", | | | | | "normalizer" => null, | -| | | | "payload" => null | +| | | | "payload" => null, | +| | | | "translationDomain" => null | | | | | ] | | email | property options | | [ | | | | | "cascadeStrategy" => "None", | @@ -153,7 +155,8 @@ public function testOutputWithPathArgument() | | | | "allowNull" => false, | | | | | "message" => "This value should not be blank.", | | | | | "normalizer" => null, | -| | | | "payload" => null | +| | | | "payload" => null, | +| | | | "translationDomain" => null | | | | | ] | | email | property options | | [ | | | | | "cascadeStrategy" => "None", | From 4a4905d0a91790a1cb3bd2cc804e3e2b495dd142 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Tue, 11 Mar 2025 18:59:11 +0100 Subject: [PATCH 4/4] Add a test to check that the translation domain is passed on --- .../Test/ConstraintValidatorTestCase.php | 17 ++++++++++++++--- .../Tests/Constraints/NotBlankValidatorTest.php | 9 +++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php b/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php index 2fe70eaef4569..92af22bfa3886 100644 --- a/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php +++ b/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php @@ -17,6 +17,7 @@ use PHPUnit\Framework\Constraint\IsNull; use PHPUnit\Framework\Constraint\LogicalOr; use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\GroupSequence; @@ -61,6 +62,8 @@ abstract class ConstraintValidatorTestCase extends TestCase protected Constraint $constraint; protected ?string $defaultTimezone = null; + private TranslatorInterface&MockObject $translator; + private string $defaultLocale; private array $expectedViolations; private int $call; @@ -122,14 +125,14 @@ protected function restoreDefaultTimezone() protected function createContext() { - $translator = $this->createMock(TranslatorInterface::class); - $translator->expects($this->any())->method('trans')->willReturnArgument(0); + $this->translator = $this->createMock(TranslatorInterface::class); + $this->translator->expects($this->any())->method('trans')->willReturnArgument(0); $validator = $this->createMock(ValidatorInterface::class); $validator->expects($this->any()) ->method('validate') ->willReturnCallback(fn () => $this->expectedViolations[$this->call++] ?? new ConstraintViolationList()); - $context = new ExecutionContext($validator, $this->root, $translator); + $context = new ExecutionContext($validator, $this->root, $this->translator); $context->setGroup($this->group); $context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath); $context->setConstraint($this->constraint); @@ -277,6 +280,14 @@ protected function expectViolationsAt(int $i, mixed $value, Constraint $constrai return $context->getViolations(); } + protected function expectTranslationDomain(string $translationDomain) + { + $this->translator + ->expects($this->atLeastOnce()) + ->method('trans') + ->with($this->anything(), $this->anything(), $translationDomain, $this->anything()); + } + protected function assertNoViolation() { $this->assertSame(0, $violationsCount = \count($this->context->getViolations()), \sprintf('0 violation expected. Got %u.', $violationsCount)); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotBlankValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotBlankValidatorTest.php index 42d5f3a6010bf..ce18bd142f2d3 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/NotBlankValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotBlankValidatorTest.php @@ -55,6 +55,15 @@ public function testNullIsInvalid() ->assertRaised(); } + public function testTranslationDomain() + { + $constraint = new NotBlank(translationDomain: 'my_domain'); + + $this->expectTranslationDomain('my_domain'); + + $this->validator->validate(null, $constraint); + } + public function testBlankIsInvalid() { $constraint = new NotBlank(message: 'myMessage');