phpsymfonysymfony6

Symfony get all event listeners in CLI command


Can anyone advise how can I get all events (classes) that have AsEventListener tags in Symfony 6.4?

An example event dispatcher has these tags:

#[AsEventListener(event: 'aa.bb.cc.', method: 'test', priority: 20)]

class test { ... }

How can I use following to get all tagged classes?

  #[TaggedIterator('messenger.message_handler')]
  private readonly iterable $messageHandlers,

I wasnt to make a custom CLI command to list events that based on a specific name.

Thanks!

UPDATE:

Thanks, based on the information I was able to get all event names by the following:

  1. Added to a constructor all event classes (they are automatically tagged with autowiring):

     public function __construct(
     #[TaggedIterator('kernel.event_listener')]
     private readonly iterable $messageHandlers
     ) {};
    
  2. In a class method use following code to get all event attributes and find event names:

             foreach ($this->messageHandlers as $messageHandler) {               
               $refClass = new \ReflectionClass($messageHandler);
               $attributes = $refClass->getAttributes();
               foreach ($attributes as $attribute) {
                 $eventArguments = $attribute->getArguments();                       
                 $output->writeln(json_encode($attribute->getArguments()));
               }
             }
    

Solution

  • You have to tag the classes you want to gather and then direct the DI container to inject all those instances of those classes somewhere.

    See this old-but-relevant blog post.

    Assuming your Test and SomeService are in a directory set for Autoconfiguration (basically, if your code lives in /src and you haven't touched the default Symfony container configuration), you have to do this:

    #[AsEventListener(event: 'aa.bb.cc.', method: 'test', priority: 20)]
    #[AutoconfigureTag('the.tag.you.want')]
    class Test { ... }
    

    Step two: inject a scoped DI container holding all of those tagged classes:

    class SomeService
    {
        public function __construct(
            #[TaggedIterator('the.tag.you.want')] iterable $listeners
        ) {
            private readonly $this->listeners = $listeners;
        }
    }
    

    I recommend you check out docs on how to work with Service Subscribers and Locators and specifically the ServiceSubscriberTrait, which will likely make your life a lot easier.