在構建多皮膚、多站點或 SaaS 多租戶應用時,往往需要根據域名、用戶角色或配置動態切換視圖目錄。CodeIgniter 3 核心類 CI_Loader 提供了 add_package_path() 方法,配合路徑優先級機制,可優雅實現此需求。
CI_Loader 內部維護 _ci_view_paths 數組,鍵為路徑,值為是否級聯。add_package_path() 通過 array_unshift 將新路徑插入數組頭部,使其擁有最高優先級。加載視圖時,系統按順序遍歷該數組,首個找到的文件生效。
application/
├── views/ # 默認視圖(回退用)
└── skins/
├── default/
│ └── views/ # 默認皮膚視圖
├── mobile/
│ └── views/ # 移動端皮膚視圖
└── tenant_123/
└── views/ # 租戶專屬視圖
關鍵約定:每個皮膚目錄下必須包含 views/ 子目錄,視圖文件直接放置於此。
<?php
class MY_Controller extends CI_Controller {
protected $current_skin = 'default';
public function __construct() {
parent::__construct();
// 業務邏輯:根據域名、Session、配置決定皮膚
$this->resolve_skin();
// 注入皮膚視圖路徑(最高優先級)
$skin_view_path = FCPATH . 'application/skins/' . $this->current_skin . '/views/';
$this->load->add_package_path($skin_view_path, TRUE); // TRUE 允許級聯查找庫/助手/配置
}
private function resolve_skin() {
// 示例:從配置或 Session 獲取
$this->current_skin = $this->config->item('active_skin') ?? 'default';
// 進階:多租戶場景
// $tenant_id = $this->session->userdata('tenant_id');
// $this->current_skin = "tenant_{$tenant_id}";
}
}
調用 $this->load->view('welcome') 時,查找順序:
application/skins/{current_skin}/views/welcome.php(皮膚專屬)application/views/welcome.php(默認回退)若皮膚目錄缺失該文件,自動回退至默認視圖,實現「覆蓋式定制」。
TRUE(默認):允許從該包路徑加載 Library、Helper、Config。適用於皮膚自帶組件。FALSE:僅影響視圖路徑,隔離副作用。推薦純視圖切換場景使用。若需同時加載「公共組件包」+「皮膚包」,調用順序決定優先級:
// 1. 先加載公共包(低優先級)
$this->load->add_package_path(FCPATH . 'application/packages/shared/', FALSE);
// 2. 再加載皮膚包(高優先級,覆蓋公共包視圖)
$this->load->add_package_path(FCPATH . 'application/skins/' . $skin . '/views/', FALSE);
stat 調用。add_package_path,應在構造函數單次執行。config.php 中的 $config['view_folder']?| 維度 | 修改配置 | add_package_path |
|---|---|---|
| 動態性 | 需重寫配置文件/重啟 | 運行時動態切換 |
| 多租戶隔離 | 困難 | 原生支持 |
| 回退機制 | 無(找不到報錯) | 自動級聯回退 |
| 代碼侵入性 | 高(影響全局) | 低(控制器級控制) |
利用 CI_Loader::add_package_path() 實現視圖路徑動態切換,是 CodeIgniter 3 實現多主題、多租戶架構的最佳實踐。核心在於:約定 skins/{name}/views/ 目錄結構 → 基礎控制器構造函數注入路徑 → 享受自動優先級與回退機制。這一方案零侵入核心代碼,完全符合框架設計哲學。