Search code examples
phpsymfonysymfony-2.8event-dispatching

Symfony EventDispatcher Service Tags Not Inside Symfony App


Using Symfony 2.8 Event Dispatcher and Container components not inside a Symfony App

From my bootstrap/kernel file:

$this->container = new ContainerBuilder(new ParameterBag());
$this->getContainer()->addCompilerPass(new RegisterListenersPass());
$this->getContainer()->register('event_dispatcher', EventDispatcher::class);
$this->loadServiceConfig(); // See below for reference

/** @var EventDispatcher $ed */
$ed = $this->getContainer()->get('event_dispatcher');
// The next line works
$ed->addSubscriber(new SampleSubscriber());

...

private function loadServiceConfig()
{
    $loader = new YamlFileLoader($this->container, new FileLocator(__DIR__);
    $loader->load('config/services.yml');
}

From config/services.yml:

services:
    sample_subscriber:
        class: Sample\Event\SampleSubscriber
        public: true
        tags:
            - { name: kernel.event_subscriber }

The manual subscription works, but I would expect the event to automatically attach given the tags from the yaml file


Solution

  • I created a standalone repo showing how to set up the container, event dispatcher, and the RegisterListenersPass:

    https://github.com/simshaun/so-45003754

    Symfony 2.8 needs a ContainerAwareEventDispatcher for the RegisterListenersPass to function.

    Here's the meat of the setup/wiring:

    <?php
    
    use Symfony\Component\Config\FileLocator;
    use Symfony\Component\DependencyInjection\ContainerBuilder;
    use Symfony\Component\DependencyInjection\Definition;
    use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
    use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
    use Symfony\Component\DependencyInjection\Reference;
    use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
    use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
    use Symfony\Component\EventDispatcher\EventDispatcherInterface;
    
    require __DIR__.'/vendor/autoload.php';
    
    
    class App
    {
        protected $container;
    
        public function __construct()
        {
            $builder = new ContainerBuilder(new ParameterBag());
            $builder->addCompilerPass(new RegisterListenersPass());
    
            $definition = new Definition(ContainerAwareEventDispatcher::class, [new Reference('service_container')]);
            $builder->setDefinition('event_dispatcher', $definition);
    
            $loader = new YamlFileLoader($builder, new FileLocator(__DIR__));
            $loader->load('services.yml');
    
            $builder->compile();
            $this->container = $builder;
        }
    
        public function getEventDispatcher(): EventDispatcherInterface
        {
            return $this->container->get('event_dispatcher');
        }
    }
    
    
    $app = new App();
    $ed = $app->getEventDispatcher();
    $ed->dispatch('my.event');