Zend Framework 1 (ZF1) 以模組化架構支援大型應用開發。本文以 ZF 1.11 為例,詳細說明如何建立多模組專案、配置模組專屬 Bootstrap、實現多佈局 (Layout) 切換,並解決模組佈局不生效的常見問題。
project-root/
├── application/
│ ├── Bootstrap.php
│ ├── configs/
│ │ └── application.ini
│ ├── controllers/ # 預設模組控制器
│ ├── models/
│ ├── views/
│ ├── layouts/
│ │ └── scripts/
│ │ └── layout.phtml
│ └── modules/
│ ├── default/ # 預設模組 (可選顯式建立)
│ └── admin/ # 後台模組
│ ├── Bootstrap.php
│ ├── controllers/
│ │ └── IndexController.php # 類名 Admin_IndexController
│ ├── models/
│ ├── views/
│ │ ├── scripts/
│ │ ├── helpers/
│ │ └── filters/
│ └── layouts/
│ └── scripts/
│ └── layout.phtml
├── library/
│ └── Rockux/ # 自訂命名空間類庫
├── public/
│ └── index.php # 入口點
└── tests/
關鍵在於移除舊版單一控制器目錄設定,改用模組化目錄設定:
; 刪除或註解舊設定
; resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
; 啟用模組化架構
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.frontController.moduleControllerDirectoryName = "controllers"
resources.frontController.defaultModule = "default"
resources.modules[] = ""
; 佈局基礎設定 (預設模組)
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
resources.layout.layout = "layout"
; 註冊自訂命名空間自動載入
autoloaderNamespaces.rockux = "Rockux_"
autoloaderNamespaces.thirdParty = "ThirdPartyLibrary_"
每個模組建立自己的 Bootstrap.php 以註冊模組專屬資源 (資源、視圖助手、過濾器等):
// application/modules/admin/Bootstrap.php
class Admin_Bootstrap extends Zend_Application_Module_Bootstrap
{
// 可覆寫 _initAutoload() 等方法自訂模組行為
}
主 Bootstrap.php 需註冊應用層級自動載入器:
// application/Bootstrap.php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initAppAutoload()
{
$autoloader = new Zend_Application_Module_Autoloader([
'namespace' => 'App',
'basePath' => dirname(__FILE__),
]);
return $autoloader;
}
}
ZF1 預設不支援在 application.ini 直接以 admin.resources.layout.layout 切換模組佈局,需自行實作 Action Helper 在 preDispatch 階段切換。
目錄:application/layouts/scripts/ 下放置 layout.phtml (預設) 與 admin.phtml (後台)。
配置:
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
resources.layout.layout = "layout"
admin.resources.layout.layout = "admin"
目錄:
application/layouts/scripts/layout.phtmlapplication/modules/admin/layouts/scripts/layout.phtml配置:
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
resources.layout.layout = "layout"
admin.resources.layout.layoutPath = APPLICATION_PATH "/modules/admin/layouts/scripts"
建立 library/Rockux/Controller/Action/Helper/LayoutLoader.php:
// 方案一:切換 layout 腳本名稱
class Rockux_Controller_Action_Helper_LayoutLoader extends Zend_Controller_Action_Helper_Abstract
{
public function preDispatch()
{
$bootstrap = $this->getActionController()->getInvokeArg('bootstrap');
$config = $bootstrap->getOptions();
$module = $this->getRequest()->getModuleName();
if (isset($config[$module]['resources']['layout']['layout'])) {
$layoutScript = $config[$module]['resources']['layout']['layout'];
$this->getActionController()
->getHelper('layout')
->setLayout($layoutScript);
}
}
}
// 方案二:切換 layout 路徑
class Rockux_Controller_Action_Helper_LayoutLoader extends Zend_Controller_Action_Helper_Abstract
{
public function preDispatch()
{
$bootstrap = $this->getActionController()->getInvokeArg('bootstrap');
$config = $bootstrap->getOptions();
$module = $this->getRequest()->getModuleName();
if (isset($config[$module]['resources']['layout']['layoutPath'])) {
$layoutPath = $config[$module]['resources']['layout']['layoutPath'];
$this->getActionController()
->getHelper('layout')
->setLayoutPath($layoutPath);
}
}
}
// application/Bootstrap.php
protected function _initLayoutHelper()
{
$this->bootstrap('frontController');
Zend_Controller_Action_HelperBroker::addHelper(
new Rockux_Controller_Action_Helper_LayoutLoader()
);
}
在 Controller 的 init() 中即時切換:
class SpecialController extends Zend_Controller_Action
{
public function init()
{
$layout = Zend_Layout::getMvcInstance();
$layout->setLayout('layout_special'); // 對應 layouts/scripts/layout_special.phtml
}
}
LayoutLoader 已正確註冊於 _initLayoutHelper,且 preDispatch 邏輯匹配模組名稱 (預設模組名為 default)。autoloaderNamespaces 設定、檔案命名是否符合 PSR-0/ZF1 慣例 (類名 Admin_IndexController 對應 Admin/IndexController.php)。view 資源已啟用,模組 views/scripts/ 目錄結構正確。ZF1 多模組架構透過 resources.modules[]、模組 Bootstrap、Module_Autoloader 實現高內聚低耦合。多佈局需配合 Action Helper 在 preDispatch 介入。遵循目錄慣例與命名規範,可構建清晰可維護的大型應用。