Modular applications in ZF 1.8
Modular applications are applications where big chunks of functionalities are encapsulated in module packages which can be easily shared between applications with minimal fuss. Although modules have existed in ZF for a long time, it is not really possible to reuse modules without adding a lot of glue to integrate the module with the application. The new autoloader and module bootstraps make this task easier.
The problems
These are some of the main considerations when integrating a module into an existing project:
- Initializing the components used by the module controllers.
- Making the module resources available to the rest of the application, e.g. models, forms, helpers, plugins.
In the olden days, the former is addressed by editing the application bootstrap, and the latter by shoving all classes used by module controllers in a namespace and copying them into the application library. Thus, integrating modules isn’t really possible without some knowledge of the innards of the module. Both of these are addressed (the latter indirectly) by module bootstraps.
(There is another concern: serving public module assets like images, css and js files. I have a module in my googlecode project that addresses this, but still the best way to solve this is to copy the assets to the public directory.)
Writing module bootstraps
Module bootstraps are no different from application bootstraps. Like the application bootstrap, they can have resource methods (the _init*() methods) which are executed in the order they are defined, and also resource plugins. The module bootstrap classes should be named <module>_Bootstrap, must extend Zend_Application_Module_Bootstrap and must reside in a file named Bootstrap.php under the module directory.
`-- application | `-- controllers | `-- models | `-- views | `-- modules | | `-- foo | | `-- controllers | | `-- models | | `-- views | | `-- Bootstrap.php ⇐ class Foo_Bootstrap extends Zend_Application_Module_Bootstrap | `-- Bootstrap.php ⇐ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap `-- public
There is some confusion regarding the resources initialized by the module bootstraps. Many people think that these resource methods and plugins are executed only if the request maps to a controller belonging to this module. This is not the case. As the sequence diagram below shows, these methods and plugins are executed well before the front controller is dispatched. Thus, any code in the module bootstraps affects the whole application. This is contrary to most people’s expectations, mostly because the term module bootstrap implies otherwise. Rather than a module bootstrap, one should think of them as scattered parts of the application bootstrap that are organized per module. This limits the usefulness of the module bootstrap to registering plugins, helpers, helper paths and routes as they are the things that are unlikely to conflict with other bootstraps. However, these are plenty useful by themselves, and module-specific behavior can be defined through a plugin registered by the module bootstrap. But that’s a topic for another post.

The diagram above could explain how the Modules resource plugin works far better than I could with words. Some things you should note:
- The resource plugin depends on the front controller for the module list and their locations. It does not directly pull the front controller instance from Zend_Controller_Front but rather from the FrontController resource stored by the application bootstrap. So you should either have an _initFrontController() method in your application bootstrap that returns the front controller instance or register the FrontController resource plugin. Also, be sure to register the module controller directories with the front controller. Your application.ini (if you use zf) should have these lines:
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" resources.frontController.moduleDirectory = APPLICATION_PATH "/modules" resources.modules = On ; this can be anything, really. the value passed here is ignored anyway
- The resource plugin loops through every module directory and looks for a Bootstrap.php file. If it is not found, the module resource autoloader will NOT be registered, so if you want to make available the helpers, forms, models, etc. in a module, make sure you make a module bootstrap for it even if it is empty.
- I’ve mentioned the module resource autoloader. This is the class which allows us to use module-namespaced classes liberally in our application. By default, it registers namespaces for forms, models, view helpers, plugins, and a few more. So in the foo module, you can define a class Foo_Form_Login extends Zend_Form in the file application/modules/foo/forms/Login.php. You can then instantiate this class anywhere without doing anything special, whereas before you might have to copy the class to the library directory or add the forms directory to the include path.
A ZF module repository?
It would really be awesome if there were a module repository for ZF where we can all pull pluggable modules from and immediately augment the functionality of our application. I started the modular-zf project for this reason. This was nearly impossible before because of the unassuming nature of ZF, but with Zend_Application and the Modules resource plugin specifically, we can now expect ZF applications to follow the same general structure. This makes it a lot easier to write modules that will more or less work in other applications with minimal fuss. One big issue that needs to be addressed though is the module-specific initialization. There needs to be a standard way for a module bootstrap to hook into the various stages of dispatch so that module-specific behavior can be defined. Also, I think there should be a way for a module to bootstrap other modules if it relies on another module’s resources. I hope more people would adopt these new features immediately so we could start sharing our modules.
Thanks for the great article. Could you please comment on the following: “module-specific behavior can be defined through a plugin registered by the module bootstrap”.
I know you have saved this for another blog post but a brief outline of how you would do this.
Thanks
This is the first really clear article I read about the modules feature of ZF… now my app works… and I know why! Thank’s a lot!