JMSDiExtraBundleを有効にしたらControllerクラスにDIコンテナがInjectされなくなった

JMSDiExtraBundleを有効にしたらControllerクラスにDIコンテナがInjectされなくなった

September 8, 2017,
tags: php symfony


このエントリーをはてなブックマークに追加

Symfonyでwebアプリケーションを開発するのに必須といっても過言ではないJMSDIExtraBundle。
しかし、JMSDIExraBundleを有効にしてからwebからアクセスすると、コントローラのアクションの中で$this->get("service_name")みたいなコードでエラーになりました。

Symfony2系だと特に問題ないのですが、Symfony3.3でJMSDiExtraBundleを導入したところ、ControllerクラスにDIコンテナがinjectされなくなりました。

何が原因なのか?

JMSDiExtraBundleを有効にするとControllerResolverクラスがJMSDiExtraBundleのものに差し替わります。
https://git.io/v5ruv

JMSDiExtraBundleのControllerResolverクラスでは、DIコンテナにすでに対象のコントローラが登録されていたら、DIコンテナからコントローラを取り出します。
そしてSymfony3.3だとapp/config/services.ymlでControllerクラスがDI登録されているんですよね。デフォルトで・・・

# app/config/services.yml

...
    AppBundle\Controller\:
        resource: '../../src/AppBundle/Controller'
        public: true
        tags: ['controller.service_arguments']

この時app/config/services.ymlでは特にContainerをInjectする設定をしていません。 だからcontainerがないとエラーが発生しているようです。

ということで、services.ymlでコントローラのDI登録をやめれば正常に動くようです。

どこでControllerResolverクラスが差し替わっているのか?

なぜJMSDiExtraBundleをAppKernelに登録するとControllerResolverクラスが差し替わるのか?ちょっと気になったのでついでに調べてみました。
どうやらJMS\DiExtraBundle\DependencyInjection\Compiler\IntegrationPassクラスでJMSDiExtraBundleのControllerResolverに差し替えているようです。
https://git.io/v5rzr

じゃあIntegrationPassはどこでコンテナに登録されるかというとJMS\DiExtraBundle\JMSDiExtraBundleクラスで登録されています。
https://git.io/v5rgO

つまりAppKernelにJMSDiExtraBundleを登録したらControllerResolverが差し替わるということですね。

どう対応するのがベストなのか?

Controllerクラスを継承しない、そしてContainerをControllerから使わないという方法がベストなのかと思います。
Controllerが必要なものはDIでInjectするのがいいかと。

最後に

Symfony3系では、DI登録が柔軟にできるようになりました。(app/config/services.ymlを見ればわかると思います)
JMSDiExtraBundleが本当に必要なのか?導入するメリットは本当にあるのか?
今一度考え直してみるのも良いかもしれません。

comments powered by Disqus