Help us understand the problem. What is going on with this article?

Symfony 2.8(lts) と SmartyBundle(~2.0) で Smarty のプリフィルタを利用するサンプル

More than 3 years have passed since last update.

Symfony 2.8 で SmartyBundle を利用している場合の Smarty プリフィルタの実装サンプルです。

ドキュメントを参考にしたところ、思いのほかハマって、結局 SmartyBundle のソースコードを部分的に読む事になってしまったので、メモを残しておきます。

参考: SmartyBundle のドキュメント

6.8. Enabling custom Extensions

プリフィルタを利用するサンプル実装

SmartyBundle でプリフィルタを利用する際は、Extension を用意します。
SmartyBundle の Extension は、ExtensionInterface を実装したクラスで、AbstractExtension は ExtensionInterface のデフォルト実装を用意してくれているので、AbstractExtension を継承すれば必要なメソッド(今回は getFilters )のみオーバーライドすればOKです。

サンプル実装は SSI のタグを include タグに置換するプリフィルタを登録するものです。

src/Ext/SmartyExtensionBundle/Extension/TemplateFiltersExtension.php
<?php

namespace Ext\SmartyExtensionBundle\Extension;

use Psr\Log\LoggerInterface as Logger;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
use NoiseLabs\Bundle\SmartyBundle\Extension\AbstractExtension;
use NoiseLabs\Bundle\SmartyBundle\Extension\Filter\PreFilter;

class TemplateFiltersExtension extends AbstractExtension
{
    // not required.
    public function __construct(Container $container, Logger $logger)
    {
        $this->container = $container;
        $this->logger = $logger;
    }

    // required (the official doc. said.)
    public function getName()
    {
        // the extension name.
        return 'ext.ssi2include';
    }

    public function getFilters()
    {
        return array(
            // filter name, extension obj, filter function(method) name
            new PreFilter('prefilter_ssi2include', $this, 'ssi2include'),
        );
    }

    // filter function(method).
    // example: replace ssi-tags to smarty include tags.
    public function ssi2include($source) {

        $left_delimiter = $this->container->getParameter('smarty.opt.delimiter.left');
        $right_delimiter = $this->container->getParameter('smarty.opt.delimiter.right');
        $source = preg_replace('/<!--#include\ (virtual|file)="\/?(.+)?"-->/i',
            $left_delimiter . 'include file=\'' . $_SERVER['DOCUMENT_ROOT'] . '/' . "$2" . '\'' . $right_delimiter,
            $source
        );

        return $source;
    }
}

コンストラクタは必須ではないですが、getName メソッドは必須です。

Smartyのフィルタを利用する場合は、getFilters の戻り値として、PreFilter(FilterInterface の実装クラス)の配列を返すことで、$smarty->register_prefilter() に対象のメソッドが渡されます。

公式のドキュメントでは、第一引数が $this、第二引数がフィルタ本体のメソッド名となっていますが、インストールされたバージョンでは第一引数はフィルタ名を指定するようになっています。

何かの設定で変更できるとは思いますが、デフォルトではフィルタの実装の変更を反映させる際は毎回キャッシュをクリアしてやる必要がありました。

サービスコンテナに登録

サービスコンテナに登録する際、smarty.extension というタグを付けるだけで SmartyBundle の Extension として動作します。

src/Ext/SmartyExtensionBundle/Resources/config/services.yml
services:
    smarty.extension.template_filters:
        class: Ext\SmartyExtensionBundle\Extension\TemplateFiltersExtension
        arguments: [ "@service_container", "@logger" ]
        tags:
            - { name: smarty.extension }

arguments のサービスコンテナはパラメータを取得するために渡しています。

おまけ: サンプルで参照している設定

サンプルで利用しているだけで、本筋とは関係ありませんが、参照しているパラメータ等は下記のように設定しています。

app/config/config.yml
parameters:
    smarty.opt.delimiter.left:  "{"
    smarty.opt.delimiter.right: "}"

smarty:
    options:
        left_delimiter:  "%smarty.opt.delimiter.left%"
        right_delimiter: "%smarty.opt.delimiter.right%"
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away