Symfony Исключение подписчика не сработало - PullRequest
0 голосов
/ 05 августа 2020

Мне нужно отформатировать сообщения об ошибках и вывести их в формате JSON.

У меня есть следующий подписчик на события:


namespace App\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;

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

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

И следующая конфигурация в ./config/services.yaml

services:
    _defaults:
        autowire: true
        autoconfigure: true

    App\EventSubscriber\ExceptionSubscriber:
        tags:
            - {name: kernel.event_subscriber, event: kernel.exception}

Этот подписчик событий работает, когда, например, контроллер выдает ошибку.

Но если у меня есть другая ошибка, например, неправильная инъекция DI

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

, то вывод все еще в формате Html и как Symfony страница ошибки.

Как сделать так, чтобы любая ошибка, которую ловит Symfony, преобразовывалась через мой класс в JSON?

Ответы [ 3 ]

0 голосов
/ 06 августа 2020

Вы можете переопределить контроллер ошибок по умолчанию в конфигурации.

Проверьте документацию здесь: https://symfony.com/doc/current/controller/error_pages.html#overriding -the-default-errorcontroller

0 голосов
/ 07 августа 2020

Я обнаружил, что здесь не так.

Проблема в том, что если у вас, например, ошибка конфигурации, ваши события еще не будут подключены.

В моем коде у меня есть это:

// index.php

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

    $errorHandler = Debug::enable();
}

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

Этот Debug::enable() фактически устанавливает обработчик ошибок (без этого при запуске есть только PHP обработчик ошибок по умолчанию).

Я расширил Debug своим собственным классом:


namespace App\Error;

use Symfony\Component\ErrorHandler\BufferingLogger;
use Symfony\Component\ErrorHandler\Debug as SymfonyDebug;
use Symfony\Component\ErrorHandler\ErrorHandler;

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;
    }
}

Теперь все ошибки проходят через мой App\Error\ExceptionHandler, где я могу вывести его как JsonResponse

0 голосов
/ 05 августа 2020

Не уверен, что вы имеете в виду именно это, но убедитесь, что вы правильно задали ответ:


    public function onKernelException(ExceptionEvent $event): void
    {
        $exception = $event->getThrowable();

        $response = new JsonResponse(
            ['error'],
            Response::HTTP_INTERNAL_SERVER_ERROR,
            [
                'Content-Type' => 'application/vnd.api+json',
            ]
        );

        $event->setResponse($response);
    }
...