lib/netgen/content-browser/bundle/EventListener/ExceptionSerializerListener.php line 51

  1. <?php
  2. declare(strict_types=1);
  3. namespace Netgen\Bundle\ContentBrowserBundle\EventListener;
  4. use Exception;
  5. use Netgen\ContentBrowser\Utils\BackwardsCompatibility\ExceptionEventThrowableTrait;
  6. use Netgen\ContentBrowser\Utils\BackwardsCompatibility\MainRequestEventTrait;
  7. use Psr\Log\LoggerInterface;
  8. use Psr\Log\NullLogger;
  9. use Symfony\Component\Debug\Exception\FlattenException as DebugFlattenException;
  10. use Symfony\Component\ErrorHandler\Exception\FlattenException as ErrorHandlerFlattenException;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\HttpFoundation\JsonResponse;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  15. use Symfony\Component\HttpKernel\KernelEvents;
  16. use Throwable;
  17. use function class_exists;
  18. use function get_debug_type;
  19. use function sprintf;
  20. final class ExceptionSerializerListener implements EventSubscriberInterface
  21. {
  22.     use ExceptionEventThrowableTrait;
  23.     use MainRequestEventTrait;
  24.     private bool $outputDebugInfo;
  25.     private LoggerInterface $logger;
  26.     public function __construct(bool $outputDebugInfo, ?LoggerInterface $logger null)
  27.     {
  28.         $this->outputDebugInfo $outputDebugInfo;
  29.         $this->logger $logger ?? new NullLogger();
  30.     }
  31.     public static function getSubscribedEvents(): array
  32.     {
  33.         // Must happen BEFORE Symfony Security component ExceptionListener
  34.         return [KernelEvents::EXCEPTION => ['onException'5]];
  35.     }
  36.     /**
  37.      * Serializes the exception.
  38.      *
  39.      * @param \Symfony\Component\HttpKernel\Event\ExceptionEvent $event
  40.      */
  41.     public function onException($event): void
  42.     {
  43.         if (!$this->isMainRequest($event)) {
  44.             return;
  45.         }
  46.         $attributes $event->getRequest()->attributes;
  47.         if ($attributes->get(SetIsApiRequestListener::API_FLAG_NAME) !== true) {
  48.             return;
  49.         }
  50.         $exception $this->getThrowable($event);
  51.         $this->logException($exception);
  52.         $data = [
  53.             'code' => $exception->getCode(),
  54.             'message' => $exception->getMessage(),
  55.         ];
  56.         if ($exception instanceof HttpExceptionInterface) {
  57.             $statusCode $exception->getStatusCode();
  58.             if (isset(Response::$statusTexts[$statusCode])) {
  59.                 $data['status_code'] = $statusCode;
  60.                 $data['status_text'] = Response::$statusTexts[$statusCode];
  61.             }
  62.         }
  63.         if ($this->outputDebugInfo) {
  64.             $debugException $exception->getPrevious() ?? $exception;
  65.             if (class_exists(ErrorHandlerFlattenException::class)) {
  66.                 $debugException ErrorHandlerFlattenException::createFromThrowable($debugException);
  67.             } elseif ($debugException instanceof Exception && class_exists(DebugFlattenException::class)) {
  68.                 $debugException DebugFlattenException::create($debugException);
  69.             }
  70.             $data['debug'] = [
  71.                 'file' => $debugException->getFile(),
  72.                 'line' => $debugException->getLine(),
  73.                 'trace' => $debugException->getTrace(),
  74.             ];
  75.         }
  76.         $event->setResponse(new JsonResponse($data));
  77.     }
  78.     /**
  79.      * Logs all critical errors.
  80.      */
  81.     private function logException(Throwable $error): void
  82.     {
  83.         if ($error instanceof HttpExceptionInterface && $error->getStatusCode() < 500) {
  84.             return;
  85.         }
  86.         $this->logger->critical(
  87.             sprintf(
  88.                 'Uncaught PHP error %s: "%s" at %s line %s',
  89.                 get_debug_type($error),
  90.                 $error->getMessage(),
  91.                 $error->getFile(),
  92.                 $error->getLine(),
  93.             ),
  94.             ['error' => $error],
  95.         );
  96.     }
  97. }