vendor/pimcore/pimcore/bundles/AdminBundle/EventListener/AdminExceptionListener.php line 52

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4.  * Pimcore
  5.  *
  6.  * This source file is available under two different licenses:
  7.  * - GNU General Public License version 3 (GPLv3)
  8.  * - Pimcore Commercial License (PCL)
  9.  * Full copyright and license information is available in
  10.  * LICENSE.md which is distributed with this source code.
  11.  *
  12.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  13.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  14.  */
  15. namespace Pimcore\Bundle\AdminBundle\EventListener;
  16. use Doctrine\DBAL\Exception as DBALException;
  17. use Pimcore\Bundle\AdminBundle\HttpFoundation\JsonResponse;
  18. use Pimcore\Bundle\CoreBundle\EventListener\Traits\PimcoreContextAwareTrait;
  19. use Pimcore\Http\Request\Resolver\PimcoreContextResolver;
  20. use Pimcore\Model\Element\ValidationException;
  21. use Pimcore\Model\Exception\ConfigWriteException;
  22. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  23. use Symfony\Component\HttpFoundation\Response;
  24. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  25. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  26. use Symfony\Component\HttpKernel\KernelEvents;
  27. /**
  28.  * @internal
  29.  */
  30. class AdminExceptionListener implements EventSubscriberInterface
  31. {
  32.     use PimcoreContextAwareTrait;
  33.     /**
  34.      * {@inheritdoc}
  35.      */
  36.     public static function getSubscribedEvents(): array
  37.     {
  38.         return [
  39.             KernelEvents::EXCEPTION => 'onKernelException',
  40.         ];
  41.     }
  42.     /**
  43.      * @param ExceptionEvent $event
  44.      */
  45.     public function onKernelException(ExceptionEvent $event)
  46.     {
  47.         $request $event->getRequest();
  48.         $ex $event->getThrowable();
  49.         if ($this->matchesPimcoreContext($requestPimcoreContextResolver::CONTEXT_ADMIN)) {
  50.             // only return JSON error for XHR requests
  51.             if (!$request->isXmlHttpRequest()) {
  52.                 return;
  53.             }
  54.             list($code$headers$message) = $this->getResponseData($ex);
  55.             $data = [
  56.                 'success' => false,
  57.             ];
  58.             if (!\Pimcore::inDebugMode()) {
  59.                 // DBAL exceptions do include SQL statements, we don't want to expose them
  60.                 if ($ex instanceof DBALException) {
  61.                     $message 'Database error, see logs for details';
  62.                 }
  63.             }
  64.             if (\Pimcore::inDebugMode()) {
  65.                 $data['trace'] = $ex->getTrace();
  66.                 $data['traceString'] = 'in ' $ex->getFile() . ':' $ex->getLine() . "\n" $ex->getTraceAsString();
  67.             }
  68.             if ($ex instanceof ValidationException) {
  69.                 $data['type'] = 'ValidationException';
  70.                 $code 422;
  71.                 $this->recursiveAddValidationExceptionSubItems($ex->getSubItems(), $message$data['traceString']);
  72.             }
  73.             if ($ex instanceof ConfigWriteException) {
  74.                 $data['type'] = 'ConfigWriteException';
  75.                 $code 422;
  76.             }
  77.             $data['message'] = $message;
  78.             $response = new JsonResponse($data$code$headers);
  79.             $event->setResponse($response);
  80.         }
  81.     }
  82.     private function getResponseData(\Throwable $exint $defaultStatusCode 500): array
  83.     {
  84.         $code $defaultStatusCode;
  85.         $headers = [];
  86.         $message $ex->getMessage();
  87.         if ($ex instanceof HttpExceptionInterface) {
  88.             if (empty($message)) {
  89.                 $message Response::$statusTexts[$ex->getStatusCode()];
  90.             }
  91.             $code $ex->getStatusCode();
  92.             $headers $ex->getHeaders();
  93.         }
  94.         return [$code$headers$message];
  95.     }
  96.     /**
  97.      * @param \Exception[] $items
  98.      * @param string $message
  99.      * @param string $detailedInfo
  100.      */
  101.     protected function recursiveAddValidationExceptionSubItems($items, &$message, &$detailedInfo)
  102.     {
  103.         if (!$items) {
  104.             return;
  105.         }
  106.         foreach ($items as $e) {
  107.             if ($e->getMessage()) {
  108.                 $message .= '<b>' $e->getMessage() . '</b>';
  109.                 if ($e instanceof ValidationException) {
  110.                     $this->addContext($e$message);
  111.                 }
  112.                 $message .= '<br>';
  113.                 $detailedInfo .= '<br><b>Message:</b><br>';
  114.                 $detailedInfo .= $e->getMessage() . '<br>';
  115.                 $inner $this->getInnerStack($e);
  116.                 $detailedInfo .= '<br><b>Trace:</b> ' $inner->getTraceAsString() . '<br>';
  117.             }
  118.             if ($e instanceof ValidationException) {
  119.                 $this->recursiveAddValidationExceptionSubItems($e->getSubItems(), $message$detailedInfo);
  120.             }
  121.         }
  122.     }
  123.     /**
  124.      * @param ValidationException $e
  125.      * @param string $message
  126.      */
  127.     protected function addContext(ValidationException $e, &$message)
  128.     {
  129.         $contextStack $e->getContextStack();
  130.         if ($contextStack) {
  131.             $message $message ' (' implode(','$contextStack) . ')';
  132.         }
  133.     }
  134.     /**
  135.      * @param \Throwable $e
  136.      *
  137.      * @return \Throwable
  138.      */
  139.     protected function getInnerStack(\Throwable $e)
  140.     {
  141.         while ($e->getPrevious()) {
  142.             $e $e->getPrevious();
  143.         }
  144.         return $e;
  145.     }
  146. }