Offshoot Blog

Module Bootstrapping in Zend Framework

It seems that ever since the 1.8 release of Zend Framework (where they introduced the new application bootstrapping), there has been a lot of discussion about the way that module bootstrapping is handled. I think most programmers, myself included, tend to think of “modules” as self-contained entities that can be plugged in or removed from a larger application, with little to no change to the application itself. So when we hear ZF start talking about Module bootstrapping, people tend to assume that a module bootstrap (Zend_Application_Module_Bootstrap) will perform exactly the same as the default bootstrap (Zend_Application_Bootstrap_Bootstrap), but only for the module that is being requested. Unfortunately this assumption is incorrect, for a very important reason. The default bootstrap sets up paths, loads any resources, and prep’s your application — all before your application even knows what module has been requested. All of the module bootstraps are called immediately after the default bootstrap, which is still before your application knows which module has been requested. The module bootstrap can set up paths and add to or alter loaded resources like an ACL or navigation, but they’re unable to load module specific resources or execute any module specific code.

For some background on this, you’ll want to start with Matthew Weier O’Phinney’s article “Module Bootstraps in Zend Framework: Do’s and Don’ts”. In that article you’ll get a good run down of how module bootstrapping works in ZF and why. In particular, you’ll find a more in depth answer to the most popular question: “Why are all module bootstraps run on every request, and not just the one for the requested module?”. The gist of it, as I mentioned above, is that the default module bootstrapping is intended mostly for setting up paths and initializing or altering resources that are available to the application as a whole. Module bootstrapping is not to be used for running module specific code or loading resources that should only be available to the active module.

So how do we get to a solution that allows us to run module specific code, only when that module is active? Weier O’Phinney offers a Plugin based solution. Quick and to the point. It offers us the ability to run module specific code, but has a number of important drawbacks: 1) it strips us of the powerful functionality that we get from bootstrapping (resource loading, application.ini, etc); 2) It bloats our dispatch cycle with a minimum of 1 Plugin per module (this may or may not be a big deal to you, depending on your application); and 3) possibly the most important — it requires modifications to our default bootstrapping every time a new module is added or taken away.

I’m really looking for a solution that allows my modules to be self-contained and independent of their application container. I don’t want to have to alter my default bootstrapping if I want to add or remove a module. This lead me to an article, “Zend Framework Module Config The Easy Way” by Leonard Dronkers. This was a short code example that illustrates how we can have module specific configuration, that is contained within our module and doesn’t require plugins or anything more than a one-time change to our default bootstrapping. This is a good start, but suffers from some of the same drawbacks as the last solution we looked at. It still strips us of the powerful automagical resource loading, and also delegates to the controllers to deal with the module specific configuration. The latter can lead to a bloated controller layer and even potentially to duplicated code. This is definitely on the right track, but still isn’t what I’m looking for.

From here, I came across “Active Module Based Config with Zend Framework” and “Active Module Config V2″ by Kathryn “BinaryKitten”. The former article is her first attempt at solving this problem and an interesting read, but the latter article is the important one. Finally we’re getting closer to the kind of solution that I’ve been looking for. Yet still, something is missing. The plugin appears to be doing too much and some of code is adapted(or duplicated) from some of the ZF bootstrapping classes. It also forces us to bloat our module bootstrap classes with an additional set of activeInit* methods (not to be confused with the __init* methods). It doesn’t appear to allow for the module specific configuration offered by Dronkers’ solution, expecting all the work to be custom coded in the activeInit* methods. Though a great start, this solution falls short without a solution for storing the result of the activeInit* methods back on the bootstrap for access elsewhere in the application.

Time to take what I’ve learned from the above articles and throw my 2 cents into the mix! Big disclaimer here: this code has NOT been tested and should NOT be used in a production environment. This is just an initial phase of this solution and is lacking a considerable amount of error checking and unit testing. It appears to work for the few cases that I’ve run it through, which is promising, but it is by no means a complete solution yet.

Ok, let’s get down to business…

I started by adapting Dronkers’ solution into a module bootstrap class that loads a module specific ini file

