Skip to content
Advertisement

Symfony Exception Subscriber not triggered

I need to format error messages and output it in JSON format.

I have the following event subscriber:

namespace AppEventSubscriber;

use SymfonyComponentEventDispatcherEventSubscriberInterface;
use SymfonyComponentHttpKernelEventExceptionEvent;
use SymfonyComponentHttpKernelKernelEvents;

final class ExceptionSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [KernelEvents::EXCEPTION => 'onKernelException'];
    }

    public function onKernelException(ExceptionEvent $event) {/*..*/}
}

And following configuration in ./config/services.yaml

services:
    _defaults:
        autowire: true
        autoconfigure: true

    AppEventSubscriberExceptionSubscriber:
        tags:
            - {name: kernel.event_subscriber, event: kernel.exception}

This event subscriber is working when e.g. controller throws error.

But if I have some other error e.g. wrong DI injection

class FooBar {
    public __constructor(NonExistingService $service) {/*..*/}
}

then output is still in Html format and as Symfony error page.


How to make that any error that Symfony catches is converted via my class to JSON?

Advertisement

Answer

I have found what’s wrong here.

Problem is that if you have e.g. configuration error, your events will be not yet hooked up.

In my code I have this:

// index.php

if ($_SERVER['APP_DEBUG']) {
    umask(0000);

    $errorHandler = Debug::enable();
}

$kernel = new Kernel();
/* .. */

This Debug::enable() actually sets error handler (without that there is only PHP default error handler at start).

I have extended Debug with my own class:

namespace AppError;

use SymfonyComponentErrorHandlerBufferingLogger;
use SymfonyComponentErrorHandlerDebug as SymfonyDebug;
use SymfonyComponentErrorHandlerErrorHandler;

class Debug extends SymfonyDebug
{
    public static function enable(): ErrorHandler
    {
        if ($_SERVER['APP_DEBUG']) {
            umask(0000);

            $errorHandler = parent::enable();
        }

        return self::setDefaultErrorHandler($errorHandler ?? null);
    }

    private static function setDefaultErrorHandler(?ErrorHandler $errorHandler): ErrorHandler
    {
        $errorHandler ??= ErrorHandler::register(new ErrorHandler(new BufferingLogger(), true));

        $errorHandler->setExceptionHandler([ExceptionHandler::class, 'renderException']);

        return $errorHandler;
    }
}


Now all errors goes through my AppErrorExceptionHandler where I can output it as JsonResponse

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement