vendor/ibexa/admin-ui/src/lib/EventListener/AdminExceptionListener.php line 88

Open in your IDE?
  1. <?php
  2. /**
  3.  * @copyright Copyright (C) Ibexa AS. All rights reserved.
  4.  * @license For full copyright and license information view LICENSE file distributed with this source code.
  5.  */
  6. declare(strict_types=1);
  7. namespace Ibexa\AdminUi\EventListener;
  8. use Ibexa\Bundle\AdminUi\IbexaAdminUiBundle;
  9. use Ibexa\Contracts\AdminUi\Notification\NotificationHandlerInterface;
  10. use Ibexa\Core\MVC\Symfony\SiteAccess;
  11. use Psr\Log\LoggerAwareInterface;
  12. use Psr\Log\LoggerAwareTrait;
  13. use SplFileInfo;
  14. use Symfony\Component\Filesystem\Filesystem;
  15. use Symfony\Component\HttpFoundation\Response;
  16. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  17. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  18. use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupCollectionInterface;
  19. use Symfony\WebpackEncoreBundle\Asset\TagRenderer;
  20. use Throwable;
  21. use Twig\Environment;
  22. use Twig\Error\RuntimeError;
  23. class AdminExceptionListener implements LoggerAwareInterface
  24. {
  25.     use LoggerAwareTrait;
  26.     /** @var \Ibexa\Contracts\AdminUi\Notification\NotificationHandlerInterface */
  27.     protected $notificationHandler;
  28.     /** @var \Twig\Environment */
  29.     protected $twig;
  30.     /** @var \Symfony\WebpackEncoreBundle\Asset\TagRenderer */
  31.     protected $encoreTagRenderer;
  32.     /** @var \Symfony\WebpackEncoreBundle\Asset\EntrypointLookupCollectionInterface */
  33.     private $entrypointLookupCollection;
  34.     /** @var array */
  35.     protected $siteAccessGroups;
  36.     /** @var string */
  37.     protected $rootDir;
  38.     /** @var string */
  39.     protected $kernelEnvironment;
  40.     /** @var \Psr\Log\LogLevel::* */
  41.     private $logLevel;
  42.     /**
  43.      * @param \Twig\Environment $twig
  44.      * @param \Ibexa\Contracts\AdminUi\Notification\NotificationHandlerInterface $notificationHandler
  45.      * @param \Symfony\WebpackEncoreBundle\Asset\TagRenderer $encoreTagRenderer
  46.      * @param \Symfony\WebpackEncoreBundle\Asset\EntrypointLookupCollectionInterface $entrypointLookupCollection
  47.      * @param array $siteAccessGroups
  48.      * @param string $kernelRootDir
  49.      * @param string $kernelEnvironment
  50.      * @param \Psr\Log\LogLevel::* $logLevel
  51.      */
  52.     public function __construct(
  53.         Environment $twig,
  54.         NotificationHandlerInterface $notificationHandler,
  55.         TagRenderer $encoreTagRenderer,
  56.         EntrypointLookupCollectionInterface $entrypointLookupCollection,
  57.         array $siteAccessGroups,
  58.         string $kernelProjectDir,
  59.         string $kernelEnvironment,
  60.         string $logLevel
  61.     ) {
  62.         $this->twig $twig;
  63.         $this->notificationHandler $notificationHandler;
  64.         $this->encoreTagRenderer $encoreTagRenderer;
  65.         $this->entrypointLookupCollection $entrypointLookupCollection;
  66.         $this->siteAccessGroups $siteAccessGroups;
  67.         $this->rootDir $kernelProjectDir;
  68.         $this->kernelEnvironment $kernelEnvironment;
  69.         $this->logLevel $logLevel;
  70.     }
  71.     /**
  72.      * @param \Symfony\Component\HttpKernel\Event\ExceptionEvent $event
  73.      */
  74.     public function onKernelException(ExceptionEvent $event)
  75.     {
  76.         if ($this->kernelEnvironment !== 'prod') {
  77.             return;
  78.         }
  79.         if (!$this->isAdminException($event)) {
  80.             return;
  81.         }
  82.         $response = new Response();
  83.         $exception $event->getThrowable();
  84.         if ($exception instanceof HttpExceptionInterface) {
  85.             $response->setStatusCode($exception->getStatusCode());
  86.             $response->headers->replace($exception->getHeaders());
  87.         } else {
  88.             $response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
  89.         }
  90.         $code $response->getStatusCode();
  91.         // map exception to UI notification
  92.         $this->notificationHandler->error(/** @Ignore */
  93.             $this->getNotificationMessage($exception)
  94.         );
  95.         $this->logger->log($this->logLevel$exception->getMessage(), [
  96.             'exception' => $exception,
  97.         ]);
  98.         if ($exception instanceof RuntimeError) {
  99.             // If exception is coming from the template where encore already
  100.             // rendered resources it would result in no CSS/JS on error page.
  101.             // Thus we reset TagRenderer to prevent it from breaking error page.
  102.             $this->encoreTagRenderer->reset();
  103.             $this->entrypointLookupCollection->getEntrypointLookup('ibexa')->reset();
  104.         }
  105.         switch ($code) {
  106.             case 404:
  107.                 $content $this->twig->render('@ibexadesign/ui/error_page/404.html.twig');
  108.                 break;
  109.             case 403:
  110.                 $content $this->twig->render('@ibexadesign/ui/error_page/403.html.twig');
  111.                 break;
  112.             default:
  113.                 $content $this->twig->render('@ibexadesign/ui/error_page/unknown.html.twig');
  114.                 break;
  115.         }
  116.         $response->setContent($content);
  117.         $event->setResponse($response);
  118.     }
  119.     /**
  120.      * @param \Symfony\Component\HttpKernel\Event\ExceptionEvent $event
  121.      *
  122.      * @return bool
  123.      */
  124.     private function isAdminException(ExceptionEvent $event): bool
  125.     {
  126.         $request $event->getRequest();
  127.         /** @var \Ibexa\Core\MVC\Symfony\SiteAccess $siteAccess */
  128.         $siteAccess $request->get('siteaccess', new SiteAccess('default'));
  129.         return \in_array($siteAccess->name$this->siteAccessGroups[IbexaAdminUiBundle::ADMIN_GROUP_NAME]);
  130.     }
  131.     /**
  132.      * @param \Throwable $exception
  133.      *
  134.      * @return string
  135.      */
  136.     private function getNotificationMessage(Throwable $exception): string
  137.     {
  138.         if ($exception instanceof HttpExceptionInterface) {
  139.             return $exception->getMessage();
  140.         }
  141.         $file = new SplFileInfo($exception->getFile());
  142.         $line $exception->getLine();
  143.         $relativePathname = (new Filesystem())->makePathRelative($file->getPath(), $this->rootDir) . $file->getFilename();
  144.         $message $exception->getMessage();
  145.         return sprintf('%s [in %s:%d]'$message$relativePathname$line);
  146.     }
  147. }
  148. class_alias(AdminExceptionListener::class, 'EzSystems\EzPlatformAdminUi\EventListener\AdminExceptionListener');