src/App/Api/EventListener/ApiExceptionListener.php line 55

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Api\EventListener;
  4. use App\Api\DTO\Http\Response\ApiError;
  5. use App\Api\DTO\Http\Response\ApiProblem;
  6. use App\Api\Enum\ApiErrorCode;
  7. use App\Api\Enum\ApiProblemType;
  8. use App\Api\Enum\RouteData;
  9. use App\Api\Exception\ApiProblemExceptionInterface;
  10. use App\Api\Exception\ConstraintViolationListException;
  11. use App\Api\Exception\WrongRequestArgumentException;
  12. use App\Api\Service\LoggerService;
  13. use Psr\Log\LoggerAwareTrait;
  14. use Psr\Log\NullLogger;
  15. use Symfony\Component\HttpFoundation\JsonResponse;
  16. use Symfony\Component\HttpFoundation\Request;
  17. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  18. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  19. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  20. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  21. use Symfony\Component\Serializer\SerializerInterface;
  22. class ApiExceptionListener
  23. {
  24.     use LoggerAwareTrait;
  25.     /**
  26.      * @var SerializerInterface
  27.      */
  28.     private $serializer;
  29.     /**
  30.      * @var bool
  31.      */
  32.     private $formatHandledException;
  33.     /**
  34.      * @var LoggerService
  35.      */
  36.     private $loggerService;
  37.     public function __construct(
  38.         SerializerInterface $serializer,
  39.         LoggerService $loggerService,
  40.         bool $formatHandledException false
  41.     ) {
  42.         $this->serializer $serializer;
  43.         $this->formatHandledException $formatHandledException;
  44.         $this->logger = new NullLogger();
  45.         $this->loggerService $loggerService;
  46.     }
  47.     public function onKernelException(ExceptionEvent $event): void
  48.     {
  49.         if (!str_contains($event->getRequest()->getPathInfo(),'/api')) {
  50.             return;
  51.         }
  52.         $e $event->getThrowable();
  53.         if ($e instanceof ConstraintViolationListException) {
  54.             $apiProblem $e->getConstraintViolationList();
  55.         } elseif ($e instanceof ApiProblemExceptionInterface) {
  56.             $apiProblem $e->getApiProblem();
  57.         } else {
  58.             if ($e instanceof WrongRequestArgumentException) {
  59.                 $title $e->getMessage();
  60.                 $apiError = new ApiError(ApiErrorCode::BAD_REQUEST_DATA$title$e->getProperty());
  61.             } elseif ($e instanceof HttpExceptionInterface) {
  62.                 $title $e->getMessage();
  63.                 $apiError = new ApiError(ApiErrorCode::BAD_REQUEST_DATA$title);
  64.             } elseif ($e instanceof AccessDeniedException) {
  65.                 $e = new AccessDeniedHttpException();
  66.                 $title 'Access Denied';
  67.                 $apiError = new ApiError(ApiErrorCode::FORBIDDEN$title);
  68.             } else {
  69.                 $title 'Internal error';
  70.                 $apiError = new ApiError(ApiErrorCode::INTERNAL_ERROR$title);
  71.             }
  72.             $apiProblem = new ApiProblem(ApiProblemType::COMMON$title);
  73.             $apiProblem->addError($apiError);
  74.         }
  75.         $isHandledException $e instanceof HttpExceptionInterface;
  76.         if ($isHandledException) {
  77.             $statusCode $e->getStatusCode();
  78.             $headers $e->getHeaders();
  79.         } else {
  80.             $statusCode 500;
  81.             $headers = [];
  82.         }
  83.         $this->resolveLogger($event->getRequest());
  84.         if (!$isHandledException) {
  85.             $this->logger->error('Not handled exception', ['exception' => $e]);
  86.             if ($this->formatHandledException) {
  87.                 throw $e;
  88.             }
  89.         } else {
  90.             $this->logger->info('Handled exception', ['exception' => $e]);
  91.         }
  92.         $data $this->serializer->serialize($apiProblem'json');
  93.         $response = new JsonResponse($data$statusCode$headerstrue);
  94.         $response->headers->set('Content-Type''application/problem+json');
  95.         $event->setResponse($response);
  96.     }
  97.     private function resolveLogger(Request $request): void
  98.     {
  99.         if (in_array($request->get('_route'), RouteData::$routeListForLogging)) {
  100.             $this->loggerService->log($request);
  101.         }
  102.     }
  103. }