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

Open in your IDE?
  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\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
  13. use ApiPlatform\Core\Metadata\Resource\ToggleableOperationAttributeTrait;
  14. use ApiPlatform\Exception\RuntimeException;
  15. use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
  16. use ApiPlatform\Serializer\ResourceList;
  17. use ApiPlatform\Serializer\SerializerContextBuilderInterface;
  18. use ApiPlatform\Util\OperationRequestInitiatorTrait;
  19. use ApiPlatform\Util\RequestAttributesExtractor;
  20. use Symfony\Component\HttpFoundation\Request;
  21. use Symfony\Component\HttpFoundation\Response;
  22. use Symfony\Component\HttpKernel\Event\ViewEvent;
  23. use Symfony\Component\Serializer\Encoder\EncoderInterface;
  24. use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
  25. use Symfony\Component\Serializer\SerializerInterface;
  26. use Symfony\Component\WebLink\GenericLinkProvider;
  27. use Symfony\Component\WebLink\Link;
  28. /**
  29.  * Serializes data.
  30.  *
  31.  * @author Kévin Dunglas <dunglas@gmail.com>
  32.  */
  33. final class SerializeListener
  34. {
  35.     use OperationRequestInitiatorTrait;
  36.     use ToggleableOperationAttributeTrait;
  37.     public const OPERATION_ATTRIBUTE_KEY 'serialize';
  38.     private $serializer;
  39.     private $serializerContextBuilder;
  40.     public function __construct(SerializerInterface $serializerSerializerContextBuilderInterface $serializerContextBuilder$resourceMetadataFactory null)
  41.     {
  42.         $this->serializer $serializer;
  43.         $this->serializerContextBuilder $serializerContextBuilder;
  44.         $this->resourceMetadataFactory $resourceMetadataFactory;
  45.         if ($resourceMetadataFactory && !$resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface) {
  46.             trigger_deprecation('api-platform/core''2.7'sprintf('Use "%s" instead of "%s".'ResourceMetadataCollectionFactoryInterface::class, ResourceMetadataFactoryInterface::class));
  47.         }
  48.         if ($resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface) {
  49.             $this->resourceMetadataCollectionFactory $resourceMetadataFactory;
  50.         }
  51.     }
  52.     /**
  53.      * Serializes the data to the requested format.
  54.      */
  55.     public function onKernelView(ViewEvent $event): void
  56.     {
  57.         $controllerResult $event->getControllerResult();
  58.         $request $event->getRequest();
  59.         $operation $this->initializeOperation($request);
  60.         if ($controllerResult instanceof Response) {
  61.             return;
  62.         }
  63.         $attributes RequestAttributesExtractor::extractAttributes($request);
  64.         // TODO: 3.0 adapt condition (remove legacy part)
  65.         if (
  66.             !($attributes['respond'] ?? $request->attributes->getBoolean('_api_respond'false))
  67.             || (
  68.                 (!$this->resourceMetadataFactory || $this->resourceMetadataFactory instanceof ResourceMetadataFactoryInterface)
  69.                 && $attributes
  70.                 && $this->isOperationAttributeDisabled($attributesself::OPERATION_ATTRIBUTE_KEY)
  71.             )
  72.         ) {
  73.             return;
  74.         }
  75.         if ($this->resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface &&
  76.             ($operation && !($operation->canSerialize() ?? true))
  77.         ) {
  78.             return;
  79.         }
  80.         if (!$attributes) {
  81.             $this->serializeRawData($event$request$controllerResult);
  82.             return;
  83.         }
  84.         $context $this->serializerContextBuilder->createFromRequest($requesttrue$attributes);
  85.         if (isset($context['output']) && \array_key_exists('class'$context['output']) && null === $context['output']['class']) {
  86.             $event->setControllerResult(null);
  87.             return;
  88.         }
  89.         if ($included $request->attributes->get('_api_included')) {
  90.             $context['api_included'] = $included;
  91.         }
  92.         $resources = new ResourceList();
  93.         $context['resources'] = &$resources;
  94.         $context[AbstractObjectNormalizer::EXCLUDE_FROM_CACHE_KEY][] = 'resources';
  95.         $resourcesToPush = new ResourceList();
  96.         $context['resources_to_push'] = &$resourcesToPush;
  97.         $context[AbstractObjectNormalizer::EXCLUDE_FROM_CACHE_KEY][] = 'resources_to_push';
  98.         $request->attributes->set('_api_normalization_context'$context);
  99.         $event->setControllerResult($this->serializer->serialize($controllerResult$request->getRequestFormat(), $context));
  100.         $request->attributes->set('_resources'$request->attributes->get('_resources', []) + (array) $resources);
  101.         if (!\count($resourcesToPush)) {
  102.             return;
  103.         }
  104.         $linkProvider $request->attributes->get('_links', new GenericLinkProvider());
  105.         foreach ($resourcesToPush as $resourceToPush) {
  106.             $linkProvider $linkProvider->withLink((new Link('preload'$resourceToPush))->withAttribute('as''fetch'));
  107.         }
  108.         $request->attributes->set('_links'$linkProvider);
  109.     }
  110.     /**
  111.      * Tries to serialize data that are not API resources (e.g. the entrypoint or data returned by a custom controller).
  112.      *
  113.      * @param mixed $controllerResult
  114.      *
  115.      * @throws RuntimeException
  116.      */
  117.     private function serializeRawData(ViewEvent $eventRequest $request$controllerResult): void
  118.     {
  119.         if (\is_object($controllerResult)) {
  120.             $event->setControllerResult($this->serializer->serialize($controllerResult$request->getRequestFormat(), $request->attributes->get('_api_normalization_context', [])));
  121.             return;
  122.         }
  123.         if (!$this->serializer instanceof EncoderInterface) {
  124.             throw new RuntimeException(sprintf('The serializer must implement the "%s" interface.'EncoderInterface::class));
  125.         }
  126.         $event->setControllerResult($this->serializer->encode($controllerResult$request->getRequestFormat()));
  127.     }
  128. }
  129. class_alias(SerializeListener::class, \ApiPlatform\Core\EventListener\SerializeListener::class);