Issues

ZF-7089: Zend_Application_Resource_Modules::init() bootstraps all existing module bootstrap classes regardless of request

Description

h4. Behaviour: In Zend_Application_Resource_Modules::init(), all Bootstrap classes for all modules are loaded, regardless of what module was requested.

h4. Effect: This has the following side-effect: config ini keys that are set for each module are overwritten by each module when its bootstrap() method is called. The (unwanted) result is that the key is set for the last module encountered, not for the module requested.

h4. Example: setting layout resource in the config ini:

resources.layout.layout = "default"

resources.modules[] =
extranet.resources.layout.layout = "extranet"
intranet.resources.layout.layout = "intranet"

Also the module paths are not set explicitly, but by only setting

 
That means modules are registered in the order they are encountered when iterating through the modules directory.

h4. Result: 
the layout is set to 'intranet', even if the default or extranet module were requested.

h4. Suggested solution:
Zend_Application_Resource_Modules::init() should check for the requested module and only instantiate that bootstrap class.

The problem is that the request is not yet set in the frontcontroller when this is run. Is there a workaround?
If the request was set, it could be something like this:

the foreach starting on line 65:

foreach (array_keys($modules) as $module) { if ($module === $default) { continue; }

...

}

 

should be changed to:

$current = $front->getRequest()->getModuleName(); foreach (array_keys($modules) as $module) { if ($module === $default) { continue; } if ($module === $current) { continue; }

...

}````

Comments

That's indeed a bit unclear how the modules resource is tied to the actual application modules.

A solution could be to delegate the role of bootstrapping the modules to a plugin on routeShutdown.

This can be done by replacing the following line in Zend_Application_Resource_Modules

 

by this one

and creating a Zend_Controller_Plugin_ModulesBootstrapper plugin as follows:

 class Zend_Controller_Plugin_ModulesBootstrapper extends Zend_Controller_Plugin_Abstract
{
    public function routeShutdown(Zend_Controller_Request_Abstract $request)
    {

        $bootstrap = Zend_Controller_Front::getInstance()->getParam('bootstrap');

        $bootstraps = $bootstrap->getResource('modules');
        $module = $request->getModuleName();
        
        if (isset($bootstraps[$module])) {
            $bootstraps[$module]->bootstrap();
        }

    }
}

Although the side effects of this method need to be evaluated.

Quick precision: ````

is actually to be added after the foreach.

There were some specific problems addressed in the design goals of Zend_Application: * Autoloading for all modules should be setup up-front. This way code may selectively use information from any module without needing to know where that module resides. * Modules may need to setup front controller plugins; in particular, any given module may need to setup routes appropriate to its own controllers. The appropriate time to do this is during bootstrapping, as new routeStartup() plugins may not be added during routeStartup(). * Bootstrapping occurs prior to dispatch, and thus is request agnostic. This is to facilitate the re-use of bootstrapping in order to create service end points, one-off scripts, and to bootstrap tests. Thus, bootstrapping must occur outside of the front controller dispatch loop.

What you are suggesting goes counter to these goals entirely, and is actually impossible in the current design. The module is not known until after routing -- and routing happens during the front controller dispatch sequence. Additionally, based on the sequence of actions triggered, the module selected may change (as an example, if an exception is thrown, the ErrorController in the default module will likely be selected). I'd recommend registering a postDispatch() plugin either from your individual modules or at the application level that selects the layout based on the module.

As I've also made the same mistake as Matthijs, I think that the whole point of Zend_Application_Resource_Modules should be better clarified in the docs, as it's a bit confusing right now (in my opinion). Thanks.