Posts Tagged ‘twig’

CakePHP2.0.2で意地でもTwigを使ってみる

火曜日, 11月 15th, 2011

CakePHPの2.0系が最近安定版リリースされましたね。
まだまだ情報は少ないですが、折角なので新規の開発は1.3系ではなく2系でやりたい!と思うこの頃です。

さて、CakeといえばテンプレートエンジンはSmartyを使う人が多い印象ですが私は圧倒的にTwigが好きです。然り、Twigが好きなわけです。

CakeでTwigを利用するプラグインはこんな感じでKjell Bublitz氏が作成されているわけですが、早くも2系に実験的ながら対応しました的なことが書いてあるのでこれは!ということで導入してみました。
2系の仕様がよくわかってなかったりドキュメントがまだアレだったりと色々ありましたがとりあえず動かせてます。

環境:
CakePHP2.0.2
Twig1.3.0(stable)
cakephp-twig-view(commit a5fc2e6291)

導入:
1)基本的にInstallationに書いてある通りのフォルダ階層で突っ込みます。

こんな感じで、Plugin直下にtwig_viewを配置。
Twig本体はvendorsの下に配置。

2)初期設定諸々

app/Config/bootstrap.phpあたりに下記コードを追加してプラグイン有効化

CakePlugin::load('TwigView');

app/Controller/AppController.phpにてviewClassの変更
(2系は$viewではないっぽい)

class AppController extends Controller {

    public $viewClass = "TwigView.Twig";
}

3)app/Plugin/views/twig.phpの編集
そのままだと動かなかったのでパスまわりの修正をする。
・Twigオートローダーの読み込み

// Load Twig Lib and start auto loader
App::import('Vendor', 'TwigView.TwigAutoloader', array(
'file' => 'Twig'.DS.'lib'.DS.'Twig'.DS.'Autoloader.php'
));
include_once __DIR__ . '/../vendors/' . 'Twig'.DS.'lib'.DS.'Twig'.DS.'Autoloader.php';

・・App::importがなぜかうまく読み込めてなかったので無理矢理include・・App::importの仕様がようわからんです。

・2系用にパス周りの修正とautoescape
まとめてこんな感じに書き換えちゃいました。
autoescapeは後述しますがちょっと問題があるのでお好みで。私はonにしました。

    function __construct(&$controller, $register = true) {

        parent::__construct($controller, $register);

        if($this->isCake2()) {

            // just collecting for str_replace
            $this->templatePaths = array(
                APP.'View',
                ROOT.DS.'cake'.DS.'Lib'.DS.'View'
            );
            $loader = new Twig_Loader_Filesystem(APP.'View');
        } else {
            $this->templatePaths = array(
                APP.'views',
                ROOT.DS.'cake'.DS.'libs'.DS.'view'
            );

            // we always look in APP, this includes error templates.
            $loader = new Twig_Loader_Filesystem(APP.'views');
        }
        // setup twig and go.
        $this->Twig = new Twig_Environment($loader, array(
            'cache' => TWIG_VIEW_CACHE,
            'charset' => strtolower(Configure::read('App.encoding')),
            'auto_reload' => (bool) Configure::read('debug'),
            //'autoescape' => false
            'autoescape' => true
        ));;

        // overwrite some stuff
        $this->Twig->addExtension(new CoreExtension);

        // activate |trans filter
        $this->Twig->addExtension(new Twig_Extension_I18n);

        // activate |ago filter
        $this->Twig->addExtension(new Twig_Extension_TimeAgo);

        // activate basic filter
        $this->Twig->addExtension(new Twig_Extension_Basic);

        // activate number filters
        $this->Twig->addExtension(new Twig_Extension_Number);

        if (isset($controller->theme))
            $this->theme =& $controller->theme;

        $this->ext = '.tpl';
    }

}

$this->isCake2()を使ってざっくりパスの切替をしています。
$this->isCake2は親で設定されるプロパティを使って判定しているので、親のコンストラクタの後に諸々の処理を移動しています。

4)使ってみる

コントローラーでこんな値を設定してみて


public function index() {

    $array_vars = array("foo" => "<bar>","hoge" => "<hogehoge>" );

    $this->set("hello", "<hello! It's a beautiful Twig World!!>");
    $this->set("array_vars", $array_vars);

}

出力してみます。ビューファイルの拡張子は.tplで(変更可能)

<div>
変数:
     {{hello}}
</div>
<div>
連想配列:
<ul id="sortable_list">
{% for k,v in array_vars %}
    <li> {{ k }} , {{ v }}</li>
{% endfor %}
</ul>
</div>
<div>
ヘルパー:
    {{form.create()|raw}}
    {{form.input('input')|raw}}
    {{
    form.input('email', {
        'label': 'Your E-Mail Address'| trans
        })
    |raw}}
    {{form.end()|raw}}
</div>

こんな感じに出力されます

<や’もエスケープされてますね。
オートエスケープをオンにするとヘルパーで生成したコードもエスケープされてしまうので|rawで出力しています。
ここらへんを考慮してデフォルトオフにしているんでしょうが、出来ればヘルパーで生成した場合は自動で生出力とかにしたい・・。

ざっくりまとめ

2.0対応の部分についてはまだドキュメントなども追いついてない部分がありますがとりあえず動かすことは出来ました。
ソースはすべてgithubで公開されているので自分もフィードバック送ったりしたいところですがgitの使い方がようわからん・・。使わないとなあ。

また、2系の仕様がイマイチよくわかってないのでTwigの読み込みがApp::importになってたりアヤシイ感じなのでここはこうじゃないだろ!というツッコミお待ちしております。