1

Lets say I have 3 different bundles.

I am adding to event listeners to each bundle. When there is any exception in Bundle1, then Bundle2 and Bundle3 should not listen it.

I have tested it adding to each bundle eventlistener but when there is any error in Bundle2 then Bundle1 will listen try to handle it as well.

How to handle this situation?

if needed any code then here is my service.yaml in bundle:

kernel.listener.test1bundle.exceptionlistener:
    class: App\test1bundle\EventListener\ExceptionListener
    tags:
        - { name: kernel.event_listener, event: kernel.exception}

and here is my exception listener:

public function onKernelException(GetResponseForExceptionEvent $event)
{
    // You get the exception object from the received event
    $exception = $event->getException();
    $message = [ 
        "errors" => [
            [
                "title" => "Internal error in test1 bundle",
                "detail" => $exception->getMessage()
            ]
        ]
    ];

    $response = new JsonResponse();
    $response->setData($message);

    $response->headers->set('Content-Type', 'application/problem+json');

    $event->setResponse($response);
}

i read that it is possible just listen controller. But in that case will controller listener listen exceptions as well?

yivi
  • 42,438
  • 18
  • 116
  • 138
MRustamzade
  • 1,425
  • 14
  • 27

2 Answers2

4

What you need to do is to create different "families" of exceptions, and each event listener should decide to act or not act on the exception depending on its parentage.

E.g. lets say that on each of your bundles you create an abstract exception:

abstract class BundleOneException extends \Exception {}

(and the same for BundleTwo and BundleThree). Now on each bundle, every exception you throw should be one extended from this one.

Then on each listener you could do:

public function onKernelException(GetResponseForExceptionEvent $event)
{
    $exception = $event->getException();

    if (!$exception instanceof BundleOneException) {
        return;
    }

    // otherwise, do your thing

}

All listener are listening to all exceptions, but they will only act on the appropriate exceptions.

This is the most practical wa to handle the situation. Yes, you'd need each bundle to be consistent in the type of exceptions they throw; but throwing generic exceptions is not great practice (as demonstrated by this kind of situation).

yivi
  • 42,438
  • 18
  • 116
  • 138
  • 1
    thanks for answer, i have used your answer, but changed it little bit. insted of checking for ```!$exception instanceof BundleOneException``` i am checking if ```strpos($exception->getFile(), 'BundleOn')```. so i will know that error was in bundleOne. But your solution works great. :) – MRustamzade Feb 18 '19 at 14:44
1

The event listener bus is shared for all the bundles in your application, since all of those are instantiated for a specific AppKernel. You have several options here:

  1. Have different kernels handle different parts of your application (which means you'd have to route requests to them in your public/index.php front controller), and add separate listeners as services there. This could be quite cumbersome though, since in general you'd have to deal with not just one application, but multiple ones.

  2. If you know which specific exceptions you want to catch in your listeners, you could subclass those in each of your bundles, and only proceed in the ExceptionListeners if the class matches, as @yivi suggested in this answer.

  3. You could also grab the exception stack traces and introspect those using Exception::getTrace and some iterative digging to see if the exception that is caught in your listener was actually thrown in a specific file, perhaps by looking at the file field there.

But all in all, to me needing something like this looks like a problem with the separation of concerns principle in your application code. Looks like you are treating bundles as separate applications, but that's not the way of decomposition that's intended for bundles, as far as I know. Symfony's best practices now suggest having just the AppBundle, but even if you want to add more bundles, still, the reason for doing that is splitting your code by domain, which would automatically lead to having subclassed exceptions in each of the bundles.

kix
  • 3,290
  • 27
  • 39