Matthew Weier-O’Phinney is one of the developers of the Zend Framework, and recently released a pastebin sample application to showcase the new Dojo integration released in 1.6.
One of the strengths of the Zend Framework is that there’s no one way to do anything. Sure, there’s ways that are set up by default and you can discover these defaults by reading the manuals, but you can get outside of those defaults pretty quickly and easily. For me, one of the hardest things to do is to imagine just how to use the powerful plugin system and excellent collection of extensible that Zend Framework comes with. Matt used both to great effect in this application and I want to learn how and why he made the design decisions he did in order to make my own work better.
I’m going to take a look at how Matthew did his implementation of the basic structure and some of the details and journal what I learned in the process of dissecting this sample application.
Let’s get right down into the nuts and bolts. The good news is that the way Matt does things makes your index controller nice and compact and usable in any context without having to monkey around a lot with configuring the path to your base directory as you move between different development, staging/testing, and production servers. It also enables you to use PHPUnit for unit testing without having to go through any contortions to get the right base libraries in place.
<?php defined('APPLICATION_PATH')- or define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application')); $paths = array( '.',- APPLICATION_PATH . '/models', realpath(APPLICATION_PATH . '/../library'), ); ini_set('include_path', implode(PATH_SEPARATOR, $paths)); require_once 'Zend/Loader.php'; Zend_Loader::registerAutoload(); include dirname(__FILE__) . '/../application/bootstrap.php'; Zend_Controller_Front::getInstance()->dispatch();
The next component you’re going to have to work on is the bootstrap PHP. There’s a couple things to point out. First, it re-implements the dirctory application path search. That’s because the bootstrap (and not the front controller) gets called to load all the libraries when we’re using PHPUnit for unit testing.
<?php defined('APPLICATION_PATH')- or define('APPLICATION_PATH', realpath(dirname(__FILE__))); defined('APPLICATION_ENV') or define('APPLICATION_ENV', 'development'); if (defined('BOOTSTRAP')) { require_once 'Zend/Loader.php'; Zend_Loader::registerAutoload(); } $front = Zend_Controller_Front::getInstance(); $front->registerPlugin(new My_Plugin_Initialize(APPLICATION_ENV)) ->addControllerDirectory(APPLICATION_PATH . '/controllers');
The last two lines are what we care about from the bootstrap. Remember that Zend_Controller_Front implements the Singleton pattern. Unlike the index.php file, which calls dispatch(); against Zend_Controller_Front, the bootstrap adds a plugin and a default controller directory. The plugin’s where the fascinating stuff happens for the front controller.
To set the basic defaults that most sample apps I’ve seen have all lumped into the front controller or bootstrap, Matthew’s pastebin application extends a Zend_Controller_Plugin_Abstract into a plugin aptly named ‘Initialize’.
class My_Plugin_Initialize extends Zend_Controller_Plugin_Abstract
The constructor’s pretty simple. It sets the environment variables including the application path (note that the environment variables assume production settings if another is not already set. Production settings should be the most tightly locked down with no errors or logging shown publicly), makes sure that the Zend Framework loads if it hasn’t already, and it grabs the Zend_Controller_Front instance and registers the Initialize plugin.
Plugins, in general, are a collection of functions that can be triggered automatically during the lifetime of an object. You can find out more about Zend_Controller plugins in the framework manual. The important thing about extending Zend_Controller_Plugin_Abstract is the functions that you overload — routeStartup, routeShutdown, dispatchLoopStartup, preDispatch, postDispatch, and dispatchLoopShutdown. If you don’t recognize the significance of these places within the controller’s dispatch loop, stop here and go review the Zend_Controller basics.
Matthew’s Initialize plugin doesn’t instantiate all of the database and other objects until he starts up the router. The routeStartup function is overridden as below:
public function routeStartup(Zend_Controller_Request_Abstract $request) { $this->initControllers() ->initLog() ->initCache() ->initDb() ->initView(); }
Each function is pretty clear on what it does, and you can add steps to each while keeping the freedom, segregation, and modularity intact — something that was definitely lacking in the way I was building my front controllers. The initControllers() function is a great example — in this case, it only has one line in it. In a larger, more complex application with an administration section, you could add the controller directories for modules in other folders.
Next time I have the chance to sit down and write, I’ll take a dive into the dojo stuff. Till then, you can download Matthew’s pastebin app at his site.
If you enjoy the content, consider subscribing to the feed(s).
Jump to comments