现在的位置: 首页 > 综合 > 正文

Zend_Application

2018年05月19日 ⁄ 综合 ⁄ 共 14833字 ⁄ 字号 评论关闭

在开始之前,我有必要介绍一下 Zend_Application 。这是 Zend Framework 1.8 发布中的重大变更,可以说 Zend_Application 和其引入的 Bootstrap 及 Resource 概念,大大简化了应用程序的初始化组装过程,标志着 Zend Framework 真正迈向成熟。  

 Zend_Application 提出了两个关键概念 :  
1. Bootstrap  
对于 Bootstrap,我想接触过 Zend Framework 的人都不会陌生,意即把初始化程序的过程封装,以便管理及修改。在1.8版本出来之前,我想大部分人都是这样(或类似这样)写的 :  

// Bootstrap.php  
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 的形式来做的话,则只需要创建 Zend_Application 实例,并编写相关的配置文件 (.ini) 就可以了,至于如何创建我将在下面的内容中详细介绍。  

2. Resource  
Zend_Application_Resource 是 Zend Framework 针对 php 这种 web 开发语言的特性而加入的。它所阐述的思想是:按需加载 (Loaded On Demand) 。因为 php 每次解析都是资源循环的完整过程,这使得如何将每次php解析的代码量减至最低,就成了优化php应用程序的重要一环,也是众多框架在开发过程中的重点问题之一。  

Resource 的概念实际上可以理解为 Zend Framework 组件,例如 Zend_Controller, Zend_Db, Zend_View 等等。同时它也允许用户自定资源以调用自己的组件。例如 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 Framework 1.8 提供的默认资源总共10个:  
1. Zend_Application_Resource_Db  
 
2. Zend_Application_Resource_Frontcontroller  
 
3. Zend_Application_Resource_Layout  
 
4. Zend_Application_Resource_Locale  
 
5. Zend_Application_Resource_Modules  
 
6. Zend_Application_Resource_Navigation  
 
7. Zend_Application_Resource_Router  
 
8. Zend_Application_Resource_Session  
 
9. Zend_Application_Resource_Translate  
 
10. Zend_Application_Resource_View  

相信在未来的版本中会有所增加。  

下面是初始化一个 FrontController 资源的最简单代码 :  

// 定义应用程序路径  
defined('APPLICATION_PATH')  
    || define('APPLICATION_PATH',  
              MY_PROJECT_ROOT . '/application');  
   
// 定义应用程序环境  
defined('APPLICATION_ENV')  
    || define('APPLICATION_ENV',  
              (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')  
                                         : 'production'));  
   
// Zend_Application 和配置的 FrontController 信息  
require_on

ce 'Zend/Application.php';  
$application = new Zend_Application(  
    APPLICATION_ENV,  
    array(  
        'resources' => array(  
            'FrontController' => array(  
                'controllerDirectory' => APPLICATION_PATH . '/controllers',  
            ),  
        ),  
    )  
);  
   
// 加载资源并运行程序  
$application->bootstrap();  
$application->run();   
 
而通过 Zend_Application_Resource_ResourceAbstract 虚拟类,我们可以很方便的注册自己的资源,然后通过配置文件 (如 Application.ini) 安插进各自的 Bootstrap 过程中。而同时我们可以通过 Zend_Application_Bootstrap_Bootstrap::bootstrap($resource) 方法来动态载入所需资源 (resource) 。  

例如我要注册一个自定义的视图 (View) 资源 :  

// 自定义 view 资源  
class Kbs_Application_Resource_View extends Zend_Application_Resource_ResourceAbstract  

{  
    protected $_view;  
   
    // 初始化 view  
    // @return Zend_View $view  
    public function init()  
    {  
        if (null === $this->_view) {  
            $options = $this->getOptions();  
            $view = new Zend_View($options);  
            ......  
            $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(  

                'ViewRenderer' 
            );  
            $viewRenderer->setView($view);  
            $this->_view = $view;  
        }          
        return $this->_view;  
    }  
}   
 
接着是配置  :  

$application = new Zend_Application(APPLICATION_ENV, array(  
    // 自定义资源的路径及其前缀  
    'pluginPaths' => array(  
        'Kbs_Application_Resource' => 'Kbs/Application/Resource/',  
    ),  
    'resources' => array(  
        'FrontController' => array(...),  
        ......  
        // View 资源  
        'View' => array('title' => 'my application'),  
    ),  
));   
 
当然也可以写在配置文件中,例如 :  

// Application.ini  
 
pluginPaths.Kbs_Application_Resource                    = APPLICATION_PATH "/../library/Kbs/Application/Resource/" 

resources.view.title                                    = "my application" 
resources.view.encoding                                 = "UTF-8" 
然后给出配置文件路径 :  
$application = new Zend_Application(  
    APPLICATION_ENV,   
    PROJECT_ROOT . '/Config/Application.ini' 
));   

经过以上的预习,我们大致了解了一下 Zend_Application 及 Zend_Application_Resource 的情况。接下来让我们正式进入主题 : 如何用 Zend_Application 实现应用程序的模块化及模板化设计。  

Zend Framework 在基于 MVC 结构之上,提供了一套完整的模块设计 (Modular Design) 方案,可以说 Zend Framework 中的 MVC 是建立在模块之下的,每个模块都可以拥有自己的完整的 MVC 结构。  

但是在 Zend Framework 中为不同模块设置不同模板,甚至为同一模块设置多个模板确不是那么容易的,需要一定的配置和技巧。  

首先,我们创建应用程序目录结构如下 :  

在 application 目录下我们设有 modules 及 templates 两个目录,其中各都有 admin 及 front 两个模块。modules 中的各个模块的 controllers 文件夹是存放所有控制器的地方,如 IndexController 等。templates 中的各个模块文件夹则存放所有的模板,如上图,模块 front 中存放了名为 default 和 oceanStyle 两种模板。  

我们将拓展资源放在 library/Kbs/Application/Resource/ 目录下 :  

再来是完整的配置文件 :  

; Application.ini  
 
[production]  
;=========== 库文件路径  
;includePaths.library                                           = APPLICATION_PATH "/../library/" 

 
;=========== 类自动加载的前缀  
autoloadernamespaces.0                                          = "Zend_" 
autoloadernamespaces.1                                          = "ZendX_" 
autoloadernamespaces.2                                          = "Kbs_"   
 
;=========== php ini 配置  
phpsettings.date.timezone                                       = "Asia/Shanghai" 

phpSettings.display_startup_errors                              = 0  
phpSettings.display_errors                                      = 0  
phpsettings.error_reporting                                     = 8191  
 
;=========== bootstrap 类的路径及类名  
bootstrap.path                                                  = APPLICATION_PATH "/Bootstrap.php" 

bootstrap.class                                                 = "Bootstrap" 
 
;=========== 自定义资源的路径及其前缀  
pluginPaths.Kbs_Application_Resource                            = APPLICATION_PATH "/../library/Kbs/Application/Resource/" 

 
;=========== front controller 配置  
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  
   
 
;=========== layout 布局,实际上我们交由 view 来配置  
resources.layout.layout                                         = "we use resources.view.params.module.layout instead" 

resources.layout.layoutPath                                     = "we use resources.view.params.module.layoutPath instead" 

 
;=========== view 配置  
resources.view.title                                            = "" 
resources.view.encoding                                         = "UTF-8" 
resources.view.helperPathPrefix                                 = "Kbs_View_Helper_" 

resources.view.helperPath                                       = "Kbs/View/Helper/" 

   
 
;=========== front 和 admin 模块的 view 参数,包括 scripts 文件路径及前缀,layout 路径及名称  
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/" 

   
 
;=========== view 的其它参数  
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.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.translate.registry_key                                = "Zend_Translate" 

resources.translate.adapter                                     = "array" 
resources.translate.options.scan                                = "directory" 
resources.translate.data.directory                              = APPLICATION_PATH "/languages/" 

resources.translate.data.fileExt                                = ".php" 
 
;=========== locale  
resources.locale                                                = true  
 
 
[testing : production]  
phpSettings.display_startup_errors                              = 1  
phpSettings.display_errors                                      = 1  
phpsettings.error_reporting                                     = 8191  
resources.db.params.username                                    = "xxx" 
resources.db.params.password                                    = "xxx" 
resources.db.params.dbname                                      = "xxx" 
 
 
[development : production]  
phpSettings.display_startup_errors                              = 1  
phpSettings.display_errors                                      = 1  
phpsettings.error_reporting                                     = 8191  
resources.db.params.username                                    = "xxx" 
resources.db.params.password                                    = "xxx" 
resources.db.params.dbname                                      = "xxx" 
 
   
 
在这里,testing 及 development 均继承自 production 环境。值得注意的是,phpsettings.* 是内置的 php 运行环境参数设定, 当然你也可以用 .htaccess 或者直接在 php.ini 中设定好。bootstrap.* 则是初始化应用程序所需的 bootstrap 类及其路径。而 resources.* 就是我们所说的资源。  

以上仅为个人的配置,不一定适合每个应用,具体还要按自己需要修改。  

接下来就是 index.php 入口 :  
// 项目根目录  
defined('PROJECT_ROOT')  
    || define('PROJECT_ROOT',  
              realpath(dirname(dirname(__FILE__))));  
   
// 定义到 application 的路径  
defined('APPLICATION_PATH')  
    || define('APPLICATION_PATH',  
              PROJECT_ROOT . '/application');  
   
// 定义开发环境  
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' 
)));  
   
// Zend_Application  
require_once 'Zend/Application.php';  
   
// Create application  
$application = new Zend_Application(  
    APPLICATION_ENV,  
    PROJECT_ROOT . '/library/Kbs/Config/Application.ini' 
);  
   
// 开发环境下打开自动加载警告  
if ('production' !== APPLICATION_ENV) {  
    $application->getAutoloader()->suppressNotFoundWarnings(false);  
}  
   
// 我们仅加载 frontController 资源  
$application->getBootstrap()->bootstrap('FrontController');  
$application->run();   
 
需要解释的是 APPLICATION_ENV 是预设的系统环境变量,它将用于 Application.ini 中区分应用程序运行环境,这里预设3个值:development, testing, production,分别表示开发环境,测试环境及实际运行环境。  

注意我们在最开始仅仅载入了 frontController 这个资源,这是为了将初始化资源降到最低限度。我们将把其它资源部分地交由 Kbs_Controller_Plugin_Common 插件来按需分配,而余下部分则在需要时再通过 Zend_Application_Bootstrap_Bootstrap::bootstrap($resource) 按需加载。  

我们使用 plugin resource 而不是使用在 bootstrap 中重载资源(e.g. Bootstrap::_initView)的方法来进行资源管理,这样的好处是我们的 Bootstrap 类将非常简洁 :  

// Kbs/Application/Bootstrap.php  
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap  
{  
    // 我们不需要在这里重载任何资源  
}   
 
现在我们需要让程序 frontController 知道模板 (template) 的位置,为此我们不得不使用动作插件 (action plugin),这个我们已经在前面 Application.ini 中定义好了 :  

// 自定义拓展插件,名为 common  
 
resources.FrontController.plugins.common        = "Kbs_Controller_Plugin_Common" 

// 自定义应用程序插件 Kbs_Controller_Plugin_Common 类  
require_once('Zend/Controller/Plugin/Abstract.php');  
   
class Kbs_Controller_Plugin_Common extends Zend_Controller_Plugin_Abstract  
{  
    // route 结束时  
    public function routeShutdown(Zend_Controller_Request_Abstract $request)  
    {  
        // 获取模块名,如 admin,front 等  
        $module = $request->getModuleName();  
   
        // bootstrap 类  
        $bootstrap = Zend_Controller_Front::getInstance()->getParam('bootstrap');  

   
        // 加载 view  
        $bootstrap->bootstrap('View');  
        $view = $bootstrap->getResource('View');  
        $moduleParams = $view->$module;  
   
        // 配置 view  
        $view->addBasePath($moduleParams['basePath'])  
             ->addHelperPath($moduleParams['helperPath'],  
                             $moduleParams['helperPathPrefix']);  
   
        // 加载 layout 并配置  
        $bootstrap->bootstrap('Layout');  
        $layout = $bootstrap->getResource('Layout');  
        $layout->setLayoutPath($moduleParams['layoutPath'])  
               ->setLayout($moduleParams['layout']);  
    }  
}   
 
Plugin 是我目前所能想到的最好的解决方案,因为我们将在 routeShutdown 路由结束时很方便的取得 module 模块名,从而根据预先在 Application.ini 里面设定的配置信息,来获取相应的模板信息。  

资源 Kbs_Application_Resource_View 定义如下 :  

// 拓展资源 (plugin resource) view  
class Kbs_Application_Resource_View extends Zend_Application_Resource_ResourceAbstract  

{  
    protected $_view;  
   
    // 初始化 view  
    public function init()  
    {  
        if (null === $this->_view) {  
            // 获取从 Application.ini中 的配置  
            $options = $this->getOptions();  
            $view = new Zend_View($options);  
            if (!emptyempty($options['params'])) {  
                foreach ($options['params'] as $key => $value) {  
                    $view->$key = $value;  
                }  
            }  
   
            // viewRenderer 动作助手  
            $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(  

                'ViewRenderer' 
            );  
   
            // 保存配置好的视图对象  
            $viewRenderer->setView($view);  
            $this->_view = $view;  
        }          
        return $this->_view;  
    }  
}   
 
到此,我们已经基本上完成了所有工作。接下来就是完成 layout 及 scripts 了,当然这不一定是程序员做的事了,大可交给专业设计人员。  

上例中,只要把  

resources.view.params.front.basePath            = APPLICATION_PATH "/templates/front/default/" 

resources.view.params.front.layoutPath          = APPLICATION_PATH "/templates/front/default/layout" 

换成  

resources.view.params.front.basePath            = APPLICATION_PATH "/templates/front/oceanStyle/" 

resources.view.params.front.layoutPath          = APPLICATION_PATH "/templates/front/oceanStyle/layout" 

就能够把模板从 default 切换成 oceanStyle 。  

以上便是如何用 Zend_Application 配置及组装应用程序,并完成多模块及多模板的基本过程。这里我忽略了 Zend/Application/Module 及其相关内容,因为据内部消息称,在版本1.9及2.0之前,这部分内容还会有较大修正和改善,所以在这里就不详细说明了 .

抱歉!评论已关闭.