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

Smartyのforeachを使って商品一覧ページテンプレートなどを実現

Smartyユーザでもない人間が思い出しながらSmartyとテンプレートの良さについて解説するシリーズ(前回Smarty3.x編前々回Smarty2.x編)。前回までの例だと、いまいちテンプレートエンジンの必要性が伝わりにくい。そこで、今回はテンプレートエンジンが輝く例として、ありきたりではあるが商品の一覧ページを作る場合などについて解説していこう。

Smartyのforeachで、配列の要素数だけ繰り返し出力

オンラインショップを運営していて、商品の削除や追加があった場合、商品一覧ページから商品を消したり既存のリスト項目のhtmlをコピーして内容だけ変えて追記したりと、静的な仕組みの場合には都度の手間がかかってしまう。そこで、商品をデータベースに追加したら自動的に商品一覧ページに追加、表示してくれるような仕組みがあると有り難い。
勿論そうした仕組みを実現するには、データベースの知識などが必要である。まあ、その点はクリア出来たとして(きっと”SELECT * FROM table WHERE〜”とかなんとかSQLで取得したとして)、次に手元に出来た配列の要素数だけリスト項目を作ろうという段階になるわけだ。
データベースから帰ってくる結果の数については、もちろんテンプレートを用意する段階では知るよしもない。そこで、配列の要素数を読み取ってその回数だけループさせるための言語構造、foreachを使う。

 
//{foreach}から{/foreach}までの部分を、$arrayの要素数だけ繰り返す。
//配列のキー名はkey=で取り出す。
//値はitem=で取り出す。
//いずれも与えた文字列と同じ名前の変数({$key}、{$value}など)で取り出す。
 
<ul>
{foreach from=$array key="key" item="value"}
<li>キー値{$key}の値は{$value}</li>
{/foreach}
</ul>

たとえば$array = array(“山”,”川”,”谷”);という宣言の後に上のforeach部分が解釈されると、出力htmlは以下のようになる。

<ul>
<li>キー値1の値は山。</li>
<li>キー値2の値は川。</li>
<li>キー値3の値は谷。</li>
</ul>

このように、配列の要素数だけのリスト項目を出力してくれる。

Smartyではテンプレート自体に条件分岐を埋められる

ただ、上の例は実は要素数が0の場合に対応できていない。要素数が0だと、リスト項目をもたないただのulタグのみが出力されてしまい、htmlの文法エラーとなってしまう。
そこで、配列の要素数が0の場合ulタグも出力しないといったような条件分岐もつけたくなる。Smartyのテンプレート側でその対応は可能で、{if}内でPHP関数empty()を用いて出力の調整が出来る。

{if empty($array)}
<p>項目がありません。</p>
{else}
<ul>
{foreach from=$array key="key" item="value"}
<li>項目名{$key}の値は{$value}</li>
{/foreach}
</ul>
{/if}

このようにロジックを埋め込める。テンプレート側にロジックを埋め込むのはMVCの観点上あまりよろしいことではないのだが、こういった対応も可能ということで。

実際に商品一覧ページをテンプレートにしてみる

それでは、実際に例として商品一覧ページを作ってみよう。今回例に使うのはSmarty3.xなので、そこのところご注意を。

 
<!-- base.tpl -->
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/base.css" type="text/css">
{if $page.description != ""}
<meta name="description" content="{$page.description}">
{else}
<meta name="description" content="サンプル株式会社のホームページです">
{/if}
{if $page.keywords != ""}
<meta name="keywords" content="{$page.keywords}">
{else}
<meta name="keywords" content="サンプル株式会社,小売業,日本">
{/if}
<title>{$page.title} | サンプル株式会社</title>
{block name=head}
{/block}
</head>
<body>
<div id="wrapper">
<header>
<h1>サンプル株式会社</h1>
</header>
<div id="main">
{block name=main}
<article>
<h1>デフォルト文章</h1>
<p>mainのブロックに指定が無い場合のデフォルト文章です。</p>
.
.
</article>
{/block}
</div>
<footer>
<p>サンプル株式会社 2012-{$smarty.now|date_format:"%Y"} all rights reserved.</p>
</footer>
</div>
</body>
</html>
 
