Symfony2 or 3でイベントリスナーを設定したい時に基本的にservice.ymlで設定するのが一般的だと思います。
まあ僕の場合はJMSDiExtraBundleを愛用しているので、ちょっと違いますが・・・w
自作でBundleとか作っていると、状況によって動的にEventListenerを設定したいなんてケースありますよね。
動的って表現が微妙ですね。
想定としては 「config.ymlでの設定や他のbundleのパラメータ等の設定をみて、EventListenerに登録」 という事になります。
なんというかコンパイルタイムで設定値を見てListener登録するみたいな感じです。
通常のEventListenerの登録
まずは、通常どのようにEventListenerを登録しているのか?
以下のようにservices.ymlにtagを使って登録しているが一般的だと思います。
1
2
3
4
5
6
7
8
|
// 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の部分を削除するだけですが。。
1
2
3
4
5
6
|
// 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したクラスを作成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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を使って登録します。
1
2
3
4
5
6
7
8
9
10
11
|
// 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に登録されるかが決まります。
簡単に設定できるので、ぜひぜひ試してみてください!
参考