Symfonyで動的にEventListenerの登録を行う

Symfonyで動的にEventListenerの登録を行う

October 8, 2016
symfony

Symfony2 or 3でイベントリスナーを設定したい時に基本的にservice.ymlで設定するのが一般的だと思います。
まあ僕の場合はJMSDiExtraBundleを愛用しているので、ちょっと違いますが・・・w

自作でBundleとか作っていると、状況によって動的にEventListenerを設定したいなんてケースありますよね。

動的って表現が微妙ですね。

想定としては 「config.ymlでの設定や他のbundleのパラメータ等の設定をみて、EventListenerに登録」 という事になります。
なんというかコンパイルタイムで設定値を見てListener登録するみたいな感じです。

通常のEventListenerの登録

まずは、通常どのようにEventListenerを登録しているのか? 以下のようにservices.ymlにtagを使って登録しているが一般的だと思います。

// src/PdBundle/Resources/config/services.yml

    pd_bundle.event_listener.use_action_listener:
        class: Polidog\PdBundle\EventListener\UseActionListener
        arguments:
            - "%pd_bundle.is_use%"
        tags:
          - { name: "kernel.event_listener", event: kernel.request, method: onKernelRequest }

しかし、これでは動的に変更することが出来ません。

動的にEventListenerに登録する

CompilerPassを利用して解決しました。

  • services.ymlの修正
  • CompilerPassの作成
  • BundleクラスでaddCompilerPassをする

services.ymlの修正

まず、先程のservices.ymlの修正をします。 といってもtagの部分を削除するだけですが。。

// src/PdBundle/Resources/config/services.yml

    pd_bundle.event_listener.use_action_listener:
        class: Polidog\PdBundle\EventListener\UseActionListener
        arguments:
            - "%pd_bundle.is_use%"

CompilerPassの作成

CompilerPassInterfaceをimplementsしたクラスを作成します。

class UseActionPass implements CompilerPassInterface
{

    public function process(ContainerBuilder $container)
    {
        $isUse = $container->getParameter('pd_bundle. is_use');

        if (false === $isUse) {
            return;
        }

        $def = $container->getDefinition('pd_bundle.event_listener.use_action_listener');
        $def->addTag('kernel.event_listener',[
            'event' => KernelEvents::REQUEST,
            'method' => 'onKernelRequest'
        ]);
    }

}

BundleクラスでaddCompilerPassをする

先程作成したUseActionPassをaddCompilerPassを使って登録します。

// src/PdBundle/PdBundle.php

class PdBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        parent::build($container);
        $container->addCompilerPass(new UseActionPass());
    }

}

これで、pd_bundle.is_useパラメータがtrue or falseによってEventListenerに登録されるかが決まります。 簡単に設定できるので、ぜひぜひ試してみてください!

参考

comments powered by Disqus