日別アーカイブ: 2014年5月12日

PHPテンプレートエンジンを使おう Smarty3.x編

前回紹介したSmarty2.xの”閉じhead前切り”パラダイム。htmlを変なところでブツ切りにしなければならない事情は理解できるけれど、やはり少し格好悪い。Dreamweaverのテンプレートと比べると、どうも直感的ではない。また、完成後htmlから切り分けてテンプレートを作っていく形だと、どうしても切り損なってしまい、後から部品テンプレートの数を増やす/減らすなどで、結構な手間が生じる可能性がある。

Smarty3.xのパラダイム テンプレート継承

そこでSmarty3からはDreamweaverのような、テンプレート中の挿入部分をタグで囲み明示する形の仕組みが取り入れられた。この仕組はそして、オブジェクト指向におけるクラスの継承と実に似通ったものとなっている。

<!-- base.tpl -->
<!DOCTYPE html>
<html lang="ja">
<head>
.
.
<title>{$title} | サンプル株式会社</title>
{block name=head}
{/block}
</head>
<body>
<header>
<h1>サンプル株式会社</h1>
</header>
<div id="wrapper">
<div id="main">
{block name=main}
<article>
<h1>デフォルト文章</h1>
<p>mainのブロックに指定が無い場合のデフォルト文章です。</p>
.
.
</article>
{/block}
</div>
{block name=sidebar}
{/block}
</div>
<footer>
.
.
</footer>
</body>
</html>
 
<!-- sidebar.tpl -->
<div id="sidebar">
<aside>
.
.
</aside>
</div>

{$title}の部分は既に説明済ということで、今回新たに出てきたのは{block}である。{block}で始まり、{/block}で終わる部分は、DreamweaverにおけるTemplateBeginEditableと同じく、ここに記述が追加される可能性がありますよという表示である。では、インデックスページのテンプレートindex.tplをbase.tplの子テンプレートとして作成し、head部にメタタグを1行加えた上でサイドバーのテンプレートsidebar.tplを組み込むといったことを行ってみよう。

<!-- index.tpl -->
{extends file="base.tpl"}
{block name=head}
<meta name="description" content="…">
{/block}
{block name=sidebar}
{include file="sidebar.tpl"}
{/block}

親テンプレートの指定は{extends}で行い、親テンプレート中の{block}に挿入する内容を、子テンプレート内の{block}で囲んでいる。
また、親テンプレート中で{block name=main}で囲まれていた部分は、子テンプレートで指定がされていないため、親テンプレート中で囲まれていたデフォルト値が採用される。
{include}については、テンプレートをテンプレート中で読み込む仕組みになる。勿論サイドバーを読み込まないページについては、サイドバーのブロックを子テンプレート中で無指定にすれば良い。このように部品テンプレートの増減にも柔軟に対応できる。

また実際index.phpから呼び出す際には、子テンプレート名だけ指定すれば、自動的に親テンプレートを継承して表示してくれる。

//index.php
require_once("../bin/php/php5.4.4/lib/php/smarty/libs/Smarty.class.php");
$smarty = new Smarty();
$smarty->template_dir = "../bin/php/php5.4.4/lib/php/smarty/templates";
$smarty->compile_dir = "../bin/php/php5.4.4/lib/php/smarty/templates_c";
$smarty->config_dir = "../bin/php/php5.4.4/lib/php/smarty/configs";
$smarty->cache_dir = "../bin/php/php5.4.4/lib/php/smarty/cache";
$smarty->assign("title","トップページ");
$smarty->display("index.tpl");

Smarty3.xの注意点

Smarty2.xに比べて格段に直感的になったSmarty3.xだが、先述の通り依然Smarty2.xに留まっているユーザも多くいる。その理由としては、PHP5.2以上が必要要件であること、速度面でSmarty2.xにかなり劣るということ、メソッド名の命名規則がキャメルケースになったこと(例:$smarty->clear_all_cache()というメソッドが、$smarty->clearAllCache()に)を始めとして文法の見直しが多少あるということなど挙げられる。
一応、Smarty2.xの書き方と互換をもった、Smarty3.xのBC(Backwards Compatibility Wrapper)というものもあり、Smarty.class.phpの代わりにSmartyBC.class.phpを読み込むことで適用することも可能ではある。

SmartyはJavaScriptの扱いで少し面倒くさい

以上、とりあえずSmartyの基本を説明したわけだが、最初に宣言した通り、個人的にはPHPテンプレートエンジンはSmartyでなくTwigを使っている。その理由については、実は解説を書いている内に思い出したのだが、Smartyの場合、波括弧({})に囲まれた部分は言語構造と見なされてしまうため、JavaScriptとの相性が悪い。JavaScriptを書く部分を{literal}{/literal}で囲んでエスケープするか、あるいはSmarty側の設定をいじって、波括弧でないデリミタをあてがわないといけない。

$smarty->left_delimiter = '<!--{';
$smarty->right_delimiter = '}-->';

たとえばこのようにすると、波括弧の代わりに競合しない括弧の定義が出来るわけである。ただし、競合を避けるためだけに通常より多めの記号を打たされている感がしてあまり心証もよくない。また、熟達したsmarty使いとの引き継ぎの際にやはり口論が起きる。

(追記&訂正:コメントでご指摘いただいたとおり、Smarty3では直前ないし直後に空白文字・改行文字・タブなどを伴う波括弧はデリミタとみなされないという仕様ができたらしい。したがって、CSS、JavaScriptともに波括弧使用の後に改行を行うコーディングスタイルであれば、自然にSmartyの言語構造とみなされることを回避してくれる。

CSSの場合

 
/* 前後に改行文字があるためSmartyの言語構造とみなされない */
* {
margin : 0;
}

JavaScriptの場合

 
//前後に改行文字があるためSmartyの言語構造とみなされない
function someFunction(){
return 0;
}
 
//前後に改行文字があるためSmartyの言語構造とみなされない
while(1){
someFunction();
}

ただ、人によっては無名関数の処理部分など改行せずに記述したいという場合もあるので、その場合には少し手直しが必要になるだろう

JavaScript

 
//こんな記述はアウト
var someFunction = function(){return 0;};
 
//せめてこう変えるべき(スペースが入るのでセーフ)
var someFunction = function(){ return 0; };

追記終わり)

twigの場合だと、Smartyの波括弧にあたるのが”{%”と”%}”なので、特別に設定しなくても競合はそう起こらない。起こる可能性があるとしたら、jquery.tmplの言語構造を囲む二重波括弧({{}})が変数とみなされてしまうケースが考えられるけれど、相対的には少ないので、jquery.tmplを使うところだけ{% raw %}{% endraw %}で囲っておくという形で対処する。熟達したtwig使い(そもそもいないのでは?)との間に口論も起きないだろう。