首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

Smarty 3 擴充自訂 {load} 標籤實現模板端資料自動載入(類 foreach 語法)

     編輯:PHP 相關知識

Smarty 預設需在 PHP 端 assign 變數才能在模板使用,若區塊眾多會導致控制器臃腫。本文示範如何修改 Smarty 3 編譯器,新增 {load}…{/load} 標籤,讓模板直接宣告資料來源並自動迴圈,語法類似 {foreach}。

一、修改編譯器 Smarty_Compiler.class.php

1. 在 _compile_tag() 中註冊標籤

<?php
// 載入開始標籤
case 'load':
    $this->_push_tag('load');
    return $this->_complie_load_start($tag_args);
    break;

// 載入結束標籤
case '/load':
    $this->_pop_tag('load');
    return "";
    break;

2. 新增編譯方法 _complie_load_start()

<?php
/**
 * 編譯 {load} 開始標籤
 * 語法:{load table="表名" where="條件" limit="筆數" class="模型類別" item="迴圈變數"}
 */
function _complie_load_start($tag_args) {
    // 依參數生成唯一暫存變數名,避免巢狀衝突
    $key = substr(md5($tag_args), 8, 16);

    // 解析屬性
    $attrs = $this->_parse_attrs($tag_args);

    // 預設模型類別
    $class = (!isset($attrs['class']) || empty($attrs['class'])) ? 'cls_crud' : trim($attrs['class']);

    // 必填:table
    if (!isset($attrs['table']) || empty($attrs['table'])) {
        exit('`table` attribute is empty!');
    }
    $table = substr($attrs['table'], 1, -1); // 去除引號

    // 實例化模型並取得資料
    $db = $class::factory(array('table' => $table));
    $where = isset($attrs['where']) ? substr($attrs['where'], 1, -1) : '';
    $limit = isset($attrs['limit']) ? $attrs['limit'] : '';

    // 指派給 Smarty 臨時變數
    $this->_tpl_vars[$key] = $db->get_block_list(array($where), $limit);

    // 將 from 導向該變數,交由 foreach 編譯器處理
    $tag_args = "from=\$" . $key . " " . $tag_args;
    return $this->_compile_foreach_start($tag_args);
}

二、模板使用範例

{load table="test" where="`id`<100" limit=10 item=rec}
    <div class="item">
        <h3>{$rec.title}</h3>
        <p>{$rec.content}</p>
    </div>
{/load}

編譯後相當於:

<?php
$_from = $this->_tpl_vars[''];
if (is_array($_from) && count($_from)):
    foreach ($_from as $this->_tpl_vars['rec']):
?>
    <div class="item">...</div>
<?php
    endforeach;
endif;
unset($_from);
?>

三、進階擴充建議

  • 支援 order、group、join:在 _parse_attrs 解析更多屬性,傳給 get_block_list。
  • 快取機制:在模型層加入 Cache::get/set,避免重複查詢。
  • 權限控管:編譯器端可檢查當前用戶角色,決定是否允許載入敏感表。
  • 除錯模式:加入 debug=true 參數,編譯時輸出 SQL 日誌。

四、注意事項

  1. 修改核心檔風險:升級 Smarty 時會覆蓋,建議改寫為編譯器插件或繼承 Smarty_Compiler覆寫方法。
  2. SQL 注入風險:where 直接拼入 SQL,務必在模型層使用參數綁定或白名單過濾。
  3. 效能考量:模板端查詢會打破 MVC 分層,大型專案建議改用 View Model / Presenter 模式,在控制器統一準備資料。
  4. 巢狀 {load}:目前實作使用 MD5 產生唯一變數名,可支援巢狀,但需確保 item 不衝突。

五、替代方案:Smarty 區塊函數

若不想修改編譯器,可撰寫區塊函數 smarty_block_load:

<?php
function smarty_block_load($params, $content, $smarty, &$repeat) {
    if ($repeat) return; // 只執行一次

    $class = isset($params['class']) ? $params['class'] : 'cls_crud';
    $table = $params['table'];
    $where = isset($params['where']) ? $params['where'] : '';
    $limit = isset($params['limit']) ? $params['limit'] : '';

    $db = $class::factory(array('table' => $table));
    $data = $db->get_block_list(array($where), $limit);

    $out = '';
    foreach ($data as $row) {
        $smarty->assign('rec', $row);
        $out .= $smarty->fetch('string:' . $content); // 子模板渲染
    }
    return $out;
}
?>

模板寫法:

{load table="test" where="id<100" limit=10}
    {$rec.title} - {$rec.content}<br>
{/load}

此法無需修改核心,相容性較佳,適合輕量專案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved