I am working on an Symfony + FOSRestBundle based REST API. I have implemented (extended) custom HttpException class which is being used in case of validation errors. Along the error message I always pass an array with detailed data about validation problems which is generated by validator class. That is basically the reason why I extended base HttpException. My idea is to show array of errors from exception to the end user of API, but with the core functionality of Symfony I always get "400 Bad request" error in JSON format (no possibility to show another key/value pair along status code and message). I started looking how could I overcome this problem and tried various principles (normalizers, listeners, ...) which I found after searching the web, but none of those really solved the problem of showing the array of errors along code and message.
I'm using Twig for generating responses (I love detailed HTML errors in dev mode, so there's no way for me to replace it with something else). I checked how HTTP kernel processes the request when an exception is thrown and found out that everything goes via exception listener to the exception controller. I created custom exception controller and tried to get the array of errors from the exception. However, the real exception is wrapped into FlattenException
which discards that array. The main problem here is actually FlattenException
object, because I can't get the data from it about the errors (I know why flatten exception is used there, but in my case is not really useful since I have the real array, not some active object instead of it).
I would like to somehow replace FlattenException
with my custom class - I want extend it just to have another property for array of messages that would be preserved until exception controller's showAction and rendering of view template. Then I would change static create
function with additional logic for handling cases when my custom type of exceptions is being wrapped. I'm not sure if that's even possible without changing the core code of Symfony and if possible I'd like to stay away from any hacks.
Another thing about which I was thinking is to extend/replace ExceptionListener
. There I would just change existing logic to replace FlattenException
with MyCustomFlattenException
which would then get passed to my ExceptionController
via showAction
method. I already tried that and overrode both twig.exception_listener
and http_exception_listener
services (separately - once the first and in the other case the second; I did that in services.yaml
), but didn't have much luck with it.
For the twig.exception_listener
this is what is in my service ...
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
... and I always get the this error:
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
While for http_exception_listener
this is what's in my service ...
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
... and there is no any error, but still the core ExceptionListener
is called instead of the one I specified in services.
This is the ApiExceptionListener
class where I have some breakpoints in my IDE to check if it was really called:
<?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);
}
}
I would really appreciate any help or idea to get in the right direction of solution for this problem. Thank you!