子標題:Smarty 入門 - 4
控制樣版的內容
重覆的區塊
上面筆者提到,針對單一的一階陣列,我們可以直接將它 assign 到樣版上;但如果我們想將資料庫所選取出來的多筆資料一次顯示到樣版上時,勢必要透過迴圈將資料傾印出來。在樣版裡,我們可以利用重覆的區塊來完成這樣的動作。
在 Smarty 樣板中,我們要重覆一個區塊有兩種方式: foreach 及 section 。而在程式中我們則要 assign 一個陣列,這個陣列中可以包含數組陣列。就像下面這個例子:
首先我們來看 PHP 程式是如何寫的:
test2.php
![]()
![]()
<?php
require "main.php";
$array1 = array(1 => "蘋果", 2 => "鳳梨", 3 => "香蕉", 4 => "芭樂");
$tpl->assign("array1", $array1);
$array2 = array(
array("index1" => "data1-1", "index2" => "data1-2", "index3" => "data1-3"),
array("index1" => "data2-1", "index2" => "data2-2", "index3" => "data2-3"),
array("index1" => "data3-1", "index2" => "data3-2", "index3" => "data3-3"),
array("index1" => "data4-1", "index2" => "data4-2", "index3" => "data4-3"),
array("index1" => "data5-1", "index2" => "data5-2", "index3" => "data5-3"));
$tpl->assign("array2", $array2);
$tpl->display("test2.htm");
?>
而樣版的寫法如下:
templates/test2.htm
![]()
![]()
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>測試重覆區塊</title>
</head>
<body>
<pre>
直接呈現 array1
{$array1.1}
{$array1.2}
{$array1.3}
{$array1.4}
利用 foreach 來呈現 array1
{foreach item=item1 from=$array1}
{$item1}
{/foreach}
利用 section 來呈現 array1
{section name=sec1 loop=$array1}
{$array1[sec1]}
{/section}
利用 foreach 來呈現 array2
{foreach item=index2 from=$array2}
{foreach key=key2 item=item2 from=$index2}
{$key2} : {$item2}
{/foreach}
{/foreach}
利用 section 來呈現 array2
{section name=sec2 loop=$array2}
index1: {$array2[sec2].index1}
index2: {$array2[sec2].index2}
index3: {$array2[sec2].index3}
{/section}
</pre>
</body>
</html>
執行上例後,我們發現不管是 foreach 或 section 兩個執行結果是一樣的。那麼兩者到底有何不同呢?
第一個差別很明顯,就是 foreach 要以巢狀處理的方式來呈現我們所 assign 的兩層陣列變數,而 section 則以「主陣列[迴圈名稱].子陣列索引」即可將整個陣列呈現出來。由此可知, Smarty 在樣版中的 foreach 和 PHP 中的 foreach 是一樣的;而 section 則是 Smarty 為了處理如上列的陣列變數所發展出來的敘述。當然 section 的功能還不只如此,除了下一節所談到的巢狀資料呈現外,官方手冊中也提供了好幾個 section 的應用範例。
不過要注意的是,丟給 section 的陣列索引必須是從 0 開始的正整數,即 0, 1, 2, 3, ...。如果您的陣列索引不是從 0 開始的正整數,那麼就得改用 foreach 來呈現您的資料。您可以參考官方討論區中的此篇討論,其中探討了 section 和 foreach 的用法。
巢狀資料的呈現
樣版引擎裡最令人傷腦筋的大概就是巢狀資料的呈現吧,許多著名的樣版引擎都會特意強調這點,不過這對 Smarty 來說卻是小兒科。
最常見到的巢狀資料,就算論譠程式中的討論主題區吧。假設要呈現的結果如下:
| 公告區 | |
|---|---|
| 站務公告 | |
| 文學專區 | |
| 奇文共賞 | |
| 好書介紹 | |
| 電腦專區 | |
| 軟體討論 | |
| 硬體週邊 | |
程式中我們先以靜態資料為例:
test3_1.php
![]()
![]()
<?php
require "main.php";
$forum = array(
array("category_id" => 1, "category_name" => "公告區",
"topic" => array(
array("topic_id" => 1, "topic_name" => "站務公告")
)
),
array("category_id" => 2, "category_name" => "文學專區",
"topic" => array(
array("topic_id" => 2, "topic_name" => "好書介紹"),
array("topic_id" => 3, "topic_name" => "奇文共賞")
)
),
array("category_id" => 3, "category_name" => "電腦專區",
"topic" => array(
array("topic_id" => 4, "topic_name" => "硬體週邊"),
array("topic_id" => 5, "topic_name" => "軟體討論")
)
)
);
$tpl->assign("forum", $forum);
$tpl->display("test3.htm");
?>
樣版的寫法如下:
templates/test3.htm
![]()
![]()
<html>
<head>
<title>巢狀迴圈測試</title>
</head>
<body>
<table width="200" border="1" align="center" cellpadding="3" cellspacing="0">
{section name=sec1 loop=$forum}
<tr>
<td colspan="2"> {$forum[sec1].category_name} </td>
</tr>
{section name=sec2 loop=$forum[sec1].topic}
<tr>
<td width="25"> </td>
<td width="164"> {$forum[sec1].topic[sec2].topic_name} </td>
</tr>
{/section}
{/section}
</table>
</body>
</html>
執行的結果就像筆者上面舉的例子一樣。
因此呢,在程式中我們只要想辦法把所要重覆值一層一層的塞到陣列中,再利用 {第一層陣列[迴圈1].第二層陣列[迴圈2].第三層陣列[迴圈3]. ... .陣列索引} 這樣的方式來顯示每一個巢狀迴圈中的值。至於用什麼方法呢?下一節使用資料庫時我們再提。
轉換資料庫中的資料
上面提到如何顯示巢狀迴圈,而實際上應用時我們的資料可能是從資料庫中抓取出來的,所以我們就得想辦法把資料庫的資料變成上述的多重陣列的形式。這裡筆者用 MySQLi 來抓取資料庫中的資料,如果各位有其他自己喜好的資料庫抽象套件的話,原理也是差不多的。
我們只修改 PHP 程式,樣版還是上面那個 (這就是樣版引擎的好處~),而且抓出來的資料就是上面的例子。
test3_2.php
![]()
![]()
<?php
require "main.php";
// 建立資料庫連結
$mysqli = new mysqli("localhost", "username", "password", "testdb");
// 先建立第一層陣列及 SQL 指令
$category = array();
$sql1 = "SELECT category_id, category_name FROM categories";
// 抓取第一層迴圈的資料
if ($result1 = $mysqli->query($sql1)) {
while ($item_category = $result1->fetch_assoc())
{
// 建立第二層陣列及 SQL 指令
$topic = array();
$sql2 = sprintf(
"SELECT topic_id, topic_name FROM topics WHERE category_id = '%s'",
$item_category['category_id']
);
// 抓取第二層迴圈的資料
if ($result2 = $mysqli->query($sql2)) {
while ($item_topic = $result2->fetch_assoc())
{
// 把抓取的資料推入第二層陣列中
array_push($topic, $item_topic);
}
$result2->close();
}
// 把第二層陣列指定為第一層陣列所抓取的資料中的一個成員
$item_category['topic'] = $topic;
// 把第一層資料推入第一層陣列中
array_push($category, $item_category);
$result1->close();
}
}
$mysqli->close();
$tpl->assign("forum", $category);
$tpl->display("test3.htm");
?>
在資料庫抓取一筆資料後,我們得到的是一個包含該筆資料的陣列。透過 while 敘述及 array_push 函式,我們將資料庫中的資料一筆一筆塞到陣列裡。如果您只用到單層迴圈,就把第二層迴圈 (紅色的部份) 去掉即可。