views:

426

answers:

3

The manual on Zend_Application_Module_Autoloader states the following:

When using module bootstraps with Zend_Application, an instance of Zend_Application_Module_Autoloader will be created by default for each discrete module, allowing you to autoload module resources.

Source: http://framework.zend.com/manual/zh/zend.loader.autoloader-resource.html#zend.loader.autoloader-resource.module

This requires me to create an empty bootstrap class for each of my modules or else resource autoloading per module won't work with the build-in autoloader.

Now I have two questions

  • What is a discrete module?
  • Is there a way to have this resource autoloader registered by default for each module without the need to create a bootstrap file for each module? I want it available in each module and creating so many empty bootstrap classes is something i'd rather prevent.
+1  A: 

The reason modules bootstraps enable autoload is because they extend Zend_Application_Module_Bootstrap which sets the autoloader in the constructor like so

public function __construct($application)
{
  //...
  if ($application->hasOption('resourceloader')) {
      $this->setOptions(array(
          'resourceloader' => $application->getOption('resourceloader')
      ));
  }
  $this->initResourceLoader();
  //...
}

This runs because the modules resource runs the bootstrap for each module in the init function ...

       foreach ($modules as $module => $moduleDirectory) {
        $bootstrapClass = $this->_formatModuleName($module) . '_Bootstrap';
        if (!class_exists($bootstrapClass, false)) {
            $bootstrapPath  = dirname($moduleDirectory) . '/Bootstrap.php';
            if (file_exists($bootstrapPath)) {
                $eMsgTpl = 'Bootstrap file found for module "%s" but bootstrap class "%s" not found';
                include_once $bootstrapPath;
                if (($default != $module)
                    && !class_exists($bootstrapClass, false)
                ) {
                    throw new Zend_Application_Resource_Exception(sprintf(
                        $eMsgTpl, $module, $bootstrapClass
                    ));
                } elseif ($default == $module) {
                    if (!class_exists($bootstrapClass, false)) {
                        $bootstrapClass = 'Bootstrap';
                        if (!class_exists($bootstrapClass, false)) {
                            throw new Zend_Application_Resource_Exception(sprintf(
                                $eMsgTpl, $module, $bootstrapClass
                            ));
                        }
                    }
                }
            } else {
                continue;
            }
        }

        if ($bootstrapClass == $curBootstrapClass) {
            // If the found bootstrap class matches the one calling this
            // resource, don't re-execute.
            continue;
        }

        $moduleBootstrap = new $bootstrapClass($bootstrap);
        $moduleBootstrap->bootstrap();
        $this->_bootstraps[$module] = $moduleBootstrap;
    }

The short answer is if you don't write the empty bootstrap files, you'll have to abstract some of this well functioning, well tested code into your own global bootstrap file, and then lose the flexibility of having bootstraps for you modules when / if you need to bootstrap them later in your app.

Travis
Thanks for explaining, it just feels counter productive and not really a best practice to just litter my modules with empty bootstrap classes just to enable module specific resource loading. Indeed when i want to bootstrap a module i should add a module bootstrap but since in ALL modules resource autoloading should be available i was wondering if there wasn't something in the Application scope that could configure this?
ChrisR
I understand. If they are empty they just seem useless, but in my experience, there's come a point in time in every application where I've needed to bootstrap my module. I use it for defining custom module specific routes, grabbing specific formatted config files for modules themselves, and other things like that.You can easily remove the need for it from your app by adding that code into your bootstrap, if it bothers you that much, but IMHO, it's not worth it.
Travis
+1  A: 

Modules allow you to separate your application into specific concerns. Frequently my larger applications will have a default module for users and an admin module to contain all administrative functions. I use the directory structure recommended in the Recommended Project Structure for Zend Framework MVC Applications -> Module Structure section of the Zend Framework Documentation.

As to your second question, the answer is yes and no. If you want to take advantage of the default autoloading functionality (loading Admin_Form_Settings from the admin/forms directory), you will need a bootstrap in each module. See Matthew Weier O'Phinney's article on Module Bootstraps in Zend Framework: Do's and Don'ts for more info. You may also want to Google for and review Rob Allen's post "Bootstrapping modules in ZF 1.8 and up."

Answering no to your second question: one technique that I like to use that doesn't require empty bootstraps in each module is placing all of your application classes in the application's lib folder, and mimic the Zend Framework's directory structure. If my application is named Example, I'll create a folder named Example in my /lib directory. My user registration form would be placed in /lib/Example/Form, and might be named UserRegistration.php. My class would be named Example_Form_UserRegistration. Autoloading my form would require the following in the Bootstrap.php file:

protected function _initAppAutoload() {

    $autoloader = Zend_Loader_Autoloader::getInstance();

    return $autoloader;
}

My application.ini would include the lines

resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.modules[] = 
autoloaderNamespaces[] = "Example_"

Using this technique you should then be able to autoload any class in /lib/Example anywhere in your application without placing empty bootstraps in each module.

NOTE: I tried posting links directly to the docs and to Rob Allen's article, but since I'm a new guy I was only allowed a single link. Apologies for asking you to Google items that should be links.

Jeremy Kendall
Hi Jeremy, thanks for the answer. Just to make things clear ... i know what modules are and have been using them for ever since they became available in ZF but i was referring to the "Discrete" part :) And concerning the second question, i've considered importing nearly everything into the application namespace but since most of the modules i'm building are plug and play dropin modules i would like to keep everthing related to a module together in the module folder.
ChrisR
Aha. As far as I can tell, the "discrete" part is simply describing the modules as wholly contained, separate portions of your application. I don't think it's intended to be interpreted as a different kind of module. Confusing, as discrete can have a special meaning in technical fields.As to your second question, considering your requirements, I don't know of a way to avoid adding module bootstraps. However, there are a lot of ZF developers who are a lot smarter than I am. You might check the links at the bottom of Matthew's article for some new ideas.
Jeremy Kendall
+5  A: 

I understand your reluctance to add an empty bootstrap class to each module. However, consider the case for re-use: if you are able to bundle your module separately, you can then drop it into another application later, and autoloading will work immediately, with no extra work. This was one of the use cases for having module bootstraps, and why it currently works the way it does.

("Discrete" in this case means "self-contained", and not part of the "application" module.)

If you don't like how this operates, you're free to omit the module bootstrap -- you'll simply need to add in a resource autoloader for the module yourself somehow. This can be done via a bootstrap resource method fairly easily. However, as someone earlier posted: why re-invent the wheel when something that's tested and documented gets the job done? :)

weierophinney
Thanks matthew ... your arguments indeed make sense. I can live with empty bootstrap files and like Travis and Jeremy said there'll come a time i'll need to bootstrap them anyway so i'll just cope with it and use empty bootstrap files :)
ChrisR