简体   繁体   中英

Zend framework 1.12 front controller configuration

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM