cakePHP+smartyでキャッシュを効かせる

cakePHPでSmartyを使用しているとキャッシュに苦労します。
cakePHP標準のキャッシュが使えるtipsを見つけたいものですが、、、
今回はsmartyのキャッシュを使う方法ですが、落とし穴があるかも知れませんので自己責任でお願いします。

cakeははじめにいろいろ自分の初期化をしてデータベースアクセスし、最後にVIEWを生成します。
このうち初期化の後にキャッシュチェックをして有効であれば、その後をスルーすることにします。
smartyは独自にキャッシュメカニズムを持っているのですが、最後にならないとsmartyが働かないので、コアに手を入れて初期化直後にVIEWクラスを生成します。

まず、smarty内部でキャッシュファイルを生成するようにします。
(私はrequestActionでブロック表示しているものだけキャッシュしたかったので、bareを見ています)
/app/views/smarty.phpの「function __construct」関数($this->ext= '.tpl';とか設定しているところ)の最後に、

if($this->params['bare'] == '1') {  
    $this->Smarty->cache_lifetime = 3600; //有効秒数
    $this->Smarty->caching = true;  //有効化
    $this->cacheid = $this->params['url']['url']; //url毎にキャッシュファイルを生成する。テンプレート単位でキャッシュする場合は不要
} 

function _render(...)の最後のfetchを以下に変更、 

	return $this->Smarty->fetch($___viewFn, $this->cacheid);

/cake/dispatcher.phpの 240行目あたり(return $this->_invoke(...)の直前)で、

include_once(VIEWS."smarty.php");
$viewClass =& new SmartyView($controller);
$tplfile = $viewClass->_getViewFileName($this->params['action']);
if($viewClass->Smarty->is_cached($tplfile,$this->params['url']['url']) === true) {
    $viewClass->render();
    return;
}

smarty.phpをインクルードしてVIEWクラスを生成し、is_cached関数が真の場合、renderしてreturnしてしまいます。 


ちなみにsmartyテンプレートからcakeのrequestActionを呼ぶにはヘルパーを自作しました。
/app/views/helpers/block.php

<?php  
class BlockHelper extends AppHelper {  
    //requestAction  
    function fetch($address = null) {  
        $this->pageTitle = $title;  
        if(!$address) return;  
        $output = $this->requestAction($address, array('return'));  
        return $this->output($output);  
    }  
}  
?>

コントローラーにhelpers宣言しておいて、テンプレートからは
{$block->fetch("/tags/index")}
でNucleusライクに他のアクションの描画結果を呼び出せます。


もっと追加^^)smartyでfetchした結果を再度render評価します。
ブログや管理画面で本文を入力した内容にsmarty関数を書いたりした場合に、一度fetchして再度fetchすることによって巻数を展開します。
smartyにはリソースプラグインという機能があり、ファイルとしてテンプレートを読み込む以外にデータベースなどからテンプレートを読み込めるわけですが、なぜかPHP変数をテンプレートとして使えません。smartyプラグインとして作成します。ここではファイル名は「resource.memory.php」

<?php
function smarty_resource_memory_source($tpl_name,&$tpl_source,&$smarty_obj){
  $tpl_source = $tpl_name;
  return true;
}
function smarty_resource_memory_timestamp($tpl_name,&$tpl_timestamp,&$smarty_obj){
  $tpl_timestamp = time();
  return true;
}
function smarty_resource_memory_secure($tpl_name,&$smarty_obj){
  return true;
}
function smarty_resource_memory_trusted($tpl_name,&$smarty_obj){
}
?>

/cake/dispatcher.phpの上記fetch箇所を 

$text = $this->Smarty->fetch($___viewFn, $this->cacheid);
if(strpos($text, $this->Smarty->left_delimiter) !== false) {
    $text = $this->Smarty->fetch("memory:".$text);
}
return $text;