CakePHPでテンプレートにDBを使用する方法

現在進行している案件では、リリース後はクライアントさんの運用担当者にtemplate修正をしてもらう流れになるので、CMS的な物を作成中です。

そこで問題になるのは、templateエンジンどうするか!
CakePHP1.2では、拡張子 ctpのphpファイルがデフォルトのテンプレートなのですが、さすがにそのままデザイナさんや運用担当の方に修正をお願いするのも忍びないし、ちょっと怖いですよね。

で、クライアントサイドで修正する物は SmatyViewを使い、Smartyで実現する事にしました。

Smartyには、リソースプラグインという機構があって、ファイルシステム上に限らず独自テンプレートソースを定義する事ができます。
実習もかねて(^^;、これをCakePHPで実現する為に実験をしてみました。

使用するリソース

今回は一般的に一番使われるであろう、DB上のテンプレートソースを扱ってみる事にします。テーブルの構造は例えばこんな感じ...。

CREATE TABLE "templates" (
"id" SERIAL NOT NULL ,
"name" VARCHAR(256) NOT NULL,
"data" TEXT NOT NULL,
"created" TIMESTAMP NOT NULL ,
"modified" TIMESTAMP ,
PRIMARY KEY ("id")
);

SmartydbViewを作成

要件を簡単に実現する為に、SmartydbViewというクラスをSmartyViewから派生させました。
ソースは以下。

<?php
class SmartydbView extends SmartyView
{    
  function __construct(&$controller)
  {
    parent::__construct($controller);

    $this->subDir = null;
    $this->ext= null;

    $this->smarty->register_resource("db", array($this, "__get_template",
          "__get_template_timestamp",
          "__get_template_secure",
          "__get_template_trusted"));
    $this->smarty->default_resource_type = 'db' ;

    $this->_template = ClassRegistry::init('Template');      
    $this->_template->recursive = 0 ;
    
    $this->template = array() ;
  }
	
  function __get_template($tpl_name, &$tpl_source, &$smarty)
  {
    $tpl = $this->__read_template( $tpl_name ) ;
    if ( $tpl === false ) 
      return false ;
   
    $tpl_source = $tpl['Template']['data'];
    return true ;
  }
  
  function __get_template_timestamp($tpl_name, &$tpl_timestamp, &$smarty)
  {    
    $tpl = $this->__read_template( $tpl_name ) ;
    if ( $tpl === false ) 
      return false ;
      
    $tpl_timestamp = strtotime($tpl['Template']['modified']) ;

    return true ;
  }
  
  function __get_template_secure($tpl_name, &$smarty)
  {
      // 全てのテンプレートがセキュアであると仮定する
      return true;
  }

  function __get_template_trusted($tpl_name, &$smarty)
  {
      // テンプレートからは使用しない
  }
 
  function _getViewFileName($name = null) 
  {
    $subDir = null;

    if ($name === null) {
      $name = $this->action;
    }
    $name = str_replace('/', DS, $name);

    $tpl = $this->__read_template( $name ) ;
    
    if ( $tpl !== false ) {
      return $name ;
    }
    
    return $this->_missingView($name, 'missingView');
  }
	
  function _getLayoutFileName($name = null)
  {
    if ($name === null) {
      $name = $this->layout;
    }
		
    $tpl = $this->__read_template( $name ) ;
    
    if ( $tpl !== false ) {
      return $name ;
    }
    return $this->_missingView($file, 'missingLayout');
  }

  function __read_template( $name ) 
  {
    if ( !array_key_exists( $name, $this->template ) ) {
      $tpl = $this->_template->findByName($name) ;
      if ( !$tpl ) 
        return false ;
        
      $this->template[$name] = $tpl ;
    }
    
    return $this->template[$name] ;
  }
}
?>

テスト用のコントローラ

実際にDB上のテンプレートソースを使う為に、テスト用のコントローラを準備します。

<?php
class TesttemplatesController extends AppController {
    var $name    = 'Testtemplates';
    var $uses    = array();
    var $helpers = array('Html', 'Form');

    var $layout = 'mylayout';
    var $view    = 'Smartydb';
		
    function index()
    {
      $this->set('smarty_content', 'Testing SmartyView');
      $this->render( 'testpage') ;
    }
}
?>

これで、先ほどのテーブルに、mylayoutという名前のレイアウトとtestpageテンプレートを作れば表示出来ます。

まとめ

SmartyViewのおかげで思いのほか簡単に実現出来ました!作者のMASA-Pさんに感謝!
実際の業務で使うには、色々追加しなければならない事があるとおもいますが実験報告という事で。