Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2cf9d55

Browse files
feat: improve 'not_normalizable_value_exception' (#5844)
1 parent d42f00c commit 2cf9d55

4 files changed

Lines changed: 93 additions & 7 deletions

File tree

features/main/validation.feature

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ Feature: Using validations groups
162162
{
163163
"propertyPath": "relatedDummy",
164164
"message": "This value should be of type array|string.",
165-
"code": "0"
165+
"code": "0",
166+
"hint": "The type of the \"relatedDummy\" attribute must be \"array\" (nested document) or \"string\" (IRI), \"integer\" given."
166167
},
167168
{
168169
"propertyPath": "relatedDummies",

src/JsonApi/Serializer/ItemNormalizer.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ protected function setAttributeValue(object $object, string $attribute, mixed $v
206206
* @throws RuntimeException
207207
* @throws UnexpectedValueException
208208
*/
209-
protected function denormalizeRelation(string $attributeName, ApiProperty $propertyMetadata, string $className, mixed $value, ?string $format, array $context): object
209+
protected function denormalizeRelation(string $attributeName, ApiProperty $propertyMetadata, string $className, mixed $value, ?string $format, array $context): ?object
210210
{
211211
if (!\is_array($value) || !isset($value['id'], $value['type'])) {
212212
throw new UnexpectedValueException('Only resource linkage supported currently, see: http://jsonapi.org/format/#document-resource-object-linkage.');
@@ -215,7 +215,20 @@ protected function denormalizeRelation(string $attributeName, ApiProperty $prope
215215
try {
216216
return $this->iriConverter->getResourceFromIri($value['id'], $context + ['fetch_data' => true]);
217217
} catch (ItemNotFoundException $e) {
218-
throw new RuntimeException($e->getMessage(), $e->getCode(), $e);
218+
if (!isset($context['not_normalizable_value_exceptions'])) {
219+
throw new RuntimeException($e->getMessage(), $e->getCode(), $e);
220+
}
221+
$context['not_normalizable_value_exceptions'][] = NotNormalizableValueException::createForUnexpectedDataType(
222+
$e->getMessage(),
223+
$value,
224+
[$className],
225+
$context['deserialization_path'] ?? null,
226+
true,
227+
$e->getCode(),
228+
$e
229+
);
230+
231+
return null;
219232
}
220233
}
221234

src/Serializer/AbstractItemNormalizer.php

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -540,9 +540,35 @@ protected function denormalizeRelation(string $attributeName, ApiProperty $prope
540540
try {
541541
return $this->iriConverter->getResourceFromIri($value, $context + ['fetch_data' => true]);
542542
} catch (ItemNotFoundException $e) {
543-
throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e);
543+
if (!isset($context['not_normalizable_value_exceptions'])) {
544+
throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e);
545+
}
546+
$context['not_normalizable_value_exceptions'][] = NotNormalizableValueException::createForUnexpectedDataType(
547+
$e->getMessage(),
548+
$value,
549+
[$className],
550+
$context['deserialization_path'] ?? null,
551+
true,
552+
$e->getCode(),
553+
$e
554+
);
555+
556+
return null;
544557
} catch (InvalidArgumentException $e) {
545-
throw new UnexpectedValueException(sprintf('Invalid IRI "%s".', $value), $e->getCode(), $e);
558+
if (!isset($context['not_normalizable_value_exceptions'])) {
559+
throw new UnexpectedValueException(sprintf('Invalid IRI "%s".', $value), $e->getCode(), $e);
560+
}
561+
$context['not_normalizable_value_exceptions'][] = NotNormalizableValueException::createForUnexpectedDataType(
562+
$e->getMessage(),
563+
$value,
564+
[$className],
565+
$context['deserialization_path'] ?? null,
566+
true,
567+
$e->getCode(),
568+
$e
569+
);
570+
571+
return null;
546572
}
547573
}
548574

@@ -562,10 +588,10 @@ protected function denormalizeRelation(string $attributeName, ApiProperty $prope
562588
}
563589

564590
if (!\is_array($value)) {
565-
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute must be "array" (nested document) or "string" (IRI), "%s" given.', $attributeName, \gettype($value)), $value, [Type::BUILTIN_TYPE_ARRAY, Type::BUILTIN_TYPE_STRING], $context['deserialization_path'] ?? null);
591+
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute must be "array" (nested document) or "string" (IRI), "%s" given.', $attributeName, \gettype($value)), $value, [Type::BUILTIN_TYPE_ARRAY, Type::BUILTIN_TYPE_STRING], $context['deserialization_path'] ?? null, true);
566592
}
567593

568-
throw new UnexpectedValueException(sprintf('Nested documents for attribute "%s" are not allowed. Use IRIs instead.', $attributeName));
594+
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Nested documents for attribute "%s" are not allowed. Use IRIs instead.', $attributeName), $value, [Type::BUILTIN_TYPE_ARRAY, Type::BUILTIN_TYPE_STRING], $context['deserialization_path'] ?? null, true);
569595
}
570596

571597
/**

src/Serializer/Tests/AbstractItemNormalizerTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,52 @@ public function testBadRelationType(): void
979979
$normalizer->denormalize($data, Dummy::class);
980980
}
981981

982+
public function testBadRelationTypeWithExceptionToValidationErrors(): void
983+
{
984+
$data = [
985+
'relatedDummy' => 22,
986+
];
987+
988+
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
989+
$propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn(new PropertyNameCollection(['relatedDummy']));
990+
991+
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
992+
$propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy', [])->willReturn(
993+
(new ApiProperty())->withBuiltinTypes([new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class)])->withReadable(false)->withWritable(true)->withReadableLink(false)->withWritableLink(false)
994+
);
995+
996+
$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
997+
998+
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
999+
$resourceClassResolverProphecy->getResourceClass(null, Dummy::class)->willReturn(Dummy::class);
1000+
$resourceClassResolverProphecy->getResourceClass(null, RelatedDummy::class)->willReturn(RelatedDummy::class);
1001+
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true);
1002+
$resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(true);
1003+
1004+
$propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class);
1005+
1006+
$serializerProphecy = $this->prophesize(SerializerInterface::class);
1007+
$serializerProphecy->willImplement(DenormalizerInterface::class);
1008+
1009+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
1010+
$propertyNameCollectionFactoryProphecy->reveal(),
1011+
$propertyMetadataFactoryProphecy->reveal(),
1012+
$iriConverterProphecy->reveal(),
1013+
$resourceClassResolverProphecy->reveal(),
1014+
$propertyAccessorProphecy->reveal(),
1015+
null,
1016+
null,
1017+
[],
1018+
null,
1019+
null,
1020+
]);
1021+
$normalizer->setSerializer($serializerProphecy->reveal());
1022+
1023+
// 'not_normalizable_value_exceptions' is set by Serializer thanks to DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS
1024+
$actual = $normalizer->denormalize($data, Dummy::class, null, ['not_normalizable_value_exceptions' => []]);
1025+
$this->assertNull($actual->relatedDummy);
1026+
}
1027+
9821028
public function testInnerDocumentNotAllowed(): void
9831029
{
9841030
$this->expectException(UnexpectedValueException::class);

0 commit comments

Comments
 (0)