src/FMT/Application/Listener/ExceptionListener.php line 61

Open in your IDE?
  1. <?php
  2. /**
  3.  * Author: Anton Orlov
  4.  * Date: 20.03.2018
  5.  * Time: 19:10
  6.  */
  7. namespace FMT\Application\Listener;
  8. use FMT\Data\Entity\User;
  9. use FMT\Infrastructure\Helper\LogHelper;
  10. use FMT\Application\Controller\Common\NotFoundController;
  11. use Stripe\Exception\ApiErrorException;
  12. use Symfony\Component\HttpFoundation\JsonResponse;
  13. use Symfony\Component\HttpFoundation\RedirectResponse;
  14. use Symfony\Component\HttpFoundation\Request;
  15. use Symfony\Component\HttpFoundation\Response;
  16. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  17. use Symfony\Component\HttpKernel\Exception\HttpException;
  18. use Symfony\Component\Routing\RouterInterface;
  19. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  20. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  21. use Symfony\Component\Templating\EngineInterface;
  22. use Twig\Environment;
  23. /**
  24.  * Class ExceptionListener
  25.  * @package FMT\Application\Listener
  26.  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  27.  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  28.  */
  29. class ExceptionListener
  30. {
  31.     /** @var Environment */
  32.     private $engine;
  33.     /** @var bool */
  34.     private $debug;
  35.     /** @var RouterInterface */
  36.     private $router;
  37.     /** @var TokenStorageInterface */
  38.     private $tokenStorage;
  39.     public function __construct(
  40.         Environment $engine,
  41.         $debug,
  42.         RouterInterface $router,
  43.         TokenStorageInterface $tokenStorage
  44.     ) {
  45.         $this->engine $engine;
  46.         $this->debug = (bool) $debug;
  47.         $this->router $router;
  48.         $this->tokenStorage $tokenStorage;
  49.     }
  50.     /**
  51.      * @param ExceptionEvent $event
  52.      */
  53.     public function onResponseFormatException(ExceptionEvent $event)
  54.     {
  55.         $request $event->getRequest();
  56.         $exception $event->getThrowable();
  57.         $details = [
  58.             "success" => false,
  59.             "code" => 500,
  60.             "host" => $request->getHost(),
  61.             "message" => $exception->getMessage()
  62.         ];
  63.         if ($this->debug) {
  64.             $details["exception"] = get_class($exception);
  65.             $details["backtrace"] = $exception->getTraceAsString();
  66.         }
  67.         if ($exception instanceof HttpException) {
  68.             $details["code"] = $exception->getStatusCode();
  69.         } elseif ($exception instanceof AccessDeniedException) {
  70.             $details["code"] = $this->tokenStorage->getToken()->getUser() instanceof User ?
  71.                 Response::HTTP_FORBIDDEN :
  72.                 Response::HTTP_UNAUTHORIZED;
  73.         } elseif ($exception instanceof ApiErrorException) {
  74.             $details["code"] = $exception->getHttpStatus();
  75.         }
  76.         LogHelper::error(
  77.             "[%s] %s |\nTrace: %s",
  78.             get_class($exception),
  79.             $exception->getMessage(),
  80.             $exception->getTraceAsString()
  81.         );
  82.         LogHelper::debug($exception->getTraceAsString());
  83.         $event->stopPropagation();
  84.         if ($this->isJsonResponse($request)) {
  85.             $event->setResponse(new JsonResponse($details));
  86.             return;
  87.         }
  88.         switch ($details['code']) {
  89.             case Response::HTTP_NOT_FOUND:
  90.                 $route $this->getRedirectToRoute(NotFoundController::ROUTE_404);
  91.                 $response = new RedirectResponse($route);
  92.                 break;
  93.             case Response::HTTP_UNAUTHORIZED:
  94.                 header("Location: /log-in");
  95.                 exit;
  96.             case Response::HTTP_FORBIDDEN:
  97.             case Response::HTTP_INTERNAL_SERVER_ERROR:
  98.                 $template $this->getTemplate($details);
  99.                 $response = new Response($template);
  100.                 break;
  101.             default:
  102.                 $template $this->engine->render('TwigBundle/views/Exception/error.html.twig'$details);
  103.                 $response = new Response($template);
  104.         }
  105.         $event->setResponse($response);
  106.     }
  107.     /**
  108.      * @param $routeName
  109.      * @return string
  110.      */
  111.     private function getRedirectToRoute($routeName)
  112.     {
  113.         return $this->router->generate($routeName);
  114.     }
  115.     /**
  116.      * @param array $details
  117.      * @return string
  118.      */
  119.     private function getTemplate(array $details)
  120.     {
  121.         return $this->engine->render(
  122.             sprintf('@Public/errors/error%d.html.twig'$details['code']),
  123.             $details
  124.         );
  125.     }
  126.     /**
  127.      * @param Request $request
  128.      * @return bool
  129.      */
  130.     private function isJsonResponse(Request $request)
  131.     {
  132.         $jsonHeades array_filter([
  133.             $request->headers->get("X-Requested-With") === "XMLHttpRequest",
  134.             $request->getRequestFormat() === "json"
  135.         ]);
  136.         return count($jsonHeades) > 1;
  137.     }
  138. }