Я работаю над 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);
}
}
Я был бы очень признателен за любую помощь или идею, чтобы найти правильное решение этой проблемы. Спасибо!