Zend_Application提出的兩個關鍵概念有兩個:
1. Bootstrap
對於Bootstrap,我想接觸過ZF的人都不會陌生,意即把初始化程序的過程封裝,以便管理及修改。在ZF1.8之前,我想大部分人都是這樣(或類似這樣)寫的:
class Bootstrap
...
public function initLoader(){...}
public function initController(){...}
public function initDb(){...}
public function initVIEw(){...}
public function initLayout(){...}
public function initSession(){...}
public function initAuth(){...}
public function initAcl(){...}
...
}
這樣通常會導致Bootstrap非常巨大而臃腫,而若以Zend_Application的形式來bootstrap的話只需要創建application實例並編寫相關的配置文件(ini)就可以了,至於如何創建我將在下面的內容中詳細介紹。
2. Resource
Resource資源的概念實際上可以簡單的說成是ZF的組件,例如Zend_Controller, Zend_Db,Zend_VIEw等等,當然它還具有更深層的意思,例如它允許用戶自定義對於應用程序的資源,是面向用戶的概念。簡單的講就是,它嘗試把調用ZF組件的過程封裝成程序的資源,然後加以利用。而這樣做的好處是顯而易見的。例如,在ZF2.0中Zend_Loader::registerAutoload()將被廢棄,取而代之以Zend_Loader_Autoloader。如果你的程序中是用functioninitLoader()之類的方法來初始化自動加載的話,那就必須要修改程序了,而應用Zend_Application來幫你完成的話就省去了這些煩人的兼容性問題。
例如Zend_Application_Resource_Db的工作就是實例化Zend_Db對象並設置默認adapter,以下是簡化的源代碼:
class Zend_Application_Resource_Db extends Zend_Application_Resource_ResourceAbstract
{
...
// Defined by Zend_Application_Resource_Resource
public function init()
{
...
$this->_db = Zend_Db::factory($adapter, $this->getParams());
Zend_Db_Table::setDefaultAdapter($db);
return $db;
...
}
}
下面,我將盡量詳細的介紹運用Zend_Application組裝應用程序的過程。
首先是目錄結構。
在這裡我建立了兩個模塊分別是front和admin,templates是模版目錄,將存放所有的layout及scripts,ZF放在library下,入口index.PHP放在public下。
讓我們先來看index.PHP的配置:
// Define path to project root
defined('PROJECT_ROOT')
|| define('PROJECT_ROOT',
realpath(dirname(dirname(__FILE__))));
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH',
PROJECT_ROOT . '/application');
// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV',
(getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
: 'production'));
// Include paths
set_include_path(implode(PATH_SEPARATOR, array(
PROJECT_ROOT . '/library',
get_include_path(),
)));
// Zend_Application
require_once 'Zend/Application.PHP';
// Create application
$application = new Zend_Application(
APPLICATION_ENV,
PROJECT_ROOT . '/library/Kbs/Config/Application.ini'
);
umask(0);
// Bootstrap and Run
try {
$application->bootstrap();
$application->run();
} catch (Exception $e) {
// handle exceptions
}
需要解釋的是APPLICATION_ENV是預設的系統環境變量,它將用於Application.ini中區分應用程序運行環境,這裡預設3個值:development, testing, production,分別表示開發環境,測試環境及實際運行環境。
下面再來看Application.ini的配置:
[production]
autoloadernamespaces.0 = "Zend_"
autoloadernamespaces.1 = "Kbs_"
PHPsettings.error_reporting = 8191
PHPsettings.date.timezone = "Asia/Shanghai"
PHPSettings.display_startup_errors = 0
PHPSettings.display_errors = 0
bootstrap.path = APPLICATION_PATH "/Bootstrap.PHP"
bootstrap.class = "Bootstrap"
resources.FrontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.FrontController.moduleControllerDirectoryName = "controllers"
resources.FrontController.defaultModule = "front"
resources.FrontController.plugins.common = "Kbs_Controller_Plugin_Common"
resources.FrontController.noErrorHandler = 0
resources.FrontController.throwExceptions = 1
resources.vIEw.title = ""
resources.vIEw.encoding = "UTF-8"
resources.view.helperPathPrefix = "Kbs_VIEw_Helper_"
resources.view.helperPath = "Kbs/VIEw/Helper/"
resources.vIEw.params.front.basePath = APPLICATION_PATH "/templates/front/default/"
resources.view.params.front.helperPathPrefix = "Kbs_VIEw_Helper_Front_"
resources.view.params.front.helperPath = "Kbs/VIEw/Helper/Front/"
resources.vIEw.params.front.layout = "frontlayout"
resources.vIEw.params.front.layoutPath = APPLICATION_PATH "/templates/front/default/layout"
resources.vIEw.params.admin.basePath = APPLICATION_PATH "/templates/admin/default/"
resources.view.params.admin.helperPathPrefix = "Kbs_VIEw_Helper_Admin_"
resources.view.params.admin.helperPath = "Kbs/VIEw/Helper/Admin/"
resources.vIEw.params.admin.layout = "adminlayout"
resources.vIEw.params.admin.layoutPath = APPLICATION_PATH "/templates/admin/default/layout"
resources.vIEw.params.pathCss = "/public/CSS/"
resources.vIEw.params.pathImg = "/public/img/"
resources.vIEw.params.pathJs = "/public/JS/"
resources.vIEw.params.doctype = "Html4_STRICT"
resources.vIEw.params.charset = "utf-8"
resources.layout.layout = "we use resources.vIEw.params.module.layout instead"
resources.layout.layoutPath = "we use resources.vIEw.params.module.layoutPath instead"
resources.db.adapter = "pdo_MySQL"
resources.db.params.host = "localhost"
resources.db.params.username = "xxx"
resources.db.params.passWord = "xxx"
resources.db.params.dbname = "xxx"
resources.db.isDefaultTableAdapter = true
resources.db.params.driver_options.1002 = "SET NAMES UTF8;"
resources.locale.default = "en_US"
resources.translate.registry_key = "Zend_Translate"
resources.translate.adapter = array
resources.translate.options.scan = "directory"
resources.translate.locale = "zh_CN"
resources.translate.data.zh_CN = APPLICATION_PATH "/languages/zh_CN.PHP"
resources.translate.data.en_US = APPLICATION_PATH "/languages/en_US.PHP"
;resources.translate.data = "we use resources.translate.data.locale instead"
resources.session.save_path = APPLICATION_PATH "/../repository/session"
resources.session.use_only_cookIEs = 1
resources.session.remember_me_seconds = 864000
[testing : production]
PHPSettings.display_startup_errors = 1
PHPSettings.display_errors = 1
resources.db.params.username = "root"
resources.db.params.passWord = ""
resources.db.params.dbname = "kbs"
[development : production]
PHPSettings.display_startup_errors = 1
PHPSettings.display_errors = 1
resources.db.params.username = "root"
resources.db.params.passWord = "root"
resources.db.params.dbname = "kbs"
在這裡,testing及development均繼承自production。值得注意的是,phpsettings是內置的php運行環境參數設定,當然你也可以用.htAccess或者直接在PHP.ini中設定好。bootstrap則是初始化應用程序所需的bootstrap類及其路徑。resources就是我們所說的資源,目前ZF1.8提供的默認資源總共10個:
Zend_Application_Resource_Db
Zend_Application_Resource_Frontcontroller
Zend_Application_Resource_Layout
Zend_Application_Resource_Locale
Zend_Application_Resource_Modules
Zend_Application_Resource_Navigation
Zend_Application_Resource_Router
Zend_Application_Resource_Session
Zend_Application_Resource_Translate
Zend_Application_Resource_VIEw
相信在未來的版本中會有所增加。
最後是application/Bootstrap.PHP
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
// To init the vIEw
protected function _initVIEw()
{
$options = $this->getOptions();
$viewOptions = $options['resources']['vIEw'];
$view = new Zend_View($vIEwOptions);
if (!empty($vIEwOptions['params'])) {
foreach ($vIEwOptions['params'] as $key => $value) {
$vIEw->$key = $value;
}
}
$vIEw->env = $this->getEnvironment();
$vIEw->bootstrap = $this;
$vIEwRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
'VIEwRenderer'
);
$viewRenderer->setView($vIEw);
return $vIEw;
}
// To init the translate
protected function _initTranslate()
{
$options = $this->getOption('resources');
$options = $options['translate'];
if (!isset($options['data'])) {
throw new Zend_Application_Resource_Exception('No translation source data provided.');
}
$adapter = isset($options['adapter']) ? $options['adapter'] : Zend_Translate::AN_ARRAY;
$session = new Zend_Session_Namespace('locale');
if ($session->locale) {
$locale = $session->locale;
} else {
$locale = isset($options['locale'])
? $options['locale']
: null;
}
$data = '';
if (isset($options['data'][$locale])) {
$data = $options['data'][$locale];
}
$translateOptions = isset($options['options'])
? $options['options']
: array();
$translate = new Zend_Translate(
$adapter, $data, $locale, $translateOptions
);
Zend_Registry::set('Zend_Translate', $translate);
return $translate;
}
}
而對於如何為不同模塊(module)指定不同的layout的問題,我的解決辦法是用controller plugin,也是目前來說比較有效的方法。具體如下:
class Kbs_Controller_Plugin_Common extends Zend_Controller_Plugin_Abstract
public function routeShutdown(Zend_Controller_Request_Abstract $request)
{
$module = $request->getModuleName();
$vIEwRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
'VIEwRenderer'
);
$view = $viewRenderer->vIEw;
$moduleParams = $vIEw->$module;
$vIEw->adDBasePath($moduleParams['basePath']);
$vIEw->addHelperPath($moduleParams['helperPath'],
$moduleParams['helperPathPrefix']);
$layout = $vIEw->layout();
$layout->setLayoutPath($moduleParams['layoutPath'])
->setLayout($moduleParams['layout']);
}
routeShutdown方法於route之後執行,這為獲取module提供了辦法,而vIEw和layout所用到的參數都是Application.ini中設置好了的。
以上便是運用Zend_Application配置組裝應用程序的基本過程。這裡忽略了Zend/Application/Module及其相關內容,這是因為筆者覺得ZF1.8中Zend_Application對於module的支持還不完善,希望在未來的版本(應該是2.0)中能夠改善吧。
-