<!-- item.tpl -->
<li>
<section>
<h1>{$value.name}</h1>
<p>{$value.description}</p>
<p>{$value.price|number_format:0}円</p>
<p><a href="http://xxxxxxxx.xxx/item.php?id={$value.id}" title="{$value.name}の商品詳細">>>商品詳細へ</a></p>
</section>
</li>
 
<!-- itemlist.tpl -->
{extends file="base.tpl"}
{block name=main}
<article>
<h1>サンプル株式会社の商品一覧</h1>
{if empty($page.items)}
<p>現在取り扱っている商品はありません</p>
{else}
<p>当社が取り扱う商品の一覧です。</p>
<ul id="itemlist">
{foreach from=$page.items item="value"}
{include file="item.tpl"}
{/foreach}
</ul>
{/if}
</article>
{/block}

base.tplはどのページにも共通するベースのテンプレート。item.tplが商品情報と個別ページへと飛ぶリンクをのせる枠組みで、itemlist.tplというのは商品一覧ページitemlist.phpが呼ばれた時に読み込むテンプレート。このitemlist.tplがbase.tplの子テンプレートになっているわけだ。というわけで、呼び出し側のPHP。Smartyのパス等はdefinesmarty.phpという別ファイルにまとめたという設定で。

//itemlist.php
 
require_once("script/definesmarty.php");
$items = array();
 
//本来$itemsにデータベースから取ってきた商品情報を入れる処理が入る。
//ここでは以下の情報がかえってきたものとする。
 
$items = array(
array("id" => "1","name" =>"商品A","description" => "さわやかなミントの香りの牛車です","price" => "100000"),
array("id" => "2","name" =>"商品B","description" => "官位です。これがあれば思いのまま(返品不可)","price" => "3000"),
array("id" => "10","name" =>"商品C","description" => "古今和歌集です。お買い得セール!後の世に国宝になりますよ","price" => "160000")
);
$page = array(
"description" => "サンプル株式会社の商品一覧ページです。",
"keywords" => "サンプル株式会社,ネットショップ",
"title" => "当社商品の一覧",
"items" => $items
);
$smarty->assign("page",$page);
$smarty->display("itemlist.tpl");

色々と新しい表現などが登場しているが、とりあえず出力はこんな感じだ。

itemlist.phpへアクセスした結果

itemlist.phpへアクセスした結果

テンプレート内で使える、Smartyの便利な機能

前回までの例と異なり、今回はassignで連想配列を与えている。連想配列のキーで値にアクセスするためには、変数の後ろにピリオドをつける。これはまあ、説明しなくてもなんとなく分かってもらえるだろう。オブジェクトのメンバの場合には、標準的なPHPの場合と同じく”->”でアクセスする。
次に、所々に出てくる、変数の後ろに”|”がついているもの。これは後ろに続くのが修飾子名で、変数を展開した後のテキスト処理を行ってくれる。例で挙げているもののうち、”number_format:0″という修飾子。これは数字の3桁毎にカンマを入れてくれている。したがって出力後の数字は100,000円などとなっているはずだ。この修飾子のさらなる使い方は、PHPマニュアルでも見てほしい。
そして、フッタ部クレジットにある$smarty.nowというのは、Smartyが標準で備える予約変数で、プログラム動作時のタイムスタンプを得る。例のように書いておけば、年が明けてもクレジットの年号を変更する必要が無くなるわけだ。

如何だっただろうか。Smartyを使えばこのように簡単にテンプレートを用いた開発が出来る。究極足りないところはインラインPHPで補いながら開発ができるので、Dreamweaverのテンプレートより便利だろう。
こんなに便利なSmartyだが、惜しむらくはやはりヴァージョン2と3のユーザが混在しており、WEBで調べながら開発していく方法においてはリファレンスがどちらのヴァージョンに基づいたものなのか分かりにくいということ。あと、公式マニュアル(Bitcoinがドネートできる!)のデザインが無骨。確かTwigに乗り換えた理由の1つは、マニュアルがオシャレだったから、とどうでも良いことを思い出したり。