I am trying to register my modules with the front controller using the bootstrap class by using the code below:
$this->bootstrap('FrontController');
$front = $this->getResource('FrontController');
$front->addModuleDirectory(APPLICATION_PATH."/modules");
$front->setParam('prefixDefaultModule', true);
This works fine and all the modules are registered. But when I do the following my module directory is not registered and I get the "controller not found error".
$front = Zend_Controller_Front::getInstance();
$front->addModuleDirectory(APPLICATION_PATH."/modules");
$front->setParam('prefixDefaultModule', true);
As the front controller implements the singleton design pattern shouldn't both the code blocks refer to the same instance and both of my code blocks should work?
The issue is this line in your application.ini:
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
The file structure you gave doesn't include this directory, so I think you can remove it and it will solve your problem.
Longer explanation of why it works one way and not the other:
There are two ways of configuring resources with Zend Application: class resources and plugin resources. The resources.xxx
lines in application.ini are plugin resources, and the _init
methods are class resources. Class resources run before plugin resources, but if you run $this->bootstrap('...')
it will ensure that resource has been initialized (regardless of type).
So in your first code example, $this->bootstrap('FrontController');
triggers the frontController resource which you defined in your application.ini. This then sets the controller directory using the path you gave it. You then add a module directory which seems to be what your application actually uses.
In your second code example, you get an instance of the front controller and then add your module directory to it (all good). But then the plugin resource will run (as remember these run after). This will grab your existing front controller instance, but setting the controller directory overrides the module directory, so this is what causes your error later on.
I generally try and avoid mixing and matching plugin and class resources as it can cause some weird problems. So either put it all in application.ini or all in the Bootstrap class. Personally I find the latter more readable.
If you do need the controller directory as well, adding $this->bootstrap('FrontController');
to the start of your second code example should work as well, since that will trigger the plugin resource.
Here is what is going on. Tim Fountain is correct. The following line in your application.ini file is the culprit. If you remove it, your application should load correctly.
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
You may also have to remove this line since it is part of the frontcontroller too.
resources.frontController.params.displayExceptions = 1
But you also have 2 other options to be able to use Zend_Controller_Front::getInstance()
Option 1. You change your index.php to bootstrap specific resources:
$application->bootstrap(array('FrontController', 'ModuleConfig'))->run();
This will bootstrap your FrontController first from your application.ini and then run your initModuleConfig
method. Essentially this allows you to control what resources are loaded and in what order. This is helpful when you have resources that you only want to bootstrap at specific times.
I think if you do not provide an array to the bootstrap method here, then it will call all methods prefixed with init
in the order they are declared.
Option 2. You could do the configuration of your of your module directory within your application.ini
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.frontController.params.prefixDefaultModule = 1
resources.frontController.params.displayExceptions = 1
This will do what you were trying to do in code. One thing to note is that you may want to bootstrap your FrontController in the constructor of your Bootstrap
class. This is just in case you need to use it during your custom initialization.
Now here is an explanation for why option 1 works.
This is a method from 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__);
}
}
This _bootstrap
is called when you call the public bootstrap
method. Example $this->bootstrap("FrontController")
or $this->bootstrap()
;
Notice the case when you don't pass in a parameter. This will call the null
case which is the case you get in your index.php
- $application->bootstrap()->run();
First it will load your class resources
and then it will also call your plugin resources
. Notice that the the plugin resources
are not loaded in the other cases.
If you follow the method calls for class resources, it is basically call your init
methods in your bootstrap call class.
The plugin resources are called afterward and one of the plugin resources. I'm not entirely sure how all the plugin resources are loaded, but I believe one source is in your application.ini
file. These will be the lines that start with resources
. Examples includes views, frontcontroller, db.
So in your situation where you call $application->bootstrap()->run();
, your init
methods are loaded first. But your FrontController
is not bootstrapped yet. It eventually gets bootstrapped as a plugin resource which is taken from your application.ini
. This apparently overwrites what you did in your bootstrap class.
Another question you may be asking is why is the FrontController instance not overridden when you call $this->bootstrap("FrontController)
explicitly. I guess this pretty obvious but personally I had this question myself.
In the Bootstrap class, there is a method called _executeResource
and this will check if the resource has already been bootstrapped. It uses an associative array to keep track. The associative array is called $this->_started
.
This is why the plugin resource for the front controller is not called in your first case where you explicitly bootstrap the front controller. Hence your front controller instance is not replaced.
You need to bootstrap the front controller first so it is initialized. Once done in the cycle you could always retrieve it with the static getInstance.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.