我自己已经解决了。
我是愚蠢的。在 routeShutdown 我们不知道它是否会是一个 404 页面类型错误,直到我们尝试调度它。
所以我们能做的就是
- 测试响应中的一般异常
- 询问调度员该路线是否可能是可调度的。
所以插件无法真正确定是否存在“路由错误” - 所以它必须询问“isRouteShutdownToBeSkipped()”:
<?php
class MyPlugin extends Zend_Controller_Plugin_Abstract
{
public function routeShutdown( Zend_Controller_Request_Abstract $zfRequestObj )
{
if ( $this->isRouteShutdownToBeSkipped( $zfRequestObj ) )
{
//do not do any intensive page start up stuff
return;
}
return $this->doRouteShutdownProcesses( $zfRequestObj );
}
//...
然后 isRouteShutdownToBeSkipped() 方法测试
- 一般例外,或
- 不可调度的控制器
- 不存在的操作方法。(我避免在我的项目中使用魔法,所以我知道如果方法没有声明,那么它就不会起作用。)
所以:
<?php
class MyPlugin extends Zend_Controller_Plugin_Abstract
{
//...
protected function isRouteShutdownToBeSkipped( Zend_Controller_Request_Abstract $zfRequestObj )
{
if ( $this->getResponse()->isException() )
{
//Skip cos there was an exception already.
return TRUE;
}
if (!( $this->isDispatchable( $zfRequestObj ) ))
{
//Skip cos route is not dispatchable (i.e no valid controller found).
return TRUE;
}
if (!( $this->actionMethodExists( $zfRequestObj ) ))
{
//There is no action method on the controller class that
//resembles the requested action.
return TRUE;
}
//else else give it a go
return FALSE;
}
//...
我的isDispatchable()
方法只是委托给调度程序:
<?php
class MyPlugin extends Zend_Controller_Plugin_Abstract
{
//...
protected function isDispatchable( Zend_Controller_Request_Abstract $zfRequestObj )
{
return Zend_Controller_Front::getInstance()
->getDispatcher()
->isDispatchable( $zfRequestObj );
}
...
我的actionMethodExists()
方法有点复杂。调度程序的接口有点误导(getControllerClass()
实际上并没有返回类名),所以我们必须跳过一些箍来获取实际的控制器类名,然后及时加载类以调用 PHP 的内置method_exists()
函数:
<?php
class MyPlugin extends Zend_Controller_Plugin_Abstract
{
//...
/**
* @desc
* @returns boolean - TRUE if action method exists
*/
protected function actionMethodExists( Zend_Controller_Request_Abstract $zfRequestObj )
{
//getControllerClass() does not return the module prefix
$controllerClassSuffix = Zend_Controller_Front::getInstance()
->getDispatcher()
->getControllerClass( $zfRequestObj );
$controllerClassName = Zend_Controller_Front::getInstance()
->getDispatcher()
->formatClassName( $zfRequestObj->getModuleName() , $controllerClassSuffix );
//load the class before we call method_exists()
Zend_Controller_Front::getInstance()
->getDispatcher()
->loadClass( $controllerClassSuffix );
$actionMethod = Zend_Controller_Front::getInstance()
->getDispatcher()
->getActionMethod( $zfRequestObj );
return ( method_exists( $controllerClassName, $actionMethod ) );
}
//...
}