register_prefilter再び

どうも、僕です。

こんな僻地のブログでもGoogleさんがインデックスしてくれているお陰で、わざわざ足を運んでくださる方がいらっしゃるようで、大変有難いことです。

ところでこのブログ、どうせみんなTOKYO-TUBEの動画を保存してオフラインで鑑賞する方法が目的で訪問してくるんだろうと思ってたら、意外とSmartyのエラーで来てくれる人がいることがわかったので、register_prefilterについて追記したいと思います。

以前のエントリでは、外人のQA引っ張ってきて、黙ってregisterFilter使えよ的な回答をしたわけですが、もうちょっと具体的に書きたいと思います。


たとえばSmary2系でSmartyクラスを独自にextendしてregister_prefilterを使う場合、こんなふうに書きますね。

class SmartyExtends extends Smarty{ ←Smartyクラスを継承

    public function __construct(){ ←コンストラクタにプレフィルタを登録

        // prefiliter
        parent::register_prefilter( 'default_display_filter' ); ←前処理

        function default_display_filter( $tpl_src, &$Smarty ){ ←前処理の中身
        
            ----- 何か適当な処理 ---
            
            return $tpl_src;
        }
    }
}

まず先頭の

class SmartyExtends extends Smarty

で、SmartyをextendしたSmartyExtendsを作ります。
プログラムからnewするのはSmartyではなく、SmartyExtendsになります。

で、

function __construct(){ ... }

内にparent::register_prefilterすることで、SmartyExtendsがnewされた時点でdefault_display_filterが呼び出されるわけです。

newする度に呼び出されるのは効率的じゃなくね?っていう話もありますので、そういうのが気になる人はdisplayの中でもどこでも好きな様にやってもらって構いません。

さて、これをSmary3でやると、下記のNoticeが出ます

Notice: function call 'register_prefilter' is unknown or deprecated.


これを回避するためには、registerFilterを使うわけですが、こんな風に書き換えます。

class SmartyExtends extends Smarty{    ←Smartyクラスを拡張するのは一緒

    //テンプレート前処理
    function registerFilter($tpl_src, $type='pre'){    ←明示的に前処理を指定
        
        parent::registerFilter( $type,array('SmartyExtends','default_display_filter'));    ←前処理したい関数を登録

    }
    
    static function default_display_filter($tpl_src,$sobj){    ←実際の前処理を記述

         ----- 何か適当な処理 ---

        return $tpl_src;
    }
    
    function display($tempfile='',$cache_id = null, $compile_id = null, $parent = null){    ←display文の中でフィルタを呼ぶように変更
    
        $this->registerFilter($tempfile);    ←parent::displayする前に前処理を明示的に呼び出す
        
        parent::display($templatepath,$cache_id,$compile_id,$parent);    ←display
    }
}


先頭のextendは一緒ですが、Smarty3ではコンストラクタで処理しようとするとなぜかエラーになリます。

コンストラクタはやめて、今回はdisplay内で呼び出すことにします。

function display($tempfile='',$cache_id = null, $compile_id = null, $parent = null)

新たにdisplayクラスを作って、親のdisplayを呼び出すってやつなんですが、PHP5.3からはオーバーライドするときに
上書き元のclassと変数の数が一致しないとエラーを返すので、合わせてやる必要があります。

displayの中でプリフィルタを呼び出すわけですが、ExtendしたSmartyクラス内でカスタムしたregisterFilterを呼び出すように書き換えます。

$this->registerFilter($tempfile);

なんでこんな処理をする必要があるのかというと、後続の処理でプレフィルタにテンプレートを引き渡すためだそうです。
Smartyのサイトに書いてあったとおりです。ここで疑問を挟んではいけません。

    function registerFilter($tpl_src, $type='pre'){
        parent::registerFilter( $type,array('SmartyExtends','default_display_filter'));    
    }

はparent::registerFilterを呼び出すためだけのメソッドですが、直接parent::registerFilterを呼び出すとテンプレート$tpl_srcがプレフィルタに渡せないので、こんなふうに書きます。
Smartyのサイトに書いてあったとおりです。疑問を挟んではいけません。

$typeに指定できるのは、Smartyによれば

"pre", "post", "output" and "variable"

なので、呼び出すタイミングによって$typeを変えます。今回はpreを使いました。

もう一個の引数

array('SmartyExtends','default_display_filter')

SmartyExtendsが以前の&$SmartyにあたるSmartyオブジェクトで、default_display_filterが、プリフィルタしたい処理です。

default_display_filterの第一引数はテンプレート変数で、第二引数はSmartyオブジェクトが入ってます。

static function default_display_filter($tpl_src,$sobj){

第一引数には$this->registerFilter()したときの$tempfileがそのまま渡ってきてます。
第二引数を書いておけば、勝手にSmartyオブジェクトが入ってくれるので、フィルタ内でSmartyメソッドが呼び出せるはず。

たぶんこれでSmarty3でもプリフィルタが使えるはず・・・!