This plugin doesn’t do much right now (we’ll come back to it shortly), but what’s important here is that we have access to the module bootstrap class (which has loaded the module specific configuration file). My biggest problem with Kathryn’s solution was that the plugin was doing too much: I wanted to delegate some of the work to another class (or set of classes) and at the same time, regain the power that the ZF bootstrapping has to offer, without duplicating any code.

This is where things start to get interesting! If what I’m looking for is essentially a second round of bootstrapping, that’s specific to the active module, why not just extend the abstract bootstrapping functionality and create a class that takes care of the module specific bootstrapping. This class will need to be separate from the ZF bootstrapping procedure, so that it can be called/run in our ActiveModule plugin after the route has been parsed. I decided to go with the name “Initializer”, in the sense that the module bootstrap setups up the stage and the module Initializer puts it all into action. Maybe not the most intuitive or best fitting name, but I don’t have a lot of time to wrestle with semantics… so it’ll do for now!

The Initializer accepts the module bootstrap as an argument in the constructor, in case I need to use any of it’s methods at a later time. I don’t have a use case for it right now, but I can see the module specific initializer classes benefiting from easy access to the active module’s specific bootstrap class. I define the initialize() method as final, just following the standard set in the BootstrapAbstract class, which defines the bootstrap() method as final. I try to err on the side of consistency.

Let’s look at an example of a module specific Initializer. Let’s assume we have a module in our application called “accounts”

You’ll see the similarity in structure to the module bootstrap class, but this class allows us to keep our module setup and our module initialization separate. The functionality remains the same! I think this is what was missing from some of the other solutions that I saw. We are now able to retain the power of the ZF bootstrapping and perform it for only the active module!

We’re getting close, but we’re not done yet. We need to go back and update some of the earlier classes. First of all, we’ll need to add a method to the Offshoot_Application_Module_Bootstrap, to add our Initializer class as a resource that can be autoloaded, as well as update the Offshoot_Application_Module_Bootstrap’s constructor to call this new method.

The last piece of the puzzle is to make our module initializer available in the active module plugin, so that we can call the initialize() method and subsequently initialize (i.e. boostrap) all of it’s module specific resources. Let’s go back and look at the routeShutdown() method of the Offshoot_Controller_Plugin_ActiveModule plugin.

publicfunction routeShutdown(Zend_Controller_Request_Abstract $request){$activeModuleName=$request->getModuleName();$activeBootstrap=$this->_getActiveBootstrap($activeModuleName);if($activeBootstrap instanceof Offshoot_Application_Module_Bootstrap){$className=ucfirst($activeModuleName).'_Bootstrap_Initializer';// don't assume that every module has an initializer...if(class_exists($className)){$intializer=new$className($activeBootstrap);$intializer->initialize();}}}

And there you have it folks! I would love to hear some feedback on this or any ideas for improvement. If people like it or are interested, I’ll see if we can get a full solution up on github in the near future.

Don’t worry about the stupid question anymore.
I managed to fix the problem:
- by adding resources.modules = “” on application.ini to add modules as resources
- or by putting ‘modules’ => array(), in the options resources in index.php

great job and very neat code. I appreciated the effort to go even further all the other proposed solution.
However I need still some hits. Everything seems to work properly except the initialiser class looks it doesn’t exists. I was wondering if you can at least add/show where you pur your files to understand what I’m missing. I’m pretty sure it’s matter of path probably but I’m getting stuck in understand where is the problem

I am somewhat new to Zend but I am performancoholic. Can you tell me what other places I need to add code (application.ini, Application/Bootstrap.php) etc in order to get this running. A sample code would be helpful.

that will ensure that ZF knows to load your modules. and as long as your include_path is set properly and your resource and plugin paths are correct it should all work. i’ll try to post a sample application.ini file shortly

Chris,
Very nice piece of work. I wold like to participate on getting it that one step further as you mentioned at the bottom – to get the full solution up on github.
Please let me know how I can join your task-force for this one.
Thanks
Martin

Nice work!!! Still have a couple of doubts, when I get the options at the module bootstrap with $this->getOptions() I still get both of my modules config items (i have 2 modules i’m testing with) instead of just the active module config file (module.ini). Am i doing something wrong or is it the expected behaviour??