How to register event listeners in Symfony 4?

1.8k Views Asked by At

I'm writing a Symfony application. Means: The application has a structure of a Symfony application and uses Symfony's MVC (symfony/http-kernel, symfony/routing etc.), but it should be as framework-independent as possible. So instead of the framework's DI, I'm using PHP-DI.

Now I've added the symfony/event-dispatcher component and to register a listener for all custom events.

services.yaml

system.event_handler:
    tags:
        - { name: system.event_handler, event: general.user_message_received, method: handle }
        - { name: system.event_handler, event: xxx.foo, method: handle }
        - { name: system.event_handler, event: yyy.foo, method: handle }
        - { name: system.event_handler, event: zzz.foo, method: handle }

The system.event_handler is defined in my PHP-DI dependencies file:

...
EventHandlerInterface::class => DI\factory(function(ContainerInterface $container) {
    return new SystemEventHandler(
        $container->get('process_handler.xxx'),
        $container->get('process_handler.yyy'),
        $container->get('process_handler.zzz')
    );
}),
'system.event_handler' => DI\get(EventHandlerInterface::class),
...

Now I'm getting an error:

RuntimeException

The definition for "system.event_handler" has no class. If you intend to inject this service dynamically at runtime, please mark it as synthetic=true. If this is an abstract definition solely used by child definitions, please add abstract=true, otherwise specify a class to get rid of this error.

Why? Is it wrong to use an alias at this paces?

OK, I've replaced the alias in the services.yaml by the FQCN of my event handler:

App\Process\SystemEventHandler:
    tags:
        - { name: system.event_handler, event: general.user_message_received, method: handle }
        - { name: system.event_handler, event: xxx.foo, method: handle }
        - { name: system.event_handler, event: yyy.foo, method: handle }
        - { name: system.event_handler, event: zzz.foo, method: handle }

No errors anymore. But the event handler is still not get added to the EventDispatcher.

How to register event listeners (defined in the PHP-DI container) in Symfony 4?

1

There are 1 best solutions below

3
On

PHP-DI is called as a fallback of Symfony's container. So when an entry is not defined in Symfony, it is pulled out of PHP-DI. However I've never tried defining an entry in both containers, from my POV (as the maintainer of PHP-DI) this is not supposed to work.

Since you need to use Symfony tags, the simplest solution is to define that specific service entirely in Symfony's config (not PHP-DI).

Another lead could be to try to write a Symfony compiler pass to try and make this work, but I don't know if that is feasible. If you manage to find a good solution please report it in the GitHub repository, we could try to integrate it.