Bookmark and Share

Lee's 程序人生

HTML CSS Javascript XML AJAX ATLAS C# C++ 数据结构 软件工程 设计模式 asp.net Java 数字图象处理 Sql 数据库
  博客园  :: 首页  :: 新随笔  :: 联系 :: 管理

在开始之前,我有必要介绍一下 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_once '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 (!empty($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之前,这部分内容还会有较大修正和改善,所以在这里就不详细说明了,详情请继续关注 http://kimbs.info/ 。

 

转自:http://kbs.kimbs.cn/blog/list/post/8/title/building-multi-modules-and-multi-templates-application-using-Zend_Application 

我要啦免费统计