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

CodeIgniter 3 整合 Smarty 3 完整教程:核心類擴展、配置管理、模板繼承與最佳實踐

     編輯:PHP 相關知識

為什麼選擇 Smarty?

CI 內建視圖機制功能單一,缺乏模板繼承、區塊覆寫、快取、沙箱安全等企業級特性。Smarty 3 作為成熟模板引擎,提供:

  • 模板繼承:{block}/{extends} 實現佈局複用
  • 編譯快取:模板編譯為 PHP 檔案,效能接近原生
  • 沙箱模式:限制模板可用 PHP 函數,提升安全性
  • 豐富修飾詞:|escape, |date_format, |truncate 等
  • 插件機制:自訂函數、修飾詞、區塊函數

整合架構設計

CI_Controller (核心)
    └── MY_Controller (應用基礎控制器)
          ├── $this->smarty (CISmarty 實例)
          ├── assign($key, $val)  -> $this->smarty->assign()
          ├── display($tpl)       -> $this->smarty->display()
          └── fetch($tpl)         -> $this->smarty->fetch()

CISmarty extends Smarty
    ├── __construct() 載入 CI 配置
    ├── template_dir = APPPATH . 'views/'
    ├── compile_dir  = APPPATH . 'templates_c/'
    ├── cache_dir    = APPPATH . 'cache/smarty/'
    ├── left_delimiter  = '<{'
    ├── right_delimiter = '}>'
    └── caching = FALSE (開發) / TRUE (生產)

步驟 1:安裝 Smarty 3

# Composer 安裝 (推薦)
composer require smarty/smarty ^3.1

# 或手動下載:https://www.smarty.net/download
# 解壓 libs/ 至 application/libraries/Smarty-3.1.48/

步驟 2:建立封裝庫 application/libraries/CISmarty.php

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

require_once APPPATH . 'libraries/Smarty-3.1.48/libs/Smarty.class.php';

class CISmarty extends Smarty {
    protected $CI;

    public function __construct() {
        parent::__construct();
        $this->CI =& get_instance();

        // 載入專用配置
        $this->CI->config->load('smarty', TRUE, TRUE);
        $cfg = $this->CI->config->item('smarty');

        // 目錄配置
        $this->setTemplateDir($cfg['template_dir'] ?? APPPATH . 'views/');
        $this->setCompileDir($cfg['compile_dir'] ?? APPPATH . 'templates_c/');
        $this->setCacheDir($cfg['cache_dir'] ?? APPPATH . 'cache/smarty/');
        $this->setConfigDir($cfg['config_dir'] ?? APPPATH . 'configs/');

        // 分隔符 (避免與 JS 模板衝突)
        $this->left_delimiter  = $cfg['left_delimiter']  ?? '<{';
        $this->right_delimiter = $cfg['right_delimiter'] ?? '}>';

        // 快取與編譯檢查
        $this->caching        = $cfg['caching'] ?? (ENVIRONMENT !== 'production');
        $this->cache_lifetime = $cfg['cache_lifetime'] ?? 3600;
        $this->compile_check  = (ENVIRONMENT !== 'production');
        $this->force_compile  = (ENVIRONMENT === 'development');

        // 安全設定:沙箱模式 (生產環境建議開啟)
        if (ENVIRONMENT === 'production') {
            $this->security_policy = 'php'; // 允許 PHP 標籤但受限
            $this->php_handling    = Smarty::PHP_PASSTHRU; // 或 PHP_REMOVE
            $this->security_settings['PHP_HANDLING'] = Smarty::PHP_REMOVE;
        }

        // 註冊 CI 專用修飾詞/函數
        $this->registerPlugin('modifier', 'base_url', function($url) {
            return $this->CI->config->base_url($url);
        });
        $this->registerPlugin('modifier', 'site_url', function($uri) {
            return $this->CI->config->site_url($uri);
        });
        $this->registerPlugin('function', 'csrf_field', function() use ($CI) {
            return $CI->security->get_csrf_token_name() . '="' . $CI->security->get_csrf_hash() . '"';
        });
    }
}

步驟 3:配置檔 application/config/smarty.php

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

$config['template_dir']    = APPPATH . 'views/';
$config['compile_dir']     = APPPATH . 'templates_c/';
$config['cache_dir']       = APPPATH . 'cache/smarty/';
$config['config_dir']      = APPPATH . 'configs/';
$config['left_delimiter']  = '<{';
$config['right_delimiter'] = '}>';
$config['caching']         = (ENVIRONMENT === 'production');
$config['cache_lifetime']  = 3600;
$config['compile_check']   = (ENVIRONMENT !== 'production');
$config['force_compile']   = (ENVIRONMENT === 'development');

步驟 4:建立目錄權限

mkdir -p application/templates_c application/cache/smarty application/configs
chmod 777 application/templates_c application/cache/smarty
# Windows: 右鍵屬性 → 安全性 → 編輯 → Everyone → 完全控制

步驟 5:自動載入 application/config/autoload.php

$autoload['libraries'] = ['database', 'session', 'CISmarty'];
$autoload['helper']    = ['url', 'form', 'html'];

步驟 6:擴展核心控制器 application/core/MY_Controller.php

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class MY_Controller extends CI_Controller {
    public function __construct() {
        parent::__construct();
    }

    // 代理常用方法,保持 Smarty 原生呼叫習慣
    public function assign($key, $val = null) {
        if (is_array($key)) {
            foreach ($key as $k => $v) $this->smarty->assign($k, $v);
        } else {
            $this->smarty->assign($key, $val);
        }
        return $this; // 支援鏈式呼叫
    }

    public function display($template, $cache_id = null, $compile_id = null) {
        $this->smarty->display($template, $cache_id, $compile_id);
    }

    public function fetch($template, $cache_id = null, $compile_id = null) {
        return $this->smarty->fetch($template, $cache_id, $compile_id);
    }

    // 便利方法:直接渲染並輸出 JSON (API 專用)
    public function render_json($data, $status = 200) {
        $this->output
             ->set_status_header($status)
             ->set_content_type('application/json', 'utf-8')
             ->set_output(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES))
             ->_display();
        exit;
    }
}

步驟 7:控制器使用範例

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Welcome extends MY_Controller {
    public function index() {
        $this->assign([
            'title'   => '歡迎來到 CI + Smarty',
            'user'    => ['name' => 'John', 'role' => 'admin'],
            'items'   => ['Apple', 'Banana', 'Cherry'],
            'base_url' => base_url(),
        ]);

        // 直接渲染模板
        $this->display('welcome.tpl');
    }

    public function api_users() {
        $users = $this->db->get('users')->result_array();
        $this->render_json(['code'=>0, 'data'=>$users]);
    }
}

步驟 8:模板檔案 application/views/welcome.tpl

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title><{$title}></title>
    <link href="<{base_url('assets/css/app.css')}>" rel="stylesheet">
</head>
<body>
    <header>
        <h1><{$title}></h1>
        <p>當前用戶: <{$user.name}> (<{$user.role}>)</p>
    </header>

    <main>
        <ul>
        <{foreach $items as $item}>
            <li><{$item}></li>
        <{/foreach}>
        </ul>
    </main>

    <{* 模板繼承範例 *}>
    <{extends file="layouts/main.tpl"}>
    <{block name="content"}>
        <p>這是子頁面內容</p>
    <{/block}>
</body>
</html>

模板繼承實戰:佈局檔 application/views/layouts/main.tpl

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title><{block name="title"}>預設標題<{/block}></title>
    <{block name="head"}><{/block}>
</head>
<body>
    <header><{block name="header"}>共用導航列<{/block}></header>
    <main><{block name="content"}><{/block}></main>
    <footer><{block name="footer"}>© 2024 My App<{/block}></footer>
    <{block name="scripts"}><{/block}>
</body>
</html>
// 子頁面 application/views/user/profile.tpl
<{extends file="layouts/main.tpl"}>
<{block name="title"}>用戶檔案 - <{$user.name}><{/block}>
<{block name="content"}>
    <div class="profile">
        <h2><{$user.name}></h2>
        <p>Email: <{$user.email}></p>
    </div>
<{/block}>

進階技巧與最佳實踐

  1. 自訂修飾詞:$this->smarty->registerPlugin('modifier', 'json', 'json_encode'); → 模板用 <{$data|json}>
  2. 區塊函數:實現可重複使用的 UI 組件 (如分頁、表單欄位)
  3. 快取策略:$this->smarty->display('page.tpl', 'cache_id_123'); 針對不同用戶/參數快取
  4. 模板變數型別提示:在 IDE (PhpStorm) 安裝 Smarty 插件,獲得自動完成
  5. 錯誤處理:開發環境開啟 $this->smarty->debugging = true; 顯示調試主控台
  6. 安全:沙箱模式:生產環境設定 $this->smarty->security_policy = 'php'; $this->smarty->php_handling = Smarty::PHP_REMOVE;

常見問題排查

現象原因解決
模板變更不生效compile_check=FALSE 或快取未清除刪除 templates_c/ 內容;開發環境設定 force_compile=TRUE
Class 'Smarty' not foundrequire_once 路徑錯誤確認 Smarty.class.php 實際路徑,使用 APPPATH 常數
分隔符衝突 (Vue/React {{ }})預設 { } 被前端框架佔用設定 left_delimiter='<{', right_delimiter='}>'
中文亂碼模板檔案編碼非 UTF-8所有 .tpl 檔案儲存為 UTF-8 without BOM
權限錯誤 (無法寫入 compile_dir)目錄不可寫chmod 777 templates_c/ cache/smarty/

總結

透過 CISmarty 封裝庫 + MY_Controller 代理方法 + 專用配置檔,實現 CI 3 與 Smarty 3 的無縫整合。開發者在控制器中使用 $this->assign()/$this->display() 即可享受模板繼承、沙箱安全、編譯快取等企業級特性,同時保持 CI 原生開發習慣。建議新專案直接採用此架構,老專案可漸進式遷移視圖檔案。

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