src/EventSubscriber/ExceptionSubscriber.php line 42

Open in your IDE?
  1. <?php
  2. namespace App\EventSubscriber;
  3. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  4. use Symfony\Component\HttpFoundation\JsonResponse;
  5. use Symfony\Component\HttpFoundation\Response;
  6. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  7. use Symfony\Component\HttpKernel\KernelEvents;
  8. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  9. use Psr\Log\LoggerInterface// Para loguear las excepciones
  10. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface// Para acceder a parámetros como kernel.environment
  11. class ExceptionSubscriber implements EventSubscriberInterface
  12. {
  13.     private LoggerInterface $logger;
  14.     private string $environment;
  15.     // Inyecta el logger y el entorno del kernel
  16.     public function __construct(LoggerInterface $loggerParameterBagInterface $params)
  17.     {
  18.         $this->logger $logger;
  19.         $this->environment $params->get('kernel.environment');
  20.     }
  21.     /**
  22.      * Define a qué eventos se suscribe este listener.
  23.      */
  24.     public static function getSubscribedEvents(): array
  25.     {
  26.         // Se suscribe al evento KernelEvents::EXCEPTION
  27.         // La prioridad de -128 asegura que se ejecute después de la mayoría de los otros listeners
  28.         // incluyendo los del componente de seguridad, lo que es útil para errores de autenticación.
  29.         return [
  30.             KernelEvents::EXCEPTION => ['onKernelException', -128],
  31.         ];
  32.     }
  33.     /**
  34.      * Maneja el evento de excepción.
  35.      */
  36.     public function onKernelException(ExceptionEvent $event): void
  37.     {
  38.         $exception $event->getThrowable(); // Obtiene la excepción lanzada
  39.         $request $event->getRequest();     // Obtiene la petición actual
  40.         // Verifica si la petición es una API (por la ruta o el encabezado Accept)
  41.         // Por ejemplo, si la URL comienza con '/api'
  42.         $isApiRequest str_starts_with($request->getPathInfo(), '/api');
  43.         // O si el cliente solicita explícitamente una respuesta JSON
  44.         $acceptsJson str_contains($request->headers->get('Accept'''), 'application/json');
  45.         if ($isApiRequest || $acceptsJson) {
  46.             // Determina el código de estado HTTP adecuado
  47.             // Si la excepción es una HttpException (ej. NotFoundHttpException, UnauthorizedHttpException),
  48.             // usa su código de estado. De lo contrario, usa 500 (Internal Server Error).
  49.             $statusCode $exception instanceof HttpExceptionInterface
  50.                 $exception->getStatusCode()
  51.                 : Response::HTTP_INTERNAL_SERVER_ERROR;
  52.             // Define el mensaje de error
  53.             // En desarrollo (dev), incluye el mensaje de la excepción para depuración.
  54.             // En producción (prod), usa un mensaje genérico por seguridad.
  55.             //$message = 'Ha ocurrido un error inesperado.';
  56.             //if ($this->environment === 'dev') {
  57.             //    $message = $exception->getMessage();
  58.             //}
  59.             $message $exception->getMessage();
  60.             // Opcional: Registra la excepción completa para depuración en los logs del servidor
  61.             $this->logger->error(
  62.                 'API Exception caught: {message}',
  63.                 ['message' => $exception->getMessage(), 'exception' => $exception]
  64.             );
  65.             // Crea la respuesta JSON
  66.             $response = new JsonResponse([
  67.                 'status' => 'error',
  68.                 'message' => $message,
  69.                 // Incluye la traza de pila completa solo en desarrollo
  70.                 'trace' => $this->environment === 'dev' $exception->getTraceAsString() : null,
  71.                 // Puedes añadir otros campos como un código de error interno, etc.
  72.             ], $statusCode);
  73.             // Establece la respuesta generada como la respuesta del evento
  74.             $event->setResponse($response);
  75.             // Si deseas detener la propagación de otros listeners de eventos para esta excepción:
  76.             // $event->stopPropagation();
  77.         }
  78.     }
  79. }