From f04c970b77600060d62b48e3cae9248140227e24 Mon Sep 17 00:00:00 2001 From: Pascal CESCON - Amoifr Date: Wed, 30 Sep 2026 09:13:52 +0200 Subject: [PATCH] docs(serialization): decorate the denormalizer to change how a payload is read --- core/serialization.md | 78 ++++++++++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/core/serialization.md b/core/serialization.md index d4b077ea094..b168ffcce68 100644 --- a/core/serialization.md +++ b/core/serialization.md @@ -1126,32 +1126,24 @@ have to decorate another service: namespace App\Serializer; -use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\SerializerAwareInterface; use Symfony\Component\Serializer\SerializerInterface; -final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface +final class ApiNormalizer implements NormalizerInterface, SerializerAwareInterface { - private $decorated; - - public function __construct(NormalizerInterface $decorated) + public function __construct(private readonly NormalizerInterface $decorated) { - if (!$decorated instanceof DenormalizerInterface) { - throw new \InvalidArgumentException(sprintf('The decorated normalizer must implement the %s.', DenormalizerInterface::class)); - } - - $this->decorated = $decorated; } - public function supportsNormalization($data, $format = null) + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool { - return $this->decorated->supportsNormalization($data, $format); + return $this->decorated->supportsNormalization($data, $format, $context); } - public function normalize($object, $format = null, array $context = []) + public function normalize(mixed $data, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null { - $data = $this->decorated->normalize($object, $format, $context); + $data = $this->decorated->normalize($data, $format, $context); if (is_array($data)) { $data['date'] = date(\DateTime::RFC3339); } @@ -1159,19 +1151,67 @@ final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface, return $data; } - public function supportsDenormalization($data, $type, $format = null) + public function setSerializer(SerializerInterface $serializer): void + { + if ($this->decorated instanceof SerializerAwareInterface) { + $this->decorated->setSerializer($serializer); + } + } + + public function getSupportedTypes(?string $format): array + { + return $this->decorated->getSupportedTypes($format); + } +} +``` + +### Changing the Denormalization + +Since API Platform 4.4, incoming payloads are read by dedicated denormalizer services, which run +before the normalizers. To change how a payload is read, decorate the matching denormalizer service, +listed in the [upgrade guide](upgrade-guide.md#denormalization-moved-out-of-the-item-normalizers). +To change both directions, decorate both services. + +Decorating the normalizer with a class that also implements `DenormalizerInterface`, as in earlier +versions, still works until API Platform 6.0, but triggers a deprecation. + +```yaml +# api/config/services.yaml +services: + 'App\Serializer\ApiDenormalizer': + decorates: "api_platform.jsonld.denormalizer.item" +``` + +```php +decorated->supportsDenormalization($data, $type, $format); + return $this->decorated->supportsDenormalization($data, $type, $format, $context); } - public function denormalize($data, string $type, string $format = null, array $context = []) + public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed { + // change the incoming payload, or the context, before the resource is built return $this->decorated->denormalize($data, $type, $format, $context); } - public function setSerializer(SerializerInterface $serializer) + public function setSerializer(SerializerInterface $serializer): void { - if($this->decorated instanceof SerializerAwareInterface) { + if ($this->decorated instanceof SerializerAwareInterface) { $this->decorated->setSerializer($serializer); } }