From 4a620c75bc94919a22bc570852a5ac40642dbff1 Mon Sep 17 00:00:00 2001 From: soyuka Date: Wed, 29 Apr 2026 08:10:18 +0200 Subject: [PATCH 1/2] fix(state): preserve Type message when expectedTypes is set | Q | A | ------------- | --- | Branch? | 4.3 | Tickets | refs #7894 | License | MIT | Doc PR | N/A Only fall back to the exception message when expectedTypes is empty (Symfony 8.1 BackedEnumNormalizer). Restores BC for the validator "This value should be of type ..." translation; the user-friendly message is still available via the `hint` parameter. --- src/State/Provider/DeserializeProvider.php | 2 ++ src/State/Tests/Provider/DeserializeProviderTest.php | 6 +++--- tests/Functional/ValidationTest.php | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/State/Provider/DeserializeProvider.php b/src/State/Provider/DeserializeProvider.php index e0b3d1ad33..b73052cccc 100644 --- a/src/State/Provider/DeserializeProvider.php +++ b/src/State/Provider/DeserializeProvider.php @@ -115,6 +115,8 @@ public function provide(Operation $operation, array $uriVariables = [], array $c $parameters = []; if ($exception->canUseMessageForUser()) { $parameters['hint'] = $exception->getMessage(); + } + if (!$expectedTypes && $exception->canUseMessageForUser()) { $violationMessage = $exception->getMessage(); $violations->add(new ConstraintViolation($violationMessage, $violationMessage, $parameters, null, $exception->getPath(), null, null, (string) Type::INVALID_TYPE_ERROR)); } else { diff --git a/src/State/Tests/Provider/DeserializeProviderTest.php b/src/State/Tests/Provider/DeserializeProviderTest.php index 90a24f3cb1..1fced0c05e 100644 --- a/src/State/Tests/Provider/DeserializeProviderTest.php +++ b/src/State/Tests/Provider/DeserializeProviderTest.php @@ -208,7 +208,7 @@ public function testDeserializeSetsObjectToPopulateWhenContextIsTrue(): void } #[IgnoreDeprecations] - public function testDeserializeUsesExceptionMessageWhenCanUseMessageForUser(): void + public function testDeserializeKeepsTypeMessageWhenExpectedTypesAreSet(): void { $operation = new Post(deserialize: true, class: \stdClass::class); $decorated = $this->createStub(ProviderInterface::class); @@ -239,10 +239,10 @@ public function testDeserializeUsesExceptionMessageWhenCanUseMessageForUser(): v } catch (ValidationException $e) { $violations = $e->getConstraintViolationList(); $this->assertCount(1, $violations); - $this->assertSame('The data must belong to a backed enumeration of type Suit.', $violations[0]->getMessage()); - $this->assertSame('The data must belong to a backed enumeration of type Suit.', $violations[0]->getMessageTemplate()); + $this->assertSame('This value should be of type string.', $violations[0]->getMessage()); $this->assertSame('status', $violations[0]->getPropertyPath()); $this->assertSame((string) Type::INVALID_TYPE_ERROR, $violations[0]->getCode()); + $this->assertSame('The data must belong to a backed enumeration of type Suit.', $violations[0]->getParameters()['hint'] ?? null); } } diff --git a/tests/Functional/ValidationTest.php b/tests/Functional/ValidationTest.php index 2fa7ca46a2..6ec00a508a 100644 --- a/tests/Functional/ValidationTest.php +++ b/tests/Functional/ValidationTest.php @@ -85,7 +85,7 @@ public function testPostWithDenormalizationErrorsCollected(): void $violationBaz = $findViolation('baz'); $this->assertNotNull($violationBaz, 'Violation for "baz" not found.'); - $this->assertSame('Failed to create object because the class misses the "baz" property.', $violationBaz['message']); + $this->assertSame('This value should be of type string.', $violationBaz['message']); $this->assertArrayHasKey('hint', $violationBaz); $this->assertSame('Failed to create object because the class misses the "baz" property.', $violationBaz['hint']); @@ -117,14 +117,14 @@ public function testPostWithDenormalizationErrorsCollected(): void $violationUuid = $findViolation('uuid'); $this->assertNotNull($violationUuid); if (!method_exists(PropertyInfoExtractor::class, 'getType')) { - $this->assertSame('Invalid UUID string: y', $violationUuid['message']); + $this->assertSame('This value should be of type uuid.', $violationUuid['message']); } else { $this->assertSame('This value should be of type UuidInterface|null.', $violationUuid['message']); } $violationRelatedDummy = $findViolation('relatedDummy'); $this->assertNotNull($violationRelatedDummy); - $this->assertSame('The type of the "relatedDummy" attribute must be "array" (nested document) or "string" (IRI), "integer" given.', $violationRelatedDummy['message']); + $this->assertSame('This value should be of type array|string.', $violationRelatedDummy['message']); $violationRelatedDummies = $findViolation('relatedDummies'); $this->assertNotNull($violationRelatedDummies); From ecb3e8260c52f6aae7a12b32ad5a03dc287840d0 Mon Sep 17 00:00:00 2001 From: soyuka Date: Wed, 29 Apr 2026 08:21:26 +0200 Subject: [PATCH 2/2] test(validation): assert hints --- tests/Functional/ValidationTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Functional/ValidationTest.php b/tests/Functional/ValidationTest.php index 6ec00a508a..c82238d75d 100644 --- a/tests/Functional/ValidationTest.php +++ b/tests/Functional/ValidationTest.php @@ -125,6 +125,8 @@ public function testPostWithDenormalizationErrorsCollected(): void $violationRelatedDummy = $findViolation('relatedDummy'); $this->assertNotNull($violationRelatedDummy); $this->assertSame('This value should be of type array|string.', $violationRelatedDummy['message']); + $this->assertArrayHasKey('hint', $violationRelatedDummy); + $this->assertSame('The type of the "relatedDummy" attribute must be "array" (nested document) or "string" (IRI), "integer" given.', $violationRelatedDummy['hint']); $violationRelatedDummies = $findViolation('relatedDummies'); $this->assertNotNull($violationRelatedDummies);