2

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!

user1257255
  • 1,161
  • 8
  • 26
  • 55
  • Reading the [documentation](https://symfony.com/doc/current/service_container/service_decoration.html) it seems like it's enough to provide a class for the alias. Maybe remove all other things, like arguments and tags, and leave only the class? – Michał Tomczuk Apr 10 '19 at 15:48
  • In my previous comment I meant the alias of `twig.exception_listener`. Try providing only the `class` parameter to it. – Michał Tomczuk Apr 10 '19 at 21:53
  • @MichałTomczuk Thanks for suggestion. I changed part of `twig.exception_listener` to only contain class instead of all other things, but the error is remaining same as I pasted it above (fatal error, `$controller` argument has no type-hint). – user1257255 Apr 11 '19 at 05:58
  • @user1257255 Did you solve this issue somehow? – Nick Synev Feb 04 '21 at 13:00

0 Answers0