How to bootstrap, autoload modules and classes with Zend framework
This post is for you that have read this quick start from Zend and our goal is to create a bootstrap like this one. We assume that you know how to create a project, layout, module, controller and action by using zf.bat, zf.sh or manually and further that you are able to create a helloworld application with structure as bellow (I used zf.bat)
application
configs
application.ini
layouts
scripts
layout.phtml
modules
default
controllers
ErrorController.php
HelloworldController.php
IndexController.php
forms
HelloWorld.php
models
views
filters
helpers
scripts
error
error.phtml
helloworld
hello.phtml
index
index.phtml
second
controllers
HelloworldController.php
IndexController.php
forms
HelloWorld.php
models
views
filters
helpers
scripts
helloworld
hello.phtml
index
index.phtml
Bootstrap.php
library
Zend
Foo
Bar.php
public
index.php
tests
We have now created two modules “default” and “second”. So far I can not create a project with default module inside folder modules so you need to move controllers, forms, models, views into default (create it first). However, the main purpose here is to show how to alter the Bootstrap that generated by zf.bat so that modules will be loaded and classes within modules, such as forms, models, can be autoloaded. In this example we will test for the form HelloWorld which is loaded in controller Helloworld. Here is the content of those files
default/controllers/HelloworldController.php
<?php class HelloworldController extends Zend_Controller_Action { public function init() { /* Initialize action controller here */ } public function indexAction() { // action body } public function helloAction() { $request = $this->getRequest(); $form = new Default_Form_HelloWorld(); if ($request->isPost()) { print $request->getParam('hello'); } $this->view->form = $form; } } ?>
default/forms/HellowWorld.php
<?php class Default_Form_HelloWorld extends Zend_Form { public function init() { $this->setMethod('post'); $this->addElement('text', 'hello', array( 'label' => 'Hello default:', 'required' => true, 'filters' => array('StringTrim') )); $this->addElement('submit', 'submit', array( 'ignore' => true, 'label' => 'Say', )); } } ?>
second/controllers/HelloworldController.php
<?php class Second_HelloworldController extends Zend_Controller_Action { public function init() { /* Initialize action controller here */ } public function indexAction() { // action body } public function helloAction() { $request = $this->getRequest(); $form = new Second_Form_HelloWorld(); if ($request->isPost()) { print $request->getParam('hello'); } $this->view->form = $form; } } ?>
second/forms/HelloWorld.php
<?php class Second_Form_HelloWorld extends Zend_Form { public function init() { $this->setMethod('post'); $this->addElement('text', 'hello', array( 'label' => 'Hello second:', 'required' => true, 'filters' => array('StringTrim') )); $this->addElement('submit', 'submit', array( 'ignore' => true, 'label' => 'Say', )); } } ?>
default/views/scripts/helloworld/hello.phtml
second/views/scripts/helloworld/hello.phtml
<?php $this->form->setAction($this->url()); echo $this->form; ?>
The first step we will try to do is to make sure that we can load the modules. We start to alter Bootstrap.php What we need to do is telling Front Controller where our modules are located
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap { protected function _initDoctype() { } protected function _initApplication() { $this->bootstrap('FrontController'); $front = $this->getResource('FrontController'); $front->throwExceptions(false); $front->addModuleDirectory(APPLICATION_PATH . '/modules'); } } ?>
Be aware that this can also be done in bootstrap file (public/index.php). One can do that by adding follow
$frontController = Zend_Controller_Front::getInstance(); $frontController->addModuleDirectory(APPLICATION_PATH . '/modules');
Or add this line in application.ini that is generated by zf.bat
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
Now you should be able to navigate to http://yourserver/helloworld/hello or http://yourserver/second/helloworld/hello without any complain about “missing default module in front controller”. We got instead a fatal error which says that our form classes Default_Form_HelloWorld/Second_Form_HelloWorld is not found. The next is to enable autoloading of those form classes. To do that we start to edit Bootstrap.php again by adding init method _initAutoload() which will be called automatically
<?php class Bootstrap extends Zend_Application_Bootstrap_Bootstrap { protected function _initDoctype() { } protected function _initApplication() { $this->bootstrap('FrontController'); $front = $this->getResource('FrontController'); $front->throwExceptions(false); $front->addModuleDirectory(APPLICATION_PATH . '/modules'); } protected function _initAutoload() { // BLOCK 1 // this is a fallback to autoload our own classes in library $autoLoader = Zend_Loader_Autoloader::getInstance(); $autoLoader->setFallbackAutoloader(true); // BLOCK 2 // this is for loading forms classes in default module $autoloader = new Zend_Application_Module_Autoloader(array( 'namespace' => 'Default_', 'basePath' => APPLICATION_PATH . '/modules/default', 'resourceTypes' => array( 'forms'=>array('path'=>'/forms', 'namespace'=>'Form') ) ) ); // BLOCK 3 // this is for loading form classes in second module $autoloader = new Zend_Application_Module_Autoloader(array( 'namespace' => 'Second_', 'basePath' => APPLICATION_PATH . '/modules/second', 'resourceTypes' => array( 'forms'=>array('path'=>'/forms', 'namespace'=>'Form') ) ) ); } } ?>
BLOCK 1:
By default Zend_Loader_Autoloader will only load Zend classes. This code block tells Zend_Loader_Autoloader to include class files in arbitrary libraries. For instance, when you create a new “Bar”
$bar = new Foo_Bar();
It will try to include the file by looking in includepath/Foo/Bar.php and in our case it will include the file Foo/Bar.php
BLOCK 2 & 3:
Since Zend_Loader_Autoloader replaces _ in classname with / when loading the class file. But this will not work for classes in module folder. In these two code blocks we register the namespace and the corresponding path, ie if a class start with Second_ then it should look for the class file in application/modules/second/. When loading the form, in our case, it will add basePath and path, ie it will look for the class file in applicaton/modules/second/forms/.
Be aware that the namespace for your classes in forms and classes in library should distinct, for instance if I create a Foo class for module second in my library I should start with application name (helloworld) Helloworld_Second_Foo instead of Second_Foo which has the start namespace for the form, ie start-namespace conflict. I hope that this is the answer you are looking for …
Marvellous article you have created here! The world wide web is full of horrid authorship and I was taken hold of by your lucidity. Your closings are dead-on and I will forthwith subscribe to your rss feed to stay up to date with your up approaching postings. Yes! I admit it, your authorship style is unbelievable and i will now work harder on improving mine.
I want to quote your post in my blog. It can?
And you et an account on Twitter?
Thx guys, I hope that I have time to write more often …
@Picturito: yes, you can quote my post. And sorry I am not active on Twitter. As you can see I don’t have much time to write …