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

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\Core\EventListener;
  12. use ApiPlatform\Core\Exception\RuntimeException;
  13. use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
  14. use ApiPlatform\Core\Metadata\Resource\ToggleableOperationAttributeTrait;
  15. use ApiPlatform\Core\Serializer\ResourceList;
  16. use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
  17. use ApiPlatform\Core\Util\RequestAttributesExtractor;
  18. use Fig\Link\GenericLinkProvider;
  19. use Fig\Link\Link;
  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. /**
  27.  * Serializes data.
  28.  *
  29.  * @author Kévin Dunglas <dunglas@gmail.com>
  30.  */
  31. final class SerializeListener
  32. {
  33.     use ToggleableOperationAttributeTrait;
  34.     public const OPERATION_ATTRIBUTE_KEY 'serialize';
  35.     private $serializer;
  36.     private $serializerContextBuilder;
  37.     public function __construct(SerializerInterface $serializerSerializerContextBuilderInterface $serializerContextBuilderResourceMetadataFactoryInterface $resourceMetadataFactory null)
  38.     {
  39.         $this->serializer $serializer;
  40.         $this->serializerContextBuilder $serializerContextBuilder;
  41.         $this->resourceMetadataFactory $resourceMetadataFactory;
  42.     }
  43.     /**
  44.      * Serializes the data to the requested format.
  45.      */
  46.     public function onKernelView(ViewEvent $event): void
  47.     {
  48.         $controllerResult $event->getControllerResult();
  49.         $request $event->getRequest();
  50.         if (
  51.             $controllerResult instanceof Response
  52.             || !(($attributes RequestAttributesExtractor::extractAttributes($request))['respond'] ?? $request->attributes->getBoolean('_api_respond'false))
  53.             || ($attributes && $this->isOperationAttributeDisabled($attributesself::OPERATION_ATTRIBUTE_KEY))
  54.         ) {
  55.             return;
  56.         }
  57.         if (!$attributes) {
  58.             $this->serializeRawData($event$request$controllerResult);
  59.             return;
  60.         }
  61.         $context $this->serializerContextBuilder->createFromRequest($requesttrue$attributes);
  62.         if (isset($context['output']) && \array_key_exists('class'$context['output']) && null === $context['output']['class']) {
  63.             $event->setControllerResult(null);
  64.             return;
  65.         }
  66.         if ($included $request->attributes->get('_api_included')) {
  67.             $context['api_included'] = $included;
  68.         }
  69.         $resources = new ResourceList();
  70.         $context['resources'] = &$resources;
  71.         $context[AbstractObjectNormalizer::EXCLUDE_FROM_CACHE_KEY][] = 'resources';
  72.         $resourcesToPush = new ResourceList();
  73.         $context['resources_to_push'] = &$resourcesToPush;
  74.         $context[AbstractObjectNormalizer::EXCLUDE_FROM_CACHE_KEY][] = 'resources_to_push';
  75.         $request->attributes->set('_api_normalization_context'$context);
  76.         $event->setControllerResult($this->serializer->serialize($controllerResult$request->getRequestFormat(), $context));
  77.         $request->attributes->set('_resources'$request->attributes->get('_resources', []) + (array) $resources);
  78.         if (!\count($resourcesToPush)) {
  79.             return;
  80.         }
  81.         $linkProvider $request->attributes->get('_links', new GenericLinkProvider());
  82.         foreach ($resourcesToPush as $resourceToPush) {
  83.             $linkProvider $linkProvider->withLink((new Link('preload'$resourceToPush))->withAttribute('as''fetch'));
  84.         }
  85.         $request->attributes->set('_links'$linkProvider);
  86.     }
  87.     /**
  88.      * Tries to serialize data that are not API resources (e.g. the entrypoint or data returned by a custom controller).
  89.      *
  90.      * @param mixed $controllerResult
  91.      *
  92.      * @throws RuntimeException
  93.      */
  94.     private function serializeRawData(ViewEvent $eventRequest $request$controllerResult): void
  95.     {
  96.         if (\is_object($controllerResult)) {
  97.             $event->setControllerResult($this->serializer->serialize($controllerResult$request->getRequestFormat(), $request->attributes->get('_api_normalization_context', [])));
  98.             return;
  99.         }
  100.         if (!$this->serializer instanceof EncoderInterface) {
  101.             throw new RuntimeException(sprintf('The serializer must implement the "%s" interface.'EncoderInterface::class));
  102.         }
  103.         $event->setControllerResult($this->serializer->encode($controllerResult$request->getRequestFormat()));
  104.     }
  105. }