2014年5月8日木曜日

Symfony2のTwigExtentionをからContainerやEntityManagerを呼び出す

Symfony2は重厚で大規模開発には非常に優秀だと思います。
そんなSymfony2ですがちょっと手の込んだ事を調べると日本語情報が少ない印象です。
英語の公式ドキュメントとstackoverflow.comを行ったり来たりした結果をメモとして残しておきます。

やりたいこと


  1. Symfony2でTwigExtentionを作る
  2. 作ったTwigExtentionのgetGlobals()からDBの呼び出しやサービスの呼び出しをする
  3. base.html.twigの変数にDBから取り出した値を使う。

この2.をするのに情報がなかったです。
1.については公式ドキュメントがありますのでそちらを参考にしてください。

カスタムTwig拡張の書き方


さて本題ですがTwigExtentionをサービスコンテナに登録しましょう。
その際に

# src/Acme/DemoBundle/Resources/config/services.yml
services:
    acme.twig.acme_extension:
        class: Acme\DemoBundle\Twig\AcmeExtension
        tags:
            - { name: twig.extension }

    arguments:
            em: "@doctrine.orm.entity_manager"
            container: "@service_container"

とargumentsとしてEntityManagerとContainerを渡します。
次にTwigExtentionクラスのコンストラクタに
public function __construct($em, $container)
    {
        $this->em = $em;
        $this->container = $container;
    }
と記載します。
あとはControllerと同様に各メソッドからDoctrine2のmodelを呼び出すだけです。
実際にbase.html.twigの初期値にDBから取り出したデータを使いたいときはgetGlobals()をオーバーライドします。
public function getGlobals()
    {

        $var = $this->container
                ->get('my_domain.hoge_repository')
                ->getHoge();
        return [
            'hoge' => $hoge,
            'fuga' => 'fuga',
        ];
    }
と言った感じです。
base.html.twigの拡張すればかなりDRYにすることが出来るます。
ただしTwigExtentionでDBを呼び出すと毎回呼ばれます。
ですので出来るだけ回数を減らす必要があると思います。

Symfony2シリーズ続くかわかりませんが現場からは以上です。