Zend Framework

Issues on Modular Bootstrapping

Details

  • Type: Improvement Improvement
  • Status: Open Open
  • Priority: Major Major
  • Resolution: Unresolved
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: Zend_Application
  • Labels:
    None

Description

As defined in the section 4.6.4 of reference guide, the Modules resource (Zend_Application_Resource_Modules), by design creates a modular resource autoloader (Zend_Application_Modules_Autoloader) automatically. A deeper look in the components code shows that the Zend_Application_Module_Bootstrap have a property ($_resourceLoader) that define a resource autoloader (Zend_Application_Module_Autoloader). Chasing the calls stack:

  1. Zend_Application_Module_Bootstrap calls initResourceLoader() that proxies to getResourceLoader();
  2. getResourceLoader() creates a new Zend_Application_Module_Autoloader object;
  3. Zend_Application_Module_Autoloader constructor calls it's parent (Zend_Loader_Autoloader_Resource) constructor and pass the same options received from Zend_Application_Module_Bootstrap getResourceLoader() call;
  4. After that, the Zend_Application_Module_Autoload initDefaultResourceTypes() method is called, which initialize autoloading specifications - as plugins, models, etc.

Although this looks nice, when using a module bootstrap (a Admin_Bootstrap extends Zend_Application_Module_Bootstrap), the module resource autoloader doesn't seems to be properly initialized - it's not possible to load, for example, models without having to define a autoloader within a resource method or plugin.

I only got modular bootstrapping working by:

  1. Specifying a Zend_Application_Bootstrap_Bootstrap bootstrap object for the default module - it doesn't work with a Zend_Application_Module_Bootstrap;
  2. Specifying a resource autoloader as resource method in the default module bootstrap;
  3. Specifying a Zend_Application_Module_Bootstrap bootstrap object for non default modules.

I think that using Zend_Application_Module_Bootstrap should be mandatory for modular bootstrapping - and have the resource autoloader working as well. This can be a simple approach to avoid the current complexity of modular bootstrapping.

Last but not least, the section in reference guide looks very poor for a subject like modular bootstrapping and is insufficient to have a modular application working at a glance.

Activity

Hide
Matthew Weier O'Phinney added a comment -

It took me quite some time to understand exactly what you were trying to explain, which was quite simply: extending Zend_Application_Module_Bootstrap in the default module does not work as expected.

There are some workarounds/strategies you can use now to have this work. The easiest is to:

  1. Put all modules, including the default module, under a "modules" directory:
    application/
        modules/
            default/
            blog/
            news/
  2. Tell Zend_Application where to find the default module's bootstrap, and what it's named:
    bootstrap.path = APPLICATION_PATH "/modules/default/Bootstrap.php"
    bootstrap.class = "Default_Bootstrap"
  3. Have Default_Bootstrap extend Zend_Application_Module_Bootstrap
    This strategy utilizes modules appropriately. Because the module bootstrap is now in a directory named after the module, the module namespace will be set properly (to "Default_"), which will allow the various resources to load under that namespace.

We plan to make this easier for 1.10 already, but have to be careful to ensure we do not create a BC break.

Show
Matthew Weier O'Phinney added a comment - It took me quite some time to understand exactly what you were trying to explain, which was quite simply: extending Zend_Application_Module_Bootstrap in the default module does not work as expected. There are some workarounds/strategies you can use now to have this work. The easiest is to:
  1. Put all modules, including the default module, under a "modules" directory:
    application/
        modules/
            default/
            blog/
            news/
  2. Tell Zend_Application where to find the default module's bootstrap, and what it's named:
    bootstrap.path = APPLICATION_PATH "/modules/default/Bootstrap.php"
    bootstrap.class = "Default_Bootstrap"
  3. Have Default_Bootstrap extend Zend_Application_Module_Bootstrap This strategy utilizes modules appropriately. Because the module bootstrap is now in a directory named after the module, the module namespace will be set properly (to "Default_"), which will allow the various resources to load under that namespace.
We plan to make this easier for 1.10 already, but have to be careful to ensure we do not create a BC break.
Hide
Bruno Pirajá Moyle added a comment -

Sorry about the fuzzy explanation.

I had tried the workaround, but got the following error:

Fatal error: Uncaught exception 'Zend_Application_Bootstrap_Exception' with message 'No default controller directory registered with front controller' in /usr/local/php5/include/Zend/Application/Bootstrap/Bootstrap.php:71 Stack trace: #0 /usr/local/php5/include/Zend/Application.php(358): Zend_Application_Bootstrap_Bootstrap->run() #1 /var/www/intranet/public/index.php(32): Zend_Application->run() #2

Unknown macro: {main}
thrown in /usr/local/php5/include/Zend/Application/Bootstrap/Bootstrap.php on line 71

That's what I did:

  1. Used a modular directory:
    application/
        default/
            Bootstrap.php // Default_Bootstrap extends Zend_Application_Module_Bootstrap
        blog/
            Bootstrap.php // Blog_Bootstrap extends Zend_Application_Module_Bootstrap
        news/
            Bootstrap.php // News_Bootstrap extends Zend_Application_Module_Bootstrap
    
  2. Modified the application.ini file:
    ; Bootstrap
    bootstrap.path = APPLICATION_PATH "/modules/default/Bootstrap.php"
    bootstrap.class = "Default_Bootstrap"
    
    ; Resources (FrontController)
    resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
    
  3. Requested http://zend-app/default/index/index;
  4. Got the error.

This exception is trowed in the Zend_Application_Bootstrap_Bootstrap at line 71. Looks like the Front Controller is having some problems in it's initialization, but I noticed that the Front Controller is registered in Zend_Application_Module_Bootstrap at line 74.

Last, I tried this:

; Resources (FrontController)
resources.frontController.controllerDirectory.default = APPLICATION_PATH "/modules/default/controllers"
resources.frontController.controllerDirectory.admin = APPLICATION_PATH "/modules/admin/controllers"

It didn't work...

Thanks

Show
Bruno Pirajá Moyle added a comment - Sorry about the fuzzy explanation. I had tried the workaround, but got the following error:
Fatal error: Uncaught exception 'Zend_Application_Bootstrap_Exception' with message 'No default controller directory registered with front controller' in /usr/local/php5/include/Zend/Application/Bootstrap/Bootstrap.php:71 Stack trace: #0 /usr/local/php5/include/Zend/Application.php(358): Zend_Application_Bootstrap_Bootstrap->run() #1 /var/www/intranet/public/index.php(32): Zend_Application->run() #2
Unknown macro: {main}
thrown in /usr/local/php5/include/Zend/Application/Bootstrap/Bootstrap.php on line 71
That's what I did:
  1. Used a modular directory:
    application/
        default/
            Bootstrap.php // Default_Bootstrap extends Zend_Application_Module_Bootstrap
        blog/
            Bootstrap.php // Blog_Bootstrap extends Zend_Application_Module_Bootstrap
        news/
            Bootstrap.php // News_Bootstrap extends Zend_Application_Module_Bootstrap
    
  2. Modified the application.ini file:
    ; Bootstrap
    bootstrap.path = APPLICATION_PATH "/modules/default/Bootstrap.php"
    bootstrap.class = "Default_Bootstrap"
    
    ; Resources (FrontController)
    resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
    
  3. Requested http://zend-app/default/index/index;
  4. Got the error.
This exception is trowed in the Zend_Application_Bootstrap_Bootstrap at line 71. Looks like the Front Controller is having some problems in it's initialization, but I noticed that the Front Controller is registered in Zend_Application_Module_Bootstrap at line 74. Last, I tried this:
; Resources (FrontController)
resources.frontController.controllerDirectory.default = APPLICATION_PATH "/modules/default/controllers"
resources.frontController.controllerDirectory.admin = APPLICATION_PATH "/modules/admin/controllers"
It didn't work... Thanks
Hide
Ashley Broadley added a comment -

As far as i can see there is one other config option you need for modular applications to work:

resources.modules = ""

these are all you should need for a modular layout to work:
in your application.ini
{{resources.modules = ""
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"}}
and in your Application bootstrap class:

protected function _initAutoloader ()
    {
        $autoloader = new Zend_Application_Module_Autoloader(array(
            'namespace' => 'Default_',
            'basePath' => APPLICATION_PATH.'/modules/default'
        ));
        return $autoloader;
    }
Show
Ashley Broadley added a comment - As far as i can see there is one other config option you need for modular applications to work:
resources.modules = ""
these are all you should need for a modular layout to work: in your application.ini {{resources.modules = "" resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"}} and in your Application bootstrap class:
protected function _initAutoloader ()
    {
        $autoloader = new Zend_Application_Module_Autoloader(array(
            'namespace' => 'Default_',
            'basePath' => APPLICATION_PATH.'/modules/default'
        ));
        return $autoloader;
    }
Hide
Bruno Pirajá Moyle added a comment - - edited

Thanks Ashley...

I omitted the option resources.modules[]="" but it is defined in the configuration file as well.

In the reference guide and in the code of the Zend_Application_Module_Bootstrap creates an autoloader automatically, but this is not working as expected.

Try doing the same that I did above (using the resources.modules=[] ), do not define _initAutoloader resources methods and will check that it do not work as expected.

If we extends Zend_Application_Module_Bootstrap in our default bootstrap, an uncaught exception is throwed:

Fatal error: Uncaught exception 'Zend_Application_Bootstrap_Exception' with message 'No default controller directory registered with front controller' in /usr/local/php5/lib/php/Zend/Application/Bootstrap/Bootstrap.php:71 Stack trace: #0 /usr/local/php5/lib/php/Zend/Application.php(358): Zend_Application_Bootstrap_Bootstrap->run() #1 /var/www/intranet/public/index.php(25): Zend_Application->run() #2

Unknown macro: {main}
thrown in /usr/local/php5/lib/php/Zend/Application/Bootstrap/Bootstrap.php on line 71

Show
Bruno Pirajá Moyle added a comment - - edited Thanks Ashley... I omitted the option resources.modules[]="" but it is defined in the configuration file as well. In the reference guide and in the code of the Zend_Application_Module_Bootstrap creates an autoloader automatically, but this is not working as expected. Try doing the same that I did above (using the resources.modules=[] ), do not define _initAutoloader resources methods and will check that it do not work as expected. If we extends Zend_Application_Module_Bootstrap in our default bootstrap, an uncaught exception is throwed:
Fatal error: Uncaught exception 'Zend_Application_Bootstrap_Exception' with message 'No default controller directory registered with front controller' in /usr/local/php5/lib/php/Zend/Application/Bootstrap/Bootstrap.php:71 Stack trace: #0 /usr/local/php5/lib/php/Zend/Application.php(358): Zend_Application_Bootstrap_Bootstrap->run() #1 /var/www/intranet/public/index.php(25): Zend_Application->run() #2
Unknown macro: {main}
thrown in /usr/local/php5/lib/php/Zend/Application/Bootstrap/Bootstrap.php on line 71
Hide
Bruno Pirajá Moyle added a comment -

Reporting some evolution in my research for this issue:

  • Started a clean Zend application (with zf create project);
  • Created the modular directories structure:
application/
    configs/
    modules/
        default/
            controllers/
            models/
            views/
            Bootstrap.php # Default_Bootstrap extends Zend_Application_Module_Bootstrap
        admin/
            controllers/
            models/
            views/
            Bootstrap.php # Admin_Bootstrap extends Zend_Application_Module_Bootstrap
    scripts/
    ...
  • Updated configuration file to use a default modular bootstrap class:
bootstrap.path  = APPLICATION_FILE "/modules/default/Bootstrap.php"
bootstrap.class = "Default_Bootstrap"
  • Updated configuration file to use the Modules resource:
resources.modules = ""

Fatal error: Uncaught exception 'Zend_Application_Bootstrap_Exception' with message 'No default controller directory registered with front controller' in /usr/local/php5/lib/php/Zend/Application/Bootstrap/Bootstrap.php:71 Stack trace: #0 /usr/local/php5/lib/php/Zend/Application.php(358): Zend_Application_Bootstrap_Bootstrap->run() #1 /var/www/intranet/public/index.php(25): Zend_Application->run() #2
Unknown macro:

Unknown macro: {main}

thrown in /usr/local/php5/lib/php/Zend/Application/Bootstrap/Bootstrap.php on line 71

  • After a deeper research within involved components code, I noticed that this exception is throw in Zend_Application_Bootstrap_Bootstrap at line 74. In this line, the class check if the Front Controller has a default controller directory:
if (null === $front->getControllerDirectory($default)) {
    throw new Zend_Application_Bootstrap_Exception(
        'No default controller directory registered with front controller'
    );
}
  • Although this method was defined Zend_Application_Bootstrap_Bootstrap, it's called from Zend_Application_Module_Bootstrap - as it doesn't overwrite it.
  • This error only occurs when the Zend_Application_Module_Bootstrap is used. If the Zend_Application_Bootstrap_Bootstrap is used this exception isn't throwed. Thus, I will constrain that the problem is originated in the Zend_Application_Module_Bootstrap class.
  • I tried a simple fix by adding one line in the Zend_Application_Bootstrap_Bootstrap and the exception stopped being throwed:
    //...
    $front   = $this->getResource('FrontController');
    $default = $front->getDefaultModule();
    
    // I've added this line
    $front->setControllerDirectory(APPLICATION_PATH . '/modules/default' . '/controllers', $default);
            
    if (null === $front->getControllerDirectory($default)) {
        throw new Zend_Application_Bootstrap_Exception(
            'No default controller directory registered with front controller'
        );
    }
    
    //...
    
  • In addition, the resource autoloader created automatically by Zend_Application_Module_Bootstrap worked. Maybe the Zend_Application_Module_Bootstrap isn't instantiating the Front Controller properly.
Show
Bruno Pirajá Moyle added a comment - Reporting some evolution in my research for this issue:
  • Started a clean Zend application (with zf create project);
  • Created the modular directories structure:
application/
    configs/
    modules/
        default/
            controllers/
            models/
            views/
            Bootstrap.php # Default_Bootstrap extends Zend_Application_Module_Bootstrap
        admin/
            controllers/
            models/
            views/
            Bootstrap.php # Admin_Bootstrap extends Zend_Application_Module_Bootstrap
    scripts/
    ...
  • Updated configuration file to use a default modular bootstrap class:
bootstrap.path  = APPLICATION_FILE "/modules/default/Bootstrap.php"
bootstrap.class = "Default_Bootstrap"
  • Updated configuration file to use the Modules resource:
resources.modules = ""
Fatal error: Uncaught exception 'Zend_Application_Bootstrap_Exception' with message 'No default controller directory registered with front controller' in /usr/local/php5/lib/php/Zend/Application/Bootstrap/Bootstrap.php:71 Stack trace: #0 /usr/local/php5/lib/php/Zend/Application.php(358): Zend_Application_Bootstrap_Bootstrap->run() #1 /var/www/intranet/public/index.php(25): Zend_Application->run() #2 Unknown macro:
Unknown macro: {main}
thrown in /usr/local/php5/lib/php/Zend/Application/Bootstrap/Bootstrap.php on line 71
  • After a deeper research within involved components code, I noticed that this exception is throw in Zend_Application_Bootstrap_Bootstrap at line 74. In this line, the class check if the Front Controller has a default controller directory:
if (null === $front->getControllerDirectory($default)) {
    throw new Zend_Application_Bootstrap_Exception(
        'No default controller directory registered with front controller'
    );
}
  • Although this method was defined Zend_Application_Bootstrap_Bootstrap, it's called from Zend_Application_Module_Bootstrap - as it doesn't overwrite it.
  • This error only occurs when the Zend_Application_Module_Bootstrap is used. If the Zend_Application_Bootstrap_Bootstrap is used this exception isn't throwed. Thus, I will constrain that the problem is originated in the Zend_Application_Module_Bootstrap class.
  • I tried a simple fix by adding one line in the Zend_Application_Bootstrap_Bootstrap and the exception stopped being throwed:
    //...
    $front   = $this->getResource('FrontController');
    $default = $front->getDefaultModule();
    
    // I've added this line
    $front->setControllerDirectory(APPLICATION_PATH . '/modules/default' . '/controllers', $default);
            
    if (null === $front->getControllerDirectory($default)) {
        throw new Zend_Application_Bootstrap_Exception(
            'No default controller directory registered with front controller'
        );
    }
    
    //...
    
  • In addition, the resource autoloader created automatically by Zend_Application_Module_Bootstrap worked. Maybe the Zend_Application_Module_Bootstrap isn't instantiating the Front Controller properly.
Hide
Matthew Weier O'Phinney added a comment -

Do you have the following in your INI?

resources.frontcontroller.controllerDirectory = APPLICATION_PATH "/modules/default/controllers"

If you don't specify a controller directory during configuration or in a bootstrap resource, then you'll get the error reported.

Also, you should use array notation for the "modules" key:

resources.modules[] =

as this will properly initialize configuration for that resource.

Finally, you can replace the controllerDirectory configuration with moduleDirectory:

resources.frontcontroller.moduleDirectory = APPLICATION_PATH "/modules"

This will ensure that the modules are passed to the front controller; if you have a "default" module, it will also be defined, and that bootstrap run.

Without knowing the exact contents of your configuration, I'm primarily conjecturing here, however.

Show
Matthew Weier O'Phinney added a comment - Do you have the following in your INI?
resources.frontcontroller.controllerDirectory = APPLICATION_PATH "/modules/default/controllers"
If you don't specify a controller directory during configuration or in a bootstrap resource, then you'll get the error reported. Also, you should use array notation for the "modules" key:
resources.modules[] =
as this will properly initialize configuration for that resource. Finally, you can replace the controllerDirectory configuration with moduleDirectory:
resources.frontcontroller.moduleDirectory = APPLICATION_PATH "/modules"
This will ensure that the modules are passed to the front controller; if you have a "default" module, it will also be defined, and that bootstrap run. Without knowing the exact contents of your configuration, I'm primarily conjecturing here, however.
Hide
Bruno Pirajá Moyle added a comment -

I misspelled the Modules resource options line:

resources.modules[] = ""

And forgot to include the Front Controller resource options:

resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"

This was the correct setup in the last message, sorry.

The exception is still being throwed.

This is my full configuration file:

[production]
; PHP settings and autoloading
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"

; Bootstrap
bootstrap.path = APPLICATION_PATH "/modules/default/Bootstrap.php"
bootstrap.class = "Default_Bootstrap"

; Resources (FrontController)
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"

; Resources (Modules)
resources.modules[] = ""

[staging : production]

[testing : production]
; PHP settings and autoloading
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
; PHP settings and autoloading
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

This is my default bootstrap class:

<?php

/**
 * Default bootstrap class.
 *
 * @package default
 * @author  Bruno
 */
class Default_Bootstrap extends Zend_Application_Module_Bootstrap
{
}

And this one is my admin module bootstrap:

<?php

/**
 * Admin module bootstrap class.
 *
 * @package admin
 * @author  Bruno
 */
class Admin_Bootstrap extends Zend_Application_Module_Bootstrap
{
}
Show
Bruno Pirajá Moyle added a comment - I misspelled the Modules resource options line:
resources.modules[] = ""
And forgot to include the Front Controller resource options:
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
This was the correct setup in the last message, sorry. The exception is still being throwed. This is my full configuration file:
[production]
; PHP settings and autoloading
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"

; Bootstrap
bootstrap.path = APPLICATION_PATH "/modules/default/Bootstrap.php"
bootstrap.class = "Default_Bootstrap"

; Resources (FrontController)
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"

; Resources (Modules)
resources.modules[] = ""

[staging : production]

[testing : production]
; PHP settings and autoloading
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
; PHP settings and autoloading
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
This is my default bootstrap class:
<?php

/**
 * Default bootstrap class.
 *
 * @package default
 * @author  Bruno
 */
class Default_Bootstrap extends Zend_Application_Module_Bootstrap
{
}
And this one is my admin module bootstrap:
<?php

/**
 * Admin module bootstrap class.
 *
 * @package admin
 * @author  Bruno
 */
class Admin_Bootstrap extends Zend_Application_Module_Bootstrap
{
}

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated: