The Zend Framework MVC Architecture
一、概述:
In this chapter, we will cover the following topics:
1. Zend framework MVC overview
2. The Front Controller
3. The router
4. The dispatcher
5. The Request object
6. The Response object
二、详细介绍:
1、Zend Framework MVC overview1)了解请求(REQUEST)的产生与处理过程
一个请求被产生,一个相应的响应就被返回。上面这个流程就是发生在前端控制器(Front Controller)内部,这个过程常常是在前端控制器(Front Controller)调用dispatch()方法是触发的,这个过程可以分解为下列12个小步骤:
1. 一个请求Request的产生(创建了一个Request Object对象);
2. 路由事件routeStartup触发;
3. 路由器Router开始处理这个请求,从中获取请求信息;
4. 路由时间routeShutdown触发,路由过程结束;
5. 派遣事件dispatchLoopStartup被触发;
//派遣循环开始
6. 派遣preDispatch事件触发;
7. 派遣过程中调用动作控制器(Action Controller);
8. 动作控制器(Action Controller)将处理完成信息直接写入响应对象(Response Object);
9.派遣postDispatch时间被触发;
//派遣循环结束
10. 检测派遣标志,即检查是否还有动作没有完成,如果有再次进入派遣循环(第6步);
11. 派遣事件dispatchLoopShutdown被触发;
12. 产生的响应Response被返回。
2、 The Front Controller——–前端控制器1)介绍:前端控制器是MVC组建中的苦力,因为它要实例化对象、触发事件、建立默认的行为等,它的主要目的是处理所有进入应用的请求。前端 控制器的设计模式被应用于不同的MVC框架中,我们在Zend Framework中指代的前端控制器(Front Controller)实际上是指Zend_Controller_Front类,因为该类实现了前端控制器的模式;另一定注意的是,前端控制器设计是单 例模式(Singleton),这也就意味着它实现了单例设计模式,也就是仅仅只能有一个实例化的前端控制器,即我们不能直接实例化Front Controller,而是拿取一个:
2)默认情况下,Front Controller负责实例化很多对象,并且是针对WEB应用的,即这些对象都是默认指定在HTTP环境下被实例化出来的,例如下表:
这个表显示出了创建对象的类型,抽象类abstract class是被用于实体类concrete class继承,实体类是被前端控制器调用并实例化使用的!!插件经纪人有些特别因为它与运行环境无关,即在HTTP环境下和在CLI环境下是一样的。默 认情况下前端控制器有2个插件可用:a.Zend_Controller_Plugin_ErrorHandler;
b.Zend_Controller_Plugin_ActionStack.错误插件ErrorHandler默认是被注册的,可以通过前端控制器设置其参数noErrorHandler来取消:
Stack index是用于插件的调用时机,它越大这个插件就将在越后面执行!
默认情况下,前端控制器Front Controller也利用动作助手经济人(Action Helper Broker)注册了ViewRenderer Action Helper,我们可以通过noViewRenderer参数来禁止它:
3)使用前端控制器
[A]调用参数
调用参数可以被用于存储数据在前端控制器中,然后被传递到Action Controller、Router、Dispatcher中去了,调用参数可以很好的实现将共同的对象或者变量传递到MVC组件中去:
前端控制器有如下处理调用参数的方法:
setParam(String $name, Mixed $value): 设置调用参数setParams(Array $params): 设置多个调用参数getParam(String $name): 获取一个调用参数getParams(): 获取所有的调用参数clearParams(String|Array|Null $name): 清除调用参数[B]可选项
像调用参数样,可选项也可以影响前端控制器的默认行为,如下列可选项:
throwExceptions(Boolean $flag): 在派遣循环过程中是否抛出异常,或者捕获到Response对象中setBaseUrl(String $base): 设置请求的基本路径,不要用全部Url。returnResponse(Boolean $flag): 默认情况下,一旦派遣循环结束,前端控制器将渲染Response对象;若设为true,dispatch()方法将返回Response对象,而不是渲染它;setDefaultControllerName(String $controller): 设置默认的控制器名;默认情况下Index是默认的控制器名,我们可以通过该方法改变它;setDefaultAction(String $action): 设置默认的动作名;默认情况下index是默认动作名称,我们可以通过该方法来改变它; setDefaultModule(String $module): 设置默认的模块名;默认情况下default是默认的模块名;setModuleControllerDirectoryName(String $name);设置控制器路径名;默认下是controllers;
4)Modules, controllers, and actions
前端控制器一个主要的部分就是负责modules、controllers、actions的配置,为了工作正常,前端控制器必须知道如何组织我们的控制器和将它们放在哪里;
默认情况下,我们利用Zend_Tool创建的目录结构大致如下:
上面这种目录结构不利于管理,因为所有的控制器就在application/controllers一个控制器文件夹下,这样不方便管理,为了达到这点,我们引入modules的概念,这样可以将controllers,models,views进入一个管理单元!!
所有我们引申出来了下面两种目录结构:
(图1) (图2)
正如所见一样,图1和图2的布局基本一样,但图2的布局使用了module文件夹,这样做是为了告诉前端控制器这个是我们的modules文件路 径,同时我们也不必一定要采用上面的这两种模式,它们都可以自定义,然而99%的我们都会采用上面两种情况,而我最喜欢的还是图2中的路径布局。
★★
如果我们采用图一中的布局方式来使它能够使用前端控制器Front Controller,我们可以使用Front Controller的setControllerDirectory()或者是addControllerDirectory()方法,因此当我们应用 第一种布局方式(图1所示)时我们可以这样做:
//或者
$front->addControllerDirectory(‘/path/application/product’,'product’);
setControllerDirectory和addControllerDirectory这两种方法真正区别在于setControllerDirectory()接受一个module数组并我们要指定默认的模块名,而addControllerDirectory()一次仅仅只接受一个模块。不管怎么样,我们一次必须要一次指定一个默认的模块名,无论我们是采用setControllerDirectory()还是addControllerDirecoty()方法!!
★★★★★
我们第二中布局(图2所示)只有一点点不同,所有的modules都被放入一个叫做modules的路径下,我们可以采用addModuleDirectory()方法来让这种布局使用Front Controller控制器,因此我当我采用第二种布局方式(图2所示)时我们可以这样做:
这种方法是最简单的增加多模块的方法,同时也意味着你不需要从新定义你新添加的modules。
★★★★★
当我们使用了模块后,我们在非默认模块的的动作控制 器中需要遵循一个防止命名控制冲突的不同的命名协议。因此,在我们的例子中,所有在product模块中的动作控制器Action Controllers都需要增加一个Product的命名空间,例如,Product模块中的detail的动作控制器应当命名成 Product_DetailsController,但对于默认模块(default(global) modules)中的动作控制器则不需要,例如,default模块中的detail的动作控制器应该命名成DetailsController,然而, 我们通过设置prefixDefaultModule变量能够改变这种默认的行为:
通过这样,我们的default模块中的所有动作控制器(如detail动作控制器)都应该加上模块前缀,即Default_(Default_DetailsController);
5)自定义MVC组件
大多数情况下,默认的MVC组件(指Requset、Response、Router、Dispatcher等)基本上可以很好的服务于我们的 应用程序,但是如果我们真的需要自定义其中的一个或者几个话,前端控制器(Front Controller)提供给我们一些很简单的方法就可以定义出我们自定义的MVC组件,例如:
在这里,我们用我们自定义的MVC组件来代替原有ZF默认的MVC组件。要做到这点,我们首先要通过继承MVC组件的抽象类或者是MVC组件的子类 (这个在我们上面的一个表中可以很清晰的看到)来定义我们自己的MVC组件,这样再通过上面的代码就可以设置好我们自己的MVC组件。在大多数的案例中, 你可能只需要自定义其中一两个MVC组件就行了,例如有可能用到自定义路由!
6)小结
前端控制器用一个集中的地方提供给我们控制我们的MVC组件,回顾下前端控制器的主要方法和函数,我们所提到的这些方法和函数是前端控制器 主要的一些方法和函数,在这里并没有列出所有的方法来,因为那样和手册上基本又重复了一遍,所有没有必要。我建议你可以看下手册熟悉下前端控制器的基本方 法,如果你想了解ZF的前端控制器的每一个过程,你可以看看zf原代码。
3、Router———–路由器
1)概述:路由器主要负责解析一个请求并且决定什么module、controller、action被请求;它同时也定义了一种方法来实现用户自定义路由,这也使得它成为最有用的一个MVC组件;
2)设计:作为一个应用中的路由组件是很专业的,理所当然的路由组件是抽象的,这样允许作为开发者的我们很容易的设计出我们自定义的路由协议。然而,默 认的路由组件其实已经服务得我们很好了。记住,如果我们需要一个非标准的路由协议时候,我们就可以自定义一个自己的路由协议,而不用采用默认的路由协议。
事实上,路由组件有两个部分:路由器(或者称路由对象《the router》)和路由协议 (或者称 路由过程《the route》)。路由器主要负责管理和运行路由链,路由过程事实上主要负责匹配我们预先定义好的路由协议,意思就是我们只有一个路由器,但我们可以有许多 路由协议。(ps:不知道这样理解是不是有问题,原文是这样的:The router actually has two parts, the router and the route. The router is responsible for managing and running the route chain, and a route is responsible for actually matching the request against the predefined rule of the route. This means that we have one router to many routes.看到后面就会清楚一点的。)
路由组件基于两个接口:Zend_Controller_Router_Interface和 Zend_Controller_Router_Route_Interface;同样路由组件的两个抽象 类:Zend_Controller_Router_Abstact和Zend_Controller_Router_Route_Abstract分别 是实现了上面对应的两个接口,同时这两个抽象类也就提供给我们一些基本的函数来操作路由组件。如果我们需要创建我们自定义的路由器(the router)或者路由协议(the route),我们就可以分别继承上面的两个抽象类。路由的过程发生派遣过程的最开始,并且路由解析仅仅发生一次。路由协议在任何控制器动作 (controller action)被派遣之前被解析,一旦路由协议被解析后,路由器将会把解析出得到的信息传递给请求对象(Request object),这些信息包括moduel、controller、action、用户params等。然后派遣器(Dispatcher)就会按照这些 信息派遣正确的控制器动作。路由器也有两个前端控制器插件钩子,就是在我们之前提到过的routeStartup和routeShutdown,他们在路由解析前后分别被调用。
3)默认情况下:
默认条件下,我们的路由器是使用Zend_Controller_Router_Rewrite,是基于HTTP路由的,意味着它期望一个请求是HTTP请求并且请求对象是使用Zend_Controller_Request_Http(或者是继承它的对象),这两个默认类,在我们之前的那个表中都有见到过。默认条件下,路由协议是使用Zend_Controller_Router_Route_Module类。
4)使用路由:使用路由既可以让之很复杂,同时也能让它很简单,这是归于你的应用。然而使用一个路由是很简单的,你可以创建一个路由器让它管你的路由协议,然后你可以添加你的路由协议给路由器,这样就OK了!
不同的路由协议如下所示:
Zend_Controller_Router_Route
Zend_Controller_Router_Route_Module (Default route for module functionality)
Zend_Controller_Router_Route_Static (StaticRoute is used for managing static URIs.It’s a lot faster compared to the standard Route implementation.)
Zend_Controller_Router_Route_Regex (Regex Route)
Zend_Controller_Router_Route_Hostname (Hostname Route)
Zend_Controller_Router_Route_Chain (Chain route is used for managing route chaining)
其中我们使用到的最基本的路由协议类Zend_Controller_Router_Route,它提供给我们少量的控制。如果想要更精密的控制,我们可 以采用正则路由协议:Zend_Controller_Router_Route_Regex,它提供给我们可以通过PHP的正则来使用,很强大。其他的 几个路由协议类分别有不同的专业化。到此为止,首先让我们来看看路由器是如何让路由协议与之一起工作的。
在我们添加任何路由协议之前我们必须要得到一个路由器(the router)实例,我们可以通过自己创建一个新的路由器或者是通过前端控制器(Front Controller)来得到一个默认的路由器:
//我们实例化一个默认的路由器
$router = new Zend_Controller_Router_Rewrite();
//或者我们可以通过前端控制器的getRouter()方法得到一个默认的路由器实例
$router=$front->getRouter()
一旦我们有了路由器实例,我们就能通过它来添加我们自定义的一些路由协议:
$router->addRoute(‘myRoute’,$route);
$router->addRoute(‘myRoute1′,$route);
除此之外,我们还可以通过Zend_Config_Ini和Zend_Config_Xml对象来添加我们的路由协议:
$cOnfig= new Zend_Config_Ini(‘/path/to/config.ini’,'production’);
$router->addConfig($config,’routes’);
其实路由器也提供给我们不同的方法来得到和设置包含在它内部的信息,一些重要的方法如下:
addDefaultRoutes()andremoveDefaultRoutes()//添加或者移除默认的路由协议。assemble()//基于给定的路由协议确定URI,这个方法通过 Url视图助手(View Helper)使用提供它的链接地址。getCurrentRoute()andgetCurrentRouteName() getRoute() getRoutes() hasRoute() removeRoute();
5)路由协议详解:
【A】Zend_Controller_Router_Route
Zend_Controlloer_Router_Route路由协议提供了我们很强的功能,同时也提供了一些简单的操作,为了能够使用该路由协议,我们必须先实例化它,然后用路由器加载它:
//创建一个路由器实例
$router = new Zend_Controller_Router_Rewrite();
//创建一个路由协议实例
$route = new Zend_Controller_Router_Route(
‘product/:ident’,
array(
‘controller’=>’products’,
‘action’=>’view’
)
);
//使用路由器装载路由协议
$router->addRoute(‘product’,$route);
在 这个例子中,我们试图匹配Url指定到一个单一的产品,就像http://domain.com/product/choclolat-bar。为了实现 这点,我们在路由协议中传递了2个变量到路由协议Zend_Controller_Router_Route的构造其中。第一个变量 (’product/:indent’)就是匹配的路径,第二个变量(array变量)是路由到的动作控制器;其实路由协议也提供了第三个变量用于正则匹 配,我们将在第二个路由协议中见到;
路径使用一个特别的标识来告诉路由协议如何匹配到路径中的每一个段,这个标识有有两种,可以帮助我们创建我们的路由协议,如下所示:
a):
b)*
冒号(:) 指定了一个段,这个段包含一个变量用于传递到我们动作控制器中的变量,我们要设置好事先的变量名,比如在上面我们的变量名就是’ident’, 因此,倘若我们访问http://domian.com/product/chocoloate-bar将会创建一个变量名为ident并且其值是 ‘chocoloate-bar’的变量,我们然后就可以在我们的动作控制器ProductsController/viewAction下获取到它的 值:$this->_getParam(‘ident’);同时我们还可以在路由协议中设置ident的默认的值,即可以在路由协议类的第二个数组 变量中增加一个元素(比如我们在这定义了ident默认值为unknown):
$route = new Zend_Controller_Router_Route(
‘product/:ident’,
array(
‘controller’=>’products’,
‘action’=>’view’,
‘ident’=>’unknown’
)
);
星 号(*)被用做一个通配符,意思就是在Url中它后面的所有段都将作为一个通配数据被存储。例如,如果我们有路径’path/product /:ident/*’(就是路由协议中设置的第一个变量),并且我们访问的Url为http://domain.com/product /chocolate-bar/test/value1/another/value2,那么所有的在’chocolate-bar’后面的段都将被做成 变量名/值对,因此这样会给我们下面的结果:
ident = chocolate-bar
test = value1
another = value2
这 种行为也就是我们平常默认使用的路由协议的行为,记住变量名/值要成对出现,否则像/test/value1/这样的将不会这种另一个变量,我们有静态的 路由协议部分,这些部分简单地被匹配来满足我们的路由协议,在我们的例子中,静态部分就是product;就像你现在看到的那样,我们的 Router_Route路由协议提供给我们极大的灵活性来控制我们的路由;然而,这就就很像正则匹配了,正则匹配使我们能够提供而外的约束力来限制我们 的路由(这里的正则匹配是使用PHP的preg引擎)。在我们的产品实例中,我们得到了用户想观看的’ident’的产品特性,即我们通过用户传递过来的 参数,通过数据库的搜索得到正确的产品信息。然而,如果我们得到的需求是系统仅仅只能接受产品ID号作为我们的产品的标识,那么我们可以使用路由协议来实 现这点:
考虑下面两中路由:
//创建路由器
$router = new Zend_Controller_Router_Rewrite();
//创建路由协议
$route = new Zend_Controller_Router_Route(
‘product/:ident’,
array(
‘controller’=>’products’,
‘action’=>’view’
),
array(
//match only alpha, numbers and _-
‘ident’=>’[a-zA-Z-_0-9]+’
)
);
//让路由器装载路由协议
$router->addRoute(‘productident’,$route);
//再定义一个路由协议
$route = new Zend_Controller_Router_Route(
‘product/:id’,
array(
‘controller’=>’products’,
‘action’=>’view’
),
array(
//match only digits
‘id’=>’d+’
)
);
//让我们的路由器再装载一个路由协议
$router->addRoute(‘productid’,$route);
为 了达到我们的需求,我们创建了2种路由协议。第一种路由协议对Zend_Controller_Router_Route的构造函数添加了第三个变量– 一个正则表达式的变量ident,这个需求就是用户提供的ident必须是字母、数字和-以及下划线组成。我们的第二个路由协议试图匹配一个产品的ID 数,我们利用d+正则来匹配数字。通过我们增加的路由协议,如果我们现在浏览http://domain.com/product/12,这个id变量 就会被设置,如果我们浏览http://domain.com/product/chocoloate-bar,那么这个ident变量就会被设置,然后 我们可以在同一个动作控制中接受不同的参数来显示同样的信息!
【B】Zend_Controller_Router_Route_Static
标准路由协议,如果我们不需要任何匹配的变量,我们可以通过使用标准路由协议来实现。这个路由协议匹配到一个静态URL并且创建一个静态的路由协议,我们仅仅需要像之前那样实例化它并把它加载到路由器中就行了:
$route = new Zend_Controller_Router_Route_Static(
‘products/rss’,
array(
‘controller’=>’feed’,
‘action’=>’rss’
)
);
$router->addRoute(‘rss’,$route);
就像你看到那样,Router_Route_Static路由协议就是Router_Route一个非常简单的版本,在我们的例子中,http://domain.com/products/rss就会去访问FeedController和rss控制器;
【C】Zend_Controller_Router_Route_Regex
正则路由协议。到目前为止,我们之前的路由协议(Router_Route、Router_Route_Static)都很好的完成了基本的路由操作,我 们常用的也是他们,然而它们会有一些限制,这就是我们为什么要引进正则路由(Router_Route_Regex)的原因。正则路由给予我们preg正 则的全部力量,但同时也使得我们的路由协议变得更加复杂了一些。即使是他们有点复杂,我还是希望你能好好掌握它,因为它比标准路由协议 (Router_Route)要快一点点。
一开始,我们先对之前的产品案例改用使用正则路由:
$route=newZend_Controller_Router_Route_Regex(
‘product/([a-zA-Z-_0-9]+)’,
array(
‘controller’=>’products’,
‘action’=>’view’
)
);
$router->addRoute(‘product’,$route);
你 可以看到,我们现在移动我们的正则到我们的path(构造函数的第一个参数)中来了,就像之前的那样,这个正则路由协议现在应该是匹配是一个数字、字母、 -和_组成的ident变量的字符提供给我们,但是,你一定会问,ident变量在哪呢?好,如果你使用了这个正则路由协议,我们可以通过变量 1(one)来获取其值,即可以在控制器里用:$this->_getParam(1)来获取,其实这里如果看过正则的都知道这就是反向引用中 的1。然而,你一定会想为什么要定义的这么的垃圾,我们不能够记住或者弄清每一个数字代表的是什么变量(其实我刚开始看的时候也是一样的感受)。为了改 变这点,正则路由协议的构造函数提供了第3个参数来完成数字到变量名的映射:
$route=newZend_Controller_Router_Route_Regex(
‘product/([a-zA-Z-_0-9]+)’,
array(
‘controller’=>’products’,
‘action’=>’view’
),
array(
//完成数字到字符变量的映射
1=>’ident’
)
);
$router->addRoute(‘product’,$route);
这样,我们就简单的将变量1映射到了ident变量名,这样就设置了ident变量,同时你也可以在控制器里面获取到它的值。
另外,东西总是就两面性的,连正则路由也不例外。正则路由的一个负面作用就是表现在其他zf组件如url视图助手 ($this->baseUrl())不能够解析正则路由协议成URL,围绕这点,我们可以为我们的路由协议提供一个反向重写,就像 sprintf()工作的那样:
为了达到重写的目的,我们将正则路由协议(Router_Route_Regex)的构造函数中添加第四个变量:
$route=newZend_Controller_Router_Route_Regex(
‘product/([a-zA-Z]+)/([a-zA-Z-_0-9]+)’,
array(
‘controller’=>’products’,
‘action’=>’view’
),
array(
1=>’category’
2=>’ident’
),
//重写路由协议
‘product/%s/%s’
);
$router->addRoute(‘product’,$route);
那 现在我们已经增加了一个反向重写(reverse rewrite),我们的路由协议能够很容易的被连接到。如果你看到上面的路由协议,我们实际上可以看作是一类参数的捕获。我们然后提供了反向重写 product/%s%s,因此路由协议能够为我们提供变量。记住,这里反向重写可以先熟悉下sprintf()这个函数。
由于我们感觉这个过程相当复杂,然我们再用一个实例来说明。
设 想一下,假设我们一直在忙于我们老商城应用的重构而采用了zf框架。我们已经决定我们想让我们的产品的URl有一个好的印象针对于搜索引擎。然而由于我们 的产品已经开发完成了很久了,并且里面的url已经很多的被搜索引擎给收录了,我们不想失去这些链接,为了完成这些,我们正好可以使用正则路由的力量。
我们老的URL格式:
http://storefront/products.php/category/{categoryID}/product/{productID}
我们新的URL的格式:
http://storefront/product/{categoryName}/{productID}-{productIdent}.html
因此,一开始,我们就想重定义我们老的请求URL到我们新的请求,我们可以通过这样做:
//我们老的url匹配的正则路由协议
$route=newZend_Controller_Router_Route_Regex(
‘products.php/category/(d+)/product/(d+)’,
array(
‘controller’=>’products’,
‘action’=>’old’
),
array(
1=>’categoryID’,
2=>’productID’
)
);
在 这里,我们将我们老的url中的category和product值分别得到后分别映射到了cateforyID和productID两个变量,并且将这 两个变量传递到我们的ProductsController/oldAction中去,因此,我们可以在我们的old动作中再次重定向到我们新的URl 中:
publicfunctionoldAction(){
$catID=$this->_getParam(‘categoryID’);
$productID=$this->_getParam(‘productID’);
//model finds the product ident and category names
//….
$ident=’coolproduct’;
$catName=’coolstuff’;
//重定向到新的url
$this->_redirect(‘/product/’.$catName.’/’.$productID.’-’.$ident.’.html’,
array(‘code’=>301)
);
}
这样我们old动作控制器拿取匹配的变量从路由协议中并且使用它们重定向到一个使用一个301的新的url中去,记住,我们不应当直接将我们获取到的变量直接应用到我们的一个重定向请求中,因为这样会牵扯到安全问题。
那现在我们创建一个新的路由协议来接收我们老的URls映射过来的URLs:
//新url的正则路由协议
$route=newZend_Controller_Router_Route_Regex(
‘product/([a-zA-Z-_0-9]+)/(d+)-([a-zA-Z-_0-9]+).html’,
array(
‘controller’=>’products’,
‘action’=>’view’
),
array(
1=>’categoryIdent’,
2=>’productID’,
3=>’productIdent’
),
‘product/%s/%d-%s.html’
);
这 个路由协议匹配我们新的URLs,这个正则包含3个捕获组,分别是产品类名(categoryIdent),产品ID(productID),以及产品特 性(ident)。这个’product/%s/%d-%s.html’就是匹配原来的{categoryName} /{productID}-{productIdent}.html这种格式。最后,建议好好玩玩这个正则路由协议,我可以保证你以后会用得到的。
【D】Zend_Controller_Router_Route_Hostname
主机域名路由协议,看名字就知道他是关于处理域名的路由协议。一个常见使用就是一个域名下有按用户的子域名,如,如果我们有一个公共的外部站点 www.domain.com,现在我们的注册用户有一个帐号url像ues1.domain.com,那么我们就可以使用域名路由协议来重写这个请求:
$route=newZend_Controller_Router_Route_Hostname(
‘:username.domain.com’,
array(
‘controller’=>’account’,
‘action’=>’index’
),
array(
//Match subdomain excluding www.
‘username’=>’(?!.*www)[a-zA-Z-_0-9]+’
)
);
$router->addRoute(‘account’,$route);
正如你所见,域名路由协议(Router_Route_Hostname)很像基本路由协议(Router_Route),我们能够得到变量,设置默认值,同时还能通过正则匹配,在这里的正则匹配我们过掉了www。
6)在配置文件中配置Zend_Config
当我们有许多路由协议的时候,管理他们就开始变得很棘手了,这样我们就可以通过路由器来调用配置文件。
[production]
routes.rss.type=”Zend_Controller_Router_Route_Static”
routes.rss.route=”products/rss”
routes.rss.defaults.cOntroller=feed
routes.rss.defaults.action=rss
routes.oldproducts.type=”Zend_Controller_Router_Route_Regex”
routes.oldproducts.route=”products.php/category/(d+)/product/(d+)”
routes.oldproducts.defaults.cOntroller=products
routes.oldproducts.defaults.action=old
routes.oldproducts.map.categoryID=1
routes.oldproducts.map.productID=2
routes.product.type=”Zend_Controller_Router_Route_Regex”
routes.product.route=”product/([a-zA-Z-_0-9]+)/(d+)-([a-zA-Z-_0-9]+).html”
routes.product.defaults.cOntroller=products
routes.product.defaults.action=view
routes.product.map.categoryIdent=1
routes.product.map.productID=2
routes.product.map.productIdent=3
routes.product.reverse=”product/%s/%d-%s.html”
routes.user.route=”user/profile/:username/*”
routes.user.defaults.cOntroller=user
routes.user.defaults.action=profile
routes.user.defaults.username=”Unknown”
routes.user.reqs.username=”([a-zA-Z-_0-9]+)”
一旦我们创建了一个ini文件,我们就能把它加载到路由器中:
$cOnfig=newZend_Config_Ini(‘config.ini’,'production’);
$router=newZend_Controller_Router_Rewrite();
$router->addConfig($config,’routes’);
7)总结
路由器属于ZF mvc组件中很重要的一个,我们上面描述的这些路由是经常可以用到的。可能在一开始的时候就去用router会感觉不适应,你可以先熟悉了解它,但我希望 你还是对这个有个比较详细的了解,再次建议,你应该好好的用一下上面的路由,如果你想掌握它的话!!
4、Dispatch—————-派遣器
1)概述:派遣器主要负责我们实际调用动作控制器,事实上,派遣器是一个MCV的内部组件,并且Front Controller和它交互最密切!
2)设计:派遣器主要是负责派遣正确的动作控制器中的动作方法,意味着它必须加载所有的控制器类,并且实例化他们,并且调用其中的 Action。派遣器把持着所有的MVC组建的命名的规则的设置,这些设置包括默认的module,controller,action 命名。派遣器像其他MVC组件样,同样提供了一个接口和抽象类供我们创建我们自己的或者继承父类的派遣 器:a.Zend_Controller_Dispatcher_Interface b.Zend_Controller_Dispatcher_Abstract.
3)请求被派遣的过程:
请求派遣过程就是派遣器Dispatcher从请求对象 Request object中提取出Module,Controller,Action来,并且调用其中的Action Controller;该过程牵扯到了3个组件:Front Controller,Dispatcher,Request object;派遣的过程是发生在派遣循环中;该循环大体过程是:
a.前端控制器开始派遣循环
b.前端控制器调用派遣器
c.派遣器获取Request object请求对象,并分析它
d.派遣器从请求对象中找到对应的Action Controller动作控制器名
e.派遣器尝试加载该动作控制器类
f.动作控制器类加载成功,派遣器实例化动作控制器类
g.派遣器器从请求对象中找到对应的Action动作名
h.派遣器将派遣标志设为true,标志着派遣完成
i.派遣器开始派遣动作控制器类中的Action方法
j.派遣动作完成,派遣器检测请求对象Request object派遣完成标识是否为false,如果是false则表示还有派遣没有完成,派遣器就再次进入派遣循环过程中;
派遣标识案例说明:
//_forward()方法使用
class IndexController extends Zend_Controller_Action{
public function indexAction(){
$this->_forward(‘index’,'index’,'product’);
}
}
More body
’,'test’);More body
’More body
’,'test’);append to test segment
’,'test’);Before footer
’,'footer’,true);More body
append to test segment
’,Before footer
’,