我正在尝试使用以下代码使用bootstrap类向前端控制器注册我的模块:
$this->bootstrap('FrontController');
$front = $this->getResource('FrontController');
$front->addModuleDirectory(APPLICATION_PATH."/modules");
$front->setParam('prefixDefaultModule', true);
这很好用,所有模块都已注册。但是,当我执行以下操作时,我的模块目录未注册,我收到“找不到控制器错误”。
$front = Zend_Controller_Front::getInstance();
$front->addModuleDirectory(APPLICATION_PATH."/modules");
$front->setParam('prefixDefaultModule', true);
由于前端控制器实现了单例设计模式,因此代码块不应该引用同一个实例,而且我的两个代码块都应该有效吗?
答案 0 :(得分:2)
问题是你的application.ini中的这一行:
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
您提供的文件结构不包含此目录,因此我认为您可以将其删除,它将解决您的问题。
更长的解释为什么它以一种方式而不是另一种方式起作用:
使用Zend Application配置资源有两种方法: class 资源和插件资源。 application.ini中的resources.xxx
行是插件资源,_init
方法是类资源。类资源在插件资源之前运行,但如果运行$this->bootstrap('...')
,它将确保资源已初始化(无论类型如何)。
因此,在您的第一个代码示例中,$this->bootstrap('FrontController');
会触发您在application.ini中定义的frontController资源。然后使用您给出的路径设置控制器目录。然后添加一个模块目录,该目录似乎是您的应用程序实际使用的目录。
在第二个代码示例中,您将获得前端控制器的一个实例,然后将模块目录添加到它(一切都很好)。但是插件资源将运行(记住这些运行后)。这将获取现有的前端控制器实例,但设置控制器目录会覆盖模块目录,因此这将导致您的错误。
我通常会尝试避免混合和匹配插件和类资源,因为它可能会导致一些奇怪的问题。所以要么全部放在application.ini中,要么全部放在Bootstrap类中。我个人认为后者更具可读性。
如果您确实需要控制器目录,那么将$this->bootstrap('FrontController');
添加到第二个代码示例的开头也应该可以,因为这将触发插件资源。
答案 1 :(得分:1)
以下是正在发生的事情。蒂姆喷泉是正确的。 application.ini文件中的以下行是罪魁祸首。如果删除它,应该正确加载应用程序。
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
您可能还必须删除此行,因为它也是前控制器的一部分。
resources.frontController.params.displayExceptions = 1
但您还有2个其他选项可以使用Zend_Controller_Front::getInstance()
选项1.您将index.php更改为引导特定资源:
$application->bootstrap(array('FrontController', 'ModuleConfig'))->run();
这将首先从您的application.ini引导您的FrontController,然后运行您的initModuleConfig
方法。从本质上讲,这允许您控制加载的资源和顺序。当您拥有仅在特定时间进行引导的资源时,这非常有用。
我认为如果你没有在这里为bootstrap方法提供一个数组,那么它将按照它们被声明的顺序调用前缀为init
的所有方法。
选项2.您可以在application.ini
中配置模块目录resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.frontController.params.prefixDefaultModule = 1
resources.frontController.params.displayExceptions = 1
这将执行您在代码中尝试执行的操作。需要注意的一点是,您可能希望在Bootstrap
类的构造函数中引导FrontController。这是为了防止您在自定义初始化期间需要使用它。
现在,这是对选项1工作原理的解释。
这是Zend_Application_Bootstrap_BootstrapAbstract
protected function _bootstrap($resource = null)
{
if (null === $resource) {
foreach ($this->getClassResourceNames() as $resource) {
$this->_executeResource($resource);
}
foreach ($this->getPluginResourceNames() as $resource) {
$this->_executeResource($resource);
}
} elseif (is_string($resource)) {
$this->_executeResource($resource);
} elseif (is_array($resource)) {
foreach ($resource as $r) {
$this->_executeResource($r);
}
} else {
throw new Zend_Application_Bootstrap_Exception('Invalid argument passed to ' . __METHOD__);
}
}
调用公共_bootstrap
方法时会调用此bootstrap
。示例$this->bootstrap("FrontController")
或$this->bootstrap()
;
请注意未传入参数时的情况。这将调用null
案例,即index.php
- $application->bootstrap()->run();
首先它会加载您的class resources
,然后它也会调用您的plugin resources
。请注意,plugin resources
未在其他情况下加载。
如果您按照方法调用类资源,它基本上会在您的引导调用类中调用您的init
方法。
之后调用插件资源和其中一个插件资源。我不完全确定所有插件资源是如何加载的,但我相信你的application.ini
文件中有一个来源。这些是以resources
开头的行。示例包括views,frontcontroller,db。
因此,在您调用$application->bootstrap()->run();
的情况下,首先会加载init
方法。但是你的FrontController
还没有被引导。它最终作为插件资源被引导,该资源取自您的application.ini
。这显然会覆盖你在bootstrap类中所做的事情。
您可能会问的另一个问题是,为什么在您明确调用$this->bootstrap("FrontController)
时不会覆盖FrontController实例。我想这很明显,但我个人自己也有这个问题。
在Bootstrap类中,有一个名为_executeResource
的方法,这将检查资源是否已经被引导。它使用关联数组来跟踪。关联数组称为$this->_started
。
这就是为什么在您明确引导前端控制器的第一种情况下不调用前端控制器的插件资源。因此,您的前端控制器实例不会被替换。
答案 2 :(得分:0)
您需要先启动前端控制器,然后进行初始化。在循环中完成后,您始终可以使用静态getInstance检索它。