Skip to content

Commit ab6f41d

Browse files
committed
fix(serializer): throw NotNormalizableValueException if a resource is not found or invalid IRI
1 parent 95242f6 commit ab6f41d

File tree

2 files changed

+66
-10
lines changed

2 files changed

+66
-10
lines changed

src/Serializer/AbstractItemNormalizer.php

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
4343
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
4444
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
45-
use Symfony\Component\Serializer\Serializer;
4645

4746
/**
4847
* Base item normalizer.
@@ -224,9 +223,32 @@ public function denormalize(mixed $data, string $class, ?string $format = null,
224223
try {
225224
return $this->iriConverter->getResourceFromIri($data, $context + ['fetch_data' => true]);
226225
} catch (ItemNotFoundException $e) {
227-
throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e);
226+
if (!isset($context['not_normalizable_value_exceptions'])) {
227+
throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e);
228+
}
229+
230+
throw NotNormalizableValueException::createForUnexpectedDataType(
231+
\sprintf('The type of the "%s" resource "string" (IRI), "%s" given.', $resourceClass, \gettype($data)),
232+
$data,
233+
[$resourceClass],
234+
$context['deserialization_path'] ?? null,
235+
true,
236+
$e->getCode(),
237+
$e
238+
);
228239
} catch (InvalidArgumentException $e) {
229-
throw new UnexpectedValueException(\sprintf('Invalid IRI "%s".', $data), $e->getCode(), $e);
240+
if (!isset($context['not_normalizable_value_exceptions'])) {
241+
throw new UnexpectedValueException(\sprintf('Invalid IRI "%s".', $data), $e->getCode(), $e);
242+
}
243+
244+
throw NotNormalizableValueException::createForUnexpectedDataType(
245+
\sprintf('The type of the "%s" resource "string" (IRI), "%s" given.', $resourceClass, \gettype($data)),
246+
$data, [$resourceClass],
247+
$context['deserialization_path'] ?? null,
248+
true,
249+
$e->getCode(),
250+
$e
251+
);
230252
}
231253
}
232254

@@ -577,7 +599,8 @@ protected function denormalizeRelation(string $attributeName, ApiProperty $prope
577599
if (!isset($context['not_normalizable_value_exceptions'])) {
578600
throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e);
579601
}
580-
$context['not_normalizable_value_exceptions'][] = NotNormalizableValueException::createForUnexpectedDataType(
602+
603+
throw NotNormalizableValueException::createForUnexpectedDataType(
581604
$e->getMessage(),
582605
$value,
583606
[$className],
@@ -586,13 +609,12 @@ protected function denormalizeRelation(string $attributeName, ApiProperty $prope
586609
$e->getCode(),
587610
$e
588611
);
589-
590-
return null;
591612
} catch (InvalidArgumentException $e) {
592613
if (!isset($context['not_normalizable_value_exceptions'])) {
593614
throw new UnexpectedValueException(\sprintf('Invalid IRI "%s".', $value), $e->getCode(), $e);
594615
}
595-
$context['not_normalizable_value_exceptions'][] = NotNormalizableValueException::createForUnexpectedDataType(
616+
617+
throw NotNormalizableValueException::createForUnexpectedDataType(
596618
$e->getMessage(),
597619
$value,
598620
[$className],
@@ -601,8 +623,6 @@ protected function denormalizeRelation(string $attributeName, ApiProperty $prope
601623
$e->getCode(),
602624
$e
603625
);
604-
605-
return null;
606626
}
607627
}
608628

src/Serializer/Tests/AbstractItemNormalizerTest.php

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
5151
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
5252
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
53-
use Symfony\Component\Serializer\Serializer;
5453
use Symfony\Component\Serializer\SerializerInterface;
5554

5655
/**
@@ -913,6 +912,43 @@ public function testDeserializationPathForNotDenormalizableRelations(): void
913912
$this->assertSame('relatedDummies[0]', $errors[0]->getPath());
914913
}
915914

915+
public function testDeserializationPathForNotDenormalizableResource(): void
916+
{
917+
$this->expectException(NotNormalizableValueException::class);
918+
919+
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
920+
921+
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
922+
923+
$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
924+
$iriConverterProphecy->getResourceFromIri(Argument::cetera())->willThrow(new InvalidArgumentException('Invalid IRI'));
925+
926+
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
927+
$resourceClassResolverProphecy->getResourceClass(null, Dummy::class)->willReturn(Dummy::class);
928+
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true);
929+
930+
$propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class);
931+
932+
$serializerProphecy = $this->prophesize(SerializerInterface::class);
933+
$serializerProphecy->willImplement(DenormalizerInterface::class);
934+
935+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
936+
$propertyNameCollectionFactoryProphecy->reveal(),
937+
$propertyMetadataFactoryProphecy->reveal(),
938+
$iriConverterProphecy->reveal(),
939+
$resourceClassResolverProphecy->reveal(),
940+
$propertyAccessorProphecy->reveal(),
941+
null,
942+
null,
943+
[],
944+
null,
945+
null,
946+
]);
947+
$normalizer->setSerializer($serializerProphecy->reveal());
948+
949+
$normalizer->denormalize('wrong IRI', Dummy::class, null, ['not_normalizable_value_exceptions' => []]);
950+
}
951+
916952
public function testInnerDocumentNotAllowed(): void
917953
{
918954
$this->expectException(UnexpectedValueException::class);

0 commit comments

Comments
 (0)