vendor/friendsofsymfony/rest-bundle/Controller/ExceptionController.php line 65

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\Controller;
  11. use FOS\RestBundle\Exception\FlattenException as FosFlattenException;
  12. use FOS\RestBundle\Util\ExceptionValueMap;
  13. use FOS\RestBundle\View\View;
  14. use FOS\RestBundle\View\ViewHandlerInterface;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use Symfony\Component\HttpFoundation\Response;
  17. use Symfony\Component\ErrorHandler\Exception\FlattenException;
  18. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  19. use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
  20. /**
  21.  * Custom ExceptionController that uses the view layer and supports HTTP response status code mapping.
  22.  */
  23. class ExceptionController
  24. {
  25.     /**
  26.      * @var ViewHandlerInterface
  27.      */
  28.     private $viewHandler;
  29.     /**
  30.      * @var ExceptionValueMap
  31.      */
  32.     private $exceptionCodes;
  33.     /**
  34.      * @var bool
  35.      */
  36.     private $showException;
  37.     public function __construct(
  38.         ViewHandlerInterface $viewHandler,
  39.         ExceptionValueMap $exceptionCodes,
  40.         $showException
  41.     ) {
  42.         $this->viewHandler $viewHandler;
  43.         $this->exceptionCodes $exceptionCodes;
  44.         $this->showException $showException;
  45.     }
  46.     /**
  47.      * Converts an Exception to a Response.
  48.      *
  49.      * @param Request                   $request
  50.      * @param \Exception|\Throwable     $exception
  51.      * @param DebugLoggerInterface|null $logger
  52.      *
  53.      * @throws \InvalidArgumentException
  54.      *
  55.      * @return Response
  56.      */
  57.     public function showAction(Request $request$exceptionDebugLoggerInterface $logger null)
  58.     {
  59.         $currentContent $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1));
  60.         if ($exception instanceof \Exception) {
  61.             $code $this->getStatusCode($exception);
  62.         } else {
  63.             $code $this->getStatusCodeFromThrowable($exception);
  64.         }
  65.         $templateData $this->getTemplateData($currentContent$code$exception$logger);
  66.         if ($exception instanceof \Exception) {
  67.             $view $this->createView($exception$code$templateData$request$this->showException);
  68.         } else {
  69.             $view $this->createViewFromThrowable($exception$code$templateData$request$this->showException);
  70.         }
  71.         $response $this->viewHandler->handle($view);
  72.         return $response;
  73.     }
  74.     /**
  75.      * @param \Exception $exception
  76.      * @param int        $code
  77.      * @param array      $templateData
  78.      * @param Request    $request
  79.      * @param bool       $showException
  80.      *
  81.      * @return View
  82.      */
  83.     protected function createView(\Exception $exception$code, array $templateDataRequest $request$showException)
  84.     {
  85.         return $this->createViewFromThrowable($exception$code$templateData);
  86.     }
  87.     /**
  88.      * Determines the status code to use for the response.
  89.      *
  90.      * @param \Exception $exception
  91.      *
  92.      * @return int
  93.      */
  94.     protected function getStatusCode(\Exception $exception)
  95.     {
  96.         return $this->getStatusCodeFromThrowable($exception);
  97.     }
  98.     private function createViewFromThrowable(\Throwable $exception$code, array $templateData): View
  99.     {
  100.         $view = new View($exception$code$exception instanceof HttpExceptionInterface $exception->getHeaders() : []);
  101.         $view->setTemplateVar('raw_exception');
  102.         $view->setTemplateData($templateData);
  103.         return $view;
  104.     }
  105.     /**
  106.      * Determines the template parameters to pass to the view layer.
  107.      *
  108.      * @param string               $currentContent
  109.      * @param int                  $code
  110.      * @param \Throwable           $throwable
  111.      * @param DebugLoggerInterface $logger
  112.      *
  113.      * @return array
  114.      */
  115.     private function getTemplateData($currentContent$code, \Throwable $throwableDebugLoggerInterface $logger null)
  116.     {
  117.         if (class_exists(FlattenException::class)) {
  118.             $exception FlattenException::createFromThrowable($throwable);
  119.         } else {
  120.             $exception FosFlattenException::createFromThrowable($throwable);
  121.         }
  122.         return [
  123.             'exception' => $exception,
  124.             'status' => 'error',
  125.             'status_code' => $code,
  126.             'status_text' => array_key_exists($codeResponse::$statusTexts) ? Response::$statusTexts[$code] : 'error',
  127.             'currentContent' => $currentContent,
  128.             'logger' => $logger,
  129.         ];
  130.     }
  131.     /**
  132.      * Gets and cleans any content that was already outputted.
  133.      *
  134.      * This code comes from Symfony and should be synchronized on a regular basis
  135.      * see src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php
  136.      *
  137.      * @return string
  138.      */
  139.     private function getAndCleanOutputBuffering($startObLevel)
  140.     {
  141.         if (ob_get_level() <= $startObLevel) {
  142.             return '';
  143.         }
  144.         Response::closeOutputBuffers($startObLevel 1true);
  145.         return ob_get_clean();
  146.     }
  147.     /**
  148.      * Determines the status code to use for the response.
  149.      *
  150.      * @param \Throwable $exception
  151.      *
  152.      * @return int
  153.      */
  154.     private function getStatusCodeFromThrowable(\Throwable $exception)
  155.     {
  156.         // If matched
  157.         if ($statusCode $this->exceptionCodes->resolveThrowable($exception)) {
  158.             return $statusCode;
  159.         }
  160.         // Otherwise, default
  161.         if ($exception instanceof HttpExceptionInterface) {
  162.             return $exception->getStatusCode();
  163.         }
  164.         return 500;
  165.     }
  166. }