vendor/friendsofsymfony/rest-bundle/EventListener/ViewResponseListener.php line 57

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the FOSRestBundle package.
  4.  *
  5.  * (c) FriendsOfSymfony <http://friendsofsymfony.github.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. namespace FOS\RestBundle\EventListener;
  11. use Doctrine\Common\Annotations\Reader;
  12. use Doctrine\Persistence\Proxy;
  13. use FOS\RestBundle\Controller\Annotations\View as ViewAnnotation;
  14. use FOS\RestBundle\FOSRestBundle;
  15. use FOS\RestBundle\View\View;
  16. use FOS\RestBundle\View\ViewHandlerInterface;
  17. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  18. use Symfony\Component\HttpFoundation\Response;
  19. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  20. use Symfony\Component\HttpKernel\Event\ViewEvent;
  21. use Symfony\Component\HttpKernel\KernelEvents;
  22. /**
  23.  * The ViewResponseListener class handles the kernel.view event and creates a {@see Response} for a {@see View} provided by the controller result.
  24.  *
  25.  * @author Lukas Kahwe Smith <smith@pooteeweet.org>
  26.  *
  27.  * @internal
  28.  */
  29. class ViewResponseListener implements EventSubscriberInterface
  30. {
  31.     /**
  32.      * @var ViewHandlerInterface
  33.      */
  34.     private $viewHandler;
  35.     private $forceView;
  36.     /**
  37.      * @var Reader|null
  38.      */
  39.     private $annotationReader;
  40.     public function __construct(ViewHandlerInterface $viewHandlerbool $forceView, ?Reader $annotationReader null)
  41.     {
  42.         $this->viewHandler $viewHandler;
  43.         $this->forceView $forceView;
  44.         $this->annotationReader $annotationReader;
  45.     }
  46.     /**
  47.      * Extracts configuration for a {@see ViewAnnotation} from the controller if present.
  48.      */
  49.     public function onKernelController(ControllerEvent $event)
  50.     {
  51.         $request $event->getRequest();
  52.         if (!$request->attributes->get(FOSRestBundle::ZONE_ATTRIBUTEtrue)) {
  53.             return;
  54.         }
  55.         $controller $event->getController();
  56.         if (!\is_array($controller) && method_exists($controller'__invoke')) {
  57.             $controller = [$controller'__invoke'];
  58.         }
  59.         if (!\is_array($controller)) {
  60.             return;
  61.         }
  62.         $className $this->getRealClass(\get_class($controller[0]));
  63.         $object = new \ReflectionClass($className);
  64.         $method $object->getMethod($controller[1]);
  65.         /** @var ViewAnnotation|null $classConfiguration */
  66.         $classConfiguration null;
  67.         /** @var ViewAnnotation|null $methodConfiguration */
  68.         $methodConfiguration null;
  69.         if (null !== $this->annotationReader) {
  70.             $classConfiguration $this->getViewConfiguration($this->annotationReader->getClassAnnotations($object));
  71.             $methodConfiguration $this->getViewConfiguration($this->annotationReader->getMethodAnnotations($method));
  72.         }
  73.         if (80000 <= \PHP_VERSION_ID) {
  74.             if (null === $classConfiguration) {
  75.                 $classAttributes array_map(
  76.                     function (\ReflectionAttribute $attribute) {
  77.                         return $attribute->newInstance();
  78.                     },
  79.                     $object->getAttributes(ViewAnnotation::class, \ReflectionAttribute::IS_INSTANCEOF)
  80.                 );
  81.                 $classConfiguration $this->getViewConfiguration($classAttributes);
  82.             }
  83.             if (null === $methodConfiguration) {
  84.                 $methodAttributes array_map(
  85.                     function (\ReflectionAttribute $attribute) {
  86.                         return $attribute->newInstance();
  87.                     },
  88.                     $method->getAttributes(ViewAnnotation::class, \ReflectionAttribute::IS_INSTANCEOF)
  89.                 );
  90.                 $methodConfiguration $this->getViewConfiguration($methodAttributes);
  91.             }
  92.         }
  93.         // An annotation/attribute on the method takes precedence over the class level
  94.         if (null !== $methodConfiguration) {
  95.             $request->attributes->set(FOSRestBundle::VIEW_ATTRIBUTE$methodConfiguration);
  96.         } elseif (null !== $classConfiguration) {
  97.             $request->attributes->set(FOSRestBundle::VIEW_ATTRIBUTE$classConfiguration);
  98.         }
  99.     }
  100.     public function onKernelView(ViewEvent $event): void
  101.     {
  102.         $request $event->getRequest();
  103.         if (!$request->attributes->get(FOSRestBundle::ZONE_ATTRIBUTEtrue)) {
  104.             return;
  105.         }
  106.         /** @var ViewAnnotation|null $configuration */
  107.         $configuration $request->attributes->get(FOSRestBundle::VIEW_ATTRIBUTE);
  108.         $view $event->getControllerResult();
  109.         if (!$view instanceof View) {
  110.             if (!$configuration instanceof ViewAnnotation && !$this->forceView) {
  111.                 return;
  112.             }
  113.             $view = new View($view);
  114.         }
  115.         if ($configuration instanceof ViewAnnotation) {
  116.             if (null !== $configuration->getStatusCode() && (null === $view->getStatusCode() || Response::HTTP_OK === $view->getStatusCode())) {
  117.                 $view->setStatusCode($configuration->getStatusCode());
  118.             }
  119.             $context $view->getContext();
  120.             if ($configuration->getSerializerGroups()) {
  121.                 if (null === $context->getGroups()) {
  122.                     $context->setGroups($configuration->getSerializerGroups());
  123.                 } else {
  124.                     $context->setGroups(array_merge($context->getGroups(), $configuration->getSerializerGroups()));
  125.                 }
  126.             }
  127.             if (true === $configuration->getSerializerEnableMaxDepthChecks()) {
  128.                 $context->enableMaxDepth();
  129.             } elseif (false === $configuration->getSerializerEnableMaxDepthChecks()) {
  130.                 $context->disableMaxDepth();
  131.             }
  132.         }
  133.         if (null === $view->getFormat()) {
  134.             $view->setFormat($request->getRequestFormat());
  135.         }
  136.         $event->setResponse($this->viewHandler->handle($view$request));
  137.     }
  138.     public static function getSubscribedEvents(): array
  139.     {
  140.         return [
  141.             KernelEvents::CONTROLLER => 'onKernelController',
  142.             KernelEvents::VIEW => ['onKernelView'30],
  143.         ];
  144.     }
  145.     /**
  146.      * @param object[] $annotations
  147.      */
  148.     private function getViewConfiguration(array $annotations): ?ViewAnnotation
  149.     {
  150.         $viewAnnotation null;
  151.         foreach ($annotations as $annotation) {
  152.             if (!$annotation instanceof ViewAnnotation) {
  153.                 continue;
  154.             }
  155.             if (null === $viewAnnotation) {
  156.                 $viewAnnotation $annotation;
  157.             } else {
  158.                 throw new \LogicException('Multiple "view" annotations are not allowed.');
  159.             }
  160.         }
  161.         return $viewAnnotation;
  162.     }
  163.     private function getRealClass(string $class): string
  164.     {
  165.         if (class_exists(Proxy::class)) {
  166.             if (false === $pos strrpos($class'\\'.Proxy::MARKER.'\\')) {
  167.                 return $class;
  168.             }
  169.             return substr($class$pos Proxy::MARKER_LENGTH 2);
  170.         }
  171.         return $class;
  172.     }
  173. }