Zend_Controller体系具有可扩展性,可以通过继承已有的类或者自己写个新的类来实现Zend_Controller_Router_Interface或Zend_Controller_Dispatcher_Interface接口。
打算实现一个新的router或dispatcher的原因可能是:
已有的URI routing系统不合适,如把用Zend Framework的站点集成到一个已经存在的有自己的定向规则的站点。
你想用MVC模式来开发其它形式的PHP程序,如命令行形式的。那么你就需要自己定制一个router来处理命令行的参数了。
Zend_Controller_Dispatcher提供的机制不适用于你的程序。默认的情况是controller是类而action是类中的方法。但是也有其它情况如controller是一个目录,而action是其中的文件。这样你也要自己写。
你想为你的控制器提供更多功能。例如Zend_Controller_Action默认没有和Zend_View集成。当然你也可以通过继承来实现,这样可以不用改变Zend_Controller_Router或者Zend_Controller_Dispatcher。
P当你覆写系统的重要部分时要非常小心,特别是dispatcher。Zend_Controller的优点之一是它对于构建各种应用程序规定了一些固定的规则。如果你改写太多,有可能就失去这个优点。不过,现实当中有各种不同的需要,不可能只采用一种解决方案,所以在需要的时候可以考虑自己来改写。
当继承任何Zend_Controller的类时,你最好遵循以下命名和文件存储规则。这样做可以让另一个熟悉Zend Framework的程序员很容易地理解你的项目。
Zend_Controller的各个类在library目录下是这样分布的:
/library /Zend /Controller Action.php Dispatcher.php Router.php
当继承Zend_Controller类时,建议新的类放在带有你的前缀的和以上结构完全相同的目录下。这样别人在查看你的代码时,可以很容易找到相应的代码。
例如,Widget公司的一个项目,只实现了一个自定义的router,看起来可能是这样的:
/library /Zend /Widget /Controller Router.php README.txt
注意在这个例子中Widget/Controller/映射到Zend/Controller/。另外,这个例子提供了一个Widget_Controller_Router,这可能是Zend_Controller_Router的子类,也可以是替代(通过实现Zend_Controller_Router_Interface接口)。
同时,注意上例中在Widget/Controller/下有个README.txt文件。我们强烈建议你为客户提供各种测试和文档,同时也建议你放置一个简单的README.txt文件在适当的目录,用来简要说明代码的修正过程和它们是如何工作的。
Zend_Controller_Router_Interface接口只定义了一个方法:
<?php /** * @param Zend_Controller_Dispatcher_Interface * @throws Zend_Controller_Router_Exception * @return Zend_Controller_Dispatcher_Token|boolean */ public function route(Zend_Controller_Dispatcher_Interface $dispatcher); ?>
Routing过程只发生一次:当请求被系统接收时。router的目的在于生成一个描述controller和action的Zend_Controller_Dispatch_Token。Token对象被传给dispatcher。如果无法将一个路径分配到一个dispatch token(无效的访问路径),则会返回false。
一些router需要处理动态的元素,需要判断生成的dispatch token在return之前是否是可分配的。 出于这个原因,router把对象当成它的route()方法的唯一的参数 。 dispatcher则提供了一个 isDispatchable()方法来测试是否是可分配的。
Zend_Controller_Front会先调用router,接收第一个dispatch token,然后传递给dispatcher。dispatcher将分配action(实例化一个controller,调用它的action)并返回一个FALSE或者另一个 dispatch token。
Zend_Controller_Front重复调用dispatcher直到不返回dispatch token为止。这就是所谓的dispatch循环,它让所有的action依次处理,直到处理完毕。
Zend_Controller_Dispatcher_Interface接口定义了两个方法:
<?php /** * @param Zend_Controller_Dispatcher_Token $route * @return boolean */ public function isDispatchable(Zend_Controller_Dispatcher_Token $route); ?>
isDispatchable()方法检查一个 dispatch token 是否是可分配的。如果可以,返回TRUE,否则返回FALSE。默认地对于Zend_Controller_Dispatcher,可分配的意思就是说controller文件存在,文件内也存在相应的类,并且类中存在相应的action方法,
<?php /** * @param Zend_Controller_Dispatcher_Token $route * @return Zend_Controller_Dispatcher_Token|boolean */ public function dispatch(Zend_Controller_Dispatcher_Token $route); ?>
dispatch()方法就是action执行的地方,必须执行controller的action。它可以返回一个dispatch token或者返回一个FALSE,表示工作已经全部完成。