SymfonyのTwig内で正規表現を使ったパターンマッチングからの置換をしたい場面に遭遇した。
しかし、いくら調べてもSymfony標準のフィルターには私が望むものはありませんでしたが、カスタムフィルターや関数を作成する方法があるようなのでメモしておきます。
PHPのpreg_replace()で置換したい!
最終的にやりたいことは、Twig内でHTMLのimgタグからalt属性の文字だけを抜き出して、imgタグと置き換えること。
これだけだと需要がないように思うが、フィルター自体はPHPの[preg_replace()]関数と同様の動きをするので使い回しが可能です。
Twig側では以下のように置換できるようにします。
1 |
{{ data.content|preg_replace('/<img(.*?)alt="(.*?)"(.*?)>/si', "$2")|striptags }} |
[data.content]はHTMLコンテンツ、[preg_replace()]フィルターでPHP同様の正規表現を使ったパターンマッチングを行い、Symfonyの標準フィルター[striptags]でHTMLタグを削除するといった感じです。
Twigの拡張
それでは参考サイトを基に、Twigを拡張していきましょう。
今回は、カスタムフィルターと関数のみとします。
フィルターに関しては上記で説明しましたが、関数に関しては、独自CSRFトークンを生成する関数を作ります。
こちらも需要がないでしょうが、サービスコンテナの渡し方についてもメモしておきたかったので。
今回は触れませんが、グローバル変数もここで設定できるようです。
ブラウザの翻訳機能を使えば英語の本家ドキュメントの方がより詳しいです。
独自フィルターと独自関数を追加
例としてバンドル名はAppBundleとします。
AppBundle直下にTwigフォルダを作成して、その下に[AppExtension.php](ファイル名は任意)ファイルを作成します。
symfony/src/AppBundle/Twig/AppExtension.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
<?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の配列の中にカンマ区切りで追加します。
1 2 3 |
return [ new Twig_SimpleFilter('[Twig内のフィルター名]', [$this, '[同クラス内で実行する関数]')), ]; |
つまり、Twig側でTwig_SimpleFilter()
の第1引数を書くと、第2引数で指定した関数が実行されるという仕組みです。
サービスの登録
しかし、これだけでは使えません。
作った拡張機能を利用できるように設定ファイルで設定する必要があります。
YAMLに追加する
Symfonyの設定は最終的にはconfig.ymlに集約されるので、[app/Resourcesconfig]フォルダ以下の.ymlファイルならどこに書いても良いのですが、せっかくサービスと名の付くservices.ymlがあるので、これに書きたいと思います。
symfony/app/Resources/config/services.yml
1 2 3 4 5 6 7 |
services: app.twig_extension: class: AppBundleTwigAppExtension arguments: ["@service_container"] public: false tags: - { name: twig.extension } |
ここでは、前述の通りサービスコンテナの使い方もメモしておきたいので、
1 |
arguments: ["@service_container"] |
がキーになります。
こうすることで初めてAppExtension.phpのコンストラクタでContainerが使えるようになります。以上です。
コメント