Symfony 4: Получение дополнительных данных об исключениях в шаблоне - PullRequest
0 голосов
/ 10 апреля 2019

Я работаю над REST API на основе Symfony + FOSRestBundle. Я реализовал (расширен) пользовательский класс HttpException, который используется в случае ошибок проверки. Вдоль сообщения об ошибке я всегда передаю массив с подробными данными о проблемах валидации, который генерируется классом валидатора. Это в основном причина, почему я расширил базу HttpException. Моя идея состоит в том, чтобы показать массив ошибок от исключения до конечного пользователя API, но с основной функциональностью Symfony я всегда получаю ошибку «400 Bad request» в формате JSON (нет возможности показать другую пару ключ / значение вдоль кода состояния и сообщение). Я начал искать способы преодоления этой проблемы и попробовал различные принципы (нормализаторы, слушатели, ...), которые я нашел после поиска в Интернете, но ни один из них не решил проблему отображения массива ошибок в коде и сообщении.

Я использую Twig для генерации ответов (мне нравятся подробные ошибки HTML в режиме разработки, поэтому я не могу заменить его чем-то другим). Я проверил, как ядро ​​HTTP обрабатывает запрос при возникновении исключения, и обнаружил, что все проходит через прослушиватель исключений в контроллер исключений. Я создал собственный контроллер исключений и попытался получить массив ошибок из исключения. Однако настоящее исключение заключено в FlattenException, который отбрасывает этот массив. Основная проблема здесь на самом деле FlattenException объект, потому что я не могу получить от него данные об ошибках (я знаю, почему здесь используется исключение flatten, но в моем случае это не очень полезно, так как у меня есть настоящий массив, а не какой-то активный объект вместо него).

Я бы хотел как-то заменить FlattenException на мой собственный класс - я хочу расширить его, просто добавив другое свойство для массива сообщений, которое будет сохраняться до showAction контроллера исключений и рендеринга шаблона представления. Затем я бы изменил статическую функцию create с дополнительной логикой для обработки случаев, когда мой пользовательский тип исключений упакован. Я не уверен, возможно ли это даже без изменения основного кода Symfony, и если возможно, я бы хотел избежать любых взломов.

Еще одна вещь, о которой я думал, - это расширить / заменить ExceptionListener. Там я просто изменил бы существующую логику, чтобы заменить FlattenException на MyCustomFlattenException, которая затем была бы передана моему ExceptionController с помощью showAction метода. Я уже пробовал это и переопределил службы twig.exception_listener и http_exception_listener (по отдельности - один раз первый, а во втором - второй; я сделал это в services.yaml), но мне не повезло.

Для twig.exception_listener это то, что у меня на службе ...

twig.exception_listener:
  class: App\EventListener\ApiExceptionListener
  arguments:
    $controller: "%twig.exception_listener.controller%"
    $logger: "logger"
  tags:
    - name: kernel.event_subscriber
    - name: monolog.logger
      channel: request

... и я всегда получаю эту ошибку:

Fatal error: Uncaught Symfony\Component\DependencyInjection\Exception\RuntimeException: Cannot autowire service "App\EventListener\ApiExceptionListener": argument "$controller" of method "Symfony\Component\HttpKernel\EventListener\ExceptionListener::__construct()" has no type-hint, you should configure its value explicitly. in /project/vendor/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php on line 54

В то время как для http_exception_listener это то, что у меня на службе ...

http_exception_listener:
  class: App\EventListener\ApiExceptionListener
  arguments:
    [
      null,
      null,
      "%kernel.debug%",
      "%kernel.charset%",
      "%debug.file_link_format%",
    ]
  tags:
    - name: kernel.event_listener
      event: kernel.exception
      method: onKernelException
      priority: -1024
    - name: kernel.reset
      method: reset

... и ошибки нет, но все равно вызывается ядро ​​ExceptionListener вместо того, которое я указал в службах.

Это класс ApiExceptionListener, в котором у меня есть несколько точек останова в моей IDE, чтобы проверить, действительно ли он вызывался:

<?php

namespace App\EventListener;

use Symfony\Component\HttpKernel\EventListener\ExceptionListener;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;

class ApiExceptionListener extends ExceptionListener
{
    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        $test = 'ok';
    }

    protected function duplicateRequest(\Exception $exception, Request $request)
    {
        parent::duplicateRequest($exception, $request);
    }
}

Я был бы очень признателен за любую помощь или идею, чтобы найти правильное решение этой проблемы. Спасибо!

...