发布时间:2009-5-21 11:54 作者: admin 信息来源: ZendChina [我来说两句(275条)]
Zend Framework1.8的正式发行包中终于把Zend_Application加入其中,这标志着ZF进一步趋向成熟。这两天试着用Zend_Application重构了Bootstrap,觉得虽然还不是很完善,但是也的确大大简化了应用程序的初始化组装过程。
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)中能够改善吧。