Symfony2のTwigを拡張!カスタムフィルターや関数を追加する方法


symfony-twig-extension

SymfonyTwig内で正規表現を使ったパターンマッチングからの置換をしたい場面に遭遇した。
しかし、いくら調べてもSymfony標準のフィルターには私が望むものはありませんでしたが、独自フィルターを作成する方法があるようなのでメモしておきます。

PHPのpreg_replace()で置換したい!

最終的にやりたいことは、Twig内でHTMLimgタグからalt属性の文字だけを抜き出して、imgタグと置き換えること。
これだけだと需要がないように思うが、フィルター自体はPHPpreg_replace()関数と同様の動きをするので使い回しが可能です。
Twig側では以下のように置換できるようにします。

data.contentはHTMLコンテンツ、preg_replace()フィルターPHP同様の正規表現を使ったパターンマッチングを行い、Symfonyの標準フィルターstriptagsHTMLタグを削除するといった感じです。


Twigの拡張

それでは参考サイトを基に、Twig拡張していきましょう。
今回は、独自フィルター独自関数のみとします。
フィルターに関しては上記で説明しましたが、関数に関しては、独自CSRFトークンを生成する関数を作ります。
こちらも需要がないでしょうが、サービスコンテナの渡し方についてもメモしておきたかったので。

symfony公式にはfilterしか書いてないのでよく使いそうなfunction,filter,globalのtwig拡張のメモ。###クラス例```namespace CommonBundle\Twig\Extensi...
symfony twig拡張メモ - Qiita - Qiita
今回は触れませんが、グローバル変数もここで設定できるようです。
ブラウザの翻訳機能を使えば英語の本家ドキュメントの方がより詳しいです。
How to Write a custom Twig Extension: The main motivation for writing an extension is to move often used code into a reusable class like adding support for internationalization. An extension can defin...
How to Write a custom Twig Extension (Symfony 2.8 Docs) - symfony.com
Twig - The flexible, fast, and secure template engine for PHP
Extending Twig - Documentation - Twig - The flexible, fast, and secure PHP te... - twig.symfony.com

独自フィルターと独自関数を追加

例としてバンドル名はAppBundleとします。
AppBundle直下にTwigフォルダを作成して、その下にAppExtension.php(ファイル名は任意)ファイルを作成します。

symfony\src\AppBundle\Twig\AppExtension.php

<?php
namespace AppBundle\Twig;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;

class AppExtension extends \Twig_Extension
{
    public function __construct(Container $container)
    {
        $this->container = $container;
        $this->request = $container->get('request');
        $this->session = $container->get('session');
    }
    
    public function getFilters()
    {
        return [
            new \Twig_SimpleFilter('preg_replace', [$this, 'pregReplaceFilter']),
        ];
    }

    public function getFunctions()
    {
        return [
            new \Twig_SimpleFunction('_token', [$this, 'csrfToken']),
        ];
    }
    
    public function pregReplaceFilter($subject, $pattern = '', $replacement = '')
    {
        return preg_replace($pattern, $replacement, $subject);
    }
    
    public function csrfToken()
    {
        $did = $this->request->get('id');
        $token = '';
        if ($did) {
            $token = md5($this->container->getParameter('secret') . $id . date('YmdHis'));
            $this->session->set($id . '_token', $token);
        }
        return $token;
    }
}

解説

getFilters()フィルターを、getFunctions()関数を追加できます。
使いの仕方はどちらも同じで、returnの配列の中にカンマ区切りで追加します。

return [
    new \Twig_SimpleFilter('[Twig内のフィルター名]', [$this, '[同クラス内で実行する関数]')),
];

つまり、Twig側でTwig_SimpleFilter()第1引数を書くと、第2引数で指定した関数が実行されるという仕組みです。

サービスの登録

しかし、これだけでは使えません。
作った拡張機能を利用できるように設定ファイルで設定する必要があります。

YAMLに追加する

Symfonyの設定は最終的にはconfig.ymlに集約されるので、app\Resources\config\フォルダ以下の.ymlファイルならどこに書いても良いのですが、せっかくサービスと名の付くservices.ymlがあるので、これに書きたいと思います。

symfony\app\Resources\config\services.yml

services:
    app.twig_extension:
        class: AppBundle\Twig\AppExtension
        arguments: ["@service_container"]
        public: false
        tags:
            - { name: twig.extension }

ここでは、前述の通りサービスコンテナの使い方もメモしておきたいので、

arguments: ["@service_container"]

がキーになります。
こうすることで初めてAppExtension.phpコンストラクタContainerが使えるようになります。

以上です。


コメント

このブログの人気の投稿

Linuxでファイルの改行コードLF⇔CRLFを変換する方法

RHEL 7でスタティック(静的)ルートを追加する4つの方法

SQLPlusでのOracleリモート接続とSQLファイルを実行する方法