vendor/api-platform/core/src/Symfony/EventListener/DeserializeListener.php line 48

  1. <?php
  2. /*
  3.  * This file is part of the API Platform project.
  4.  *
  5.  * (c) Kévin Dunglas <dunglas@gmail.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. declare(strict_types=1);
  11. namespace ApiPlatform\Symfony\EventListener;
  12. use ApiPlatform\Api\FormatMatcher;
  13. use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
  14. use ApiPlatform\Serializer\SerializerContextBuilderInterface;
  15. use ApiPlatform\Util\OperationRequestInitiatorTrait;
  16. use ApiPlatform\Util\RequestAttributesExtractor;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\HttpKernel\Event\RequestEvent;
  19. use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
  20. use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
  21. use Symfony\Component\Serializer\SerializerInterface;
  22. /**
  23.  * Updates the entity retrieved by the data provider with data contained in the request body.
  24.  *
  25.  * @author Kévin Dunglas <dunglas@gmail.com>
  26.  */
  27. final class DeserializeListener
  28. {
  29.     use OperationRequestInitiatorTrait;
  30.     public const OPERATION_ATTRIBUTE_KEY 'deserialize';
  31.     public function __construct(private readonly SerializerInterface $serializer, private readonly SerializerContextBuilderInterface $serializerContextBuilder, ?ResourceMetadataCollectionFactoryInterface $resourceMetadataFactory null)
  32.     {
  33.         $this->resourceMetadataCollectionFactory $resourceMetadataFactory;
  34.     }
  35.     /**
  36.      * Deserializes the data sent in the requested format.
  37.      *
  38.      * @throws UnsupportedMediaTypeHttpException
  39.      */
  40.     public function onKernelRequest(RequestEvent $event): void
  41.     {
  42.         $request $event->getRequest();
  43.         $method $request->getMethod();
  44.         if (
  45.             'DELETE' === $method
  46.             || $request->isMethodSafe()
  47.             || !($attributes RequestAttributesExtractor::extractAttributes($request))
  48.             || !$attributes['receive']
  49.         ) {
  50.             return;
  51.         }
  52.         $operation $this->initializeOperation($request);
  53.         if (!($operation?->canDeserialize() ?? true)) {
  54.             return;
  55.         }
  56.         $context $this->serializerContextBuilder->createFromRequest($requestfalse$attributes);
  57.         $format $this->getFormat($request$operation?->getInputFormats() ?? []);
  58.         $data $request->attributes->get('data');
  59.         if (null !== $data) {
  60.             $context[AbstractNormalizer::OBJECT_TO_POPULATE] = $data;
  61.         }
  62.         $request->attributes->set(
  63.             'data',
  64.             $this->serializer->deserialize($request->getContent(), $context['resource_class'], $format$context)
  65.         );
  66.     }
  67.     /**
  68.      * Extracts the format from the Content-Type header and check that it is supported.
  69.      *
  70.      * @throws UnsupportedMediaTypeHttpException
  71.      */
  72.     private function getFormat(Request $request, array $formats): string
  73.     {
  74.         /** @var ?string $contentType */
  75.         $contentType $request->headers->get('CONTENT_TYPE');
  76.         if (null === $contentType) {
  77.             throw new UnsupportedMediaTypeHttpException('The "Content-Type" header must exist.');
  78.         }
  79.         $formatMatcher = new FormatMatcher($formats);
  80.         $format $formatMatcher->getFormat($contentType);
  81.         if (null === $format) {
  82.             $supportedMimeTypes = [];
  83.             foreach ($formats as $mimeTypes) {
  84.                 foreach ($mimeTypes as $mimeType) {
  85.                     $supportedMimeTypes[] = $mimeType;
  86.                 }
  87.             }
  88.             throw new UnsupportedMediaTypeHttpException(sprintf('The content-type "%s" is not supported. Supported MIME types are "%s".'$contentTypeimplode('", "'$supportedMimeTypes)));
  89.         }
  90.         return $format;
  91.     }
  92. }