Slim controllers are easier to test, encourage the DRY principle and force business logic back into the model layer where it belongs.
In this first article, I’ll be looking at a quick way to de-bloat Zend Framework Action Controllers by using an Action Helper to automatically instatiate models and assign them to properties in the controller and view.
Lather, Rinse, Repeat
Controller actions often perform mundane, repetitive tasks. Checking for required parameters, creating objects and assigning variables (again and again) eats up line after line of code in a typical controller.
Using the address book example, a simple action in our Contact controller might look something like this:
class ContactController extends Zend_Controller_Action { public function viewAction() { // check that we have a contact ID, otherwise redirect to index if ( !$this->_hasParam( 'id' ) || !Contact::exists( $this->_getParam( 'id' ) ) ) { $this->_helper->FlashMessenger( 'No contact specified or contact does not exist.' ); $this->_redirect( 'contact' ); } // lookup and instantiate the contact object $contact = Contact::find( $this->_getParam( 'id' ) ); // assign contact to view $this->view->contact = $contact; } }
A few things are happening here:
- First, we check to see if the ‘id’ param exists in the request.
- Then we use our model’s static exists() method to check that the contact ID corresponds to a real contact.
- The contact object is then looked up using a static finder method.
- …and finally we assign the contact to the view.
The exact code will vary depending on your model implementation, but this sort of process is pretty typical in my experience. In many actions, that’s all that’s required: the view then does its thing on the contact object that it’s been given.
Pretty boring stuff and chances are some or all of the above will be repeated in a handful of other actions in the same controller. That’s a “code smell” if ever I smelled one.
By automating these repetitive operations, there’s an opportunity to substantially reduce the size of our controllers without losing any functionality.
The Action Helper
Fortunately, Zend Framework has the perfect tool for this kind of job: an Action Helper.
By tapping into the preDispatch() hook provided and making a few basic assumptions, we can look for models specified in the request, instantiate them and then assign them to properties in both the action controller and the view.
Here’s the basic action helper class, which I’ve called “ModelWatcher”:
<?php class Dog_Zend_Controller_Action_Helper_ModelWatcher extends Zend_Controller_Action_Helper_Abstract { /** * @var string */ protected $_controllerName; /** * @return void */ public function preDispatch() { $request = $this->getRequest(); $this->_controllerName = $request->getControllerName(); $this->_view = $this->_actionController->view; try { $model = $this->_getModel(); // assign to the controller and view $this->_actionController->{$this->_controllerName} = $model; $this->_view->{$this->_controllerName} = $model; } catch ( Exception $e ) { return; } } /** * @return object The instantiated model object */ protected function _getModel() { $request = $this->getRequest(); if ( NULL === $request->getParam( 'id' ) ) { throw new Exception( "ID parameter not found in request" ); } $id = $request->getParam( 'id' ); // attempt to find and instantiate the model object $modelClass = ucfirst( $this->_controllerName ); $model = $modelClass::find( $id ); return $model; } }
Important: Don’t forget that you’ll need to add the helper to your bootstrap for this to work. Something like this should do the trick:
Zend_Controller_Action_HelperBroker::addHelper( new Dog_Zend_Controller_Action_Helper_ModelWatcher() );
When the helper’s preDispatch() method is called, it checks the request for the “id” parameter and attempts to find and create the model object. In the case of our address book, a request URL like http://www.example.com/contact/id/123 would try to retrieve an object of the class Contact whose ID is 123.
We wrap the call to _getModel() in a try…catch block to deal with two scenarios:
- When no ID parameter exists in the request or
- No record exists for the given ID
The latter assumes that the find() method will throw an exception if the record is not found.
If the lookup is successful, the newly created object is assigned to the controller and view with a property named after the controller. So with our address book example, you’d access the contact object using $this->contact from within both the controller and the view.
On failure, we do nothing – leaving the action controller to implement its own logic for dealing with non-existent objects.
The Final Weigh-In
All this means we’re left with a significantly slimmer controller action:
class ContactController extends Zend_Controller_Action { public function viewAction() { // check that we have a contact object if ( !isset( $this->contact ) ) { $this->_helper->FlashMessenger( 'No contact specified or contact does not exist.' ); $this->_redirect( 'contact' ); } } }
The controller action now only needs to check that a contact object has been created by the action helper. There’s no need for it to get its hands dirty with the request params, object generation or assigning variables to the view as it’s already been done.
This approach does require an adherence to some naming conventions… primarily that the model class name has to mirror the controller name and the identifying parameter is always passed as “id” in the URL. Provided they aren’t too wacky, it should be reasonably easy to re-jig the code to suit any conventions of your own.
Further Weight Loss
A slightly more flexible approach is to use verbose ID parameters like “contact-id”. This gives you the ability to have model classes which don’t match the controller name and also allows multiple models to be instantiated by the ModelWatcher in one request, both of which can be useful. I use something similar in my own implementation.
You might also want to consider adding other logic in to the ModelWatcher helper like record locking or fine-grained access control. Even if you decide to separate these activities into a separate helper class, you can still use the models inserted into the controller rather than going back to the request parameters again. Just make sure that the ModelWatcher is added to the action helper plugin stack before any helper that relies on it or the models it creates.
Final Thoughts
Hopefully it should be fairly clear that this simple action helper has the potential to dramatically reduce the amount of boiler plate code in your controllers. Eagle-eyed readers might also have noticed that automatically assigning models to the controller is a feature of CakePHP.
Look out for future posts where I’ll be discussing more ways to de-clutter and cut down your controllers.
P.S. Thanks to Rob Allen, Matthew Weier O’Phinney, Pádraic Brady, Wenbert Del Rosario and others for retweeting/linking to my first post

Great article!
Thank you and congratullations.
That was really helpful! I will try to use this method as it does make a lot of sense. Thanks!
No problem!
Glad you enjoyed it.
Cool post. Curious, how are you statically instantiating the find() method in the early example? Zend_Db_Table_Abstract::find() is a non-static method, so how are you overriding that behavior?
Jason
Hi Jason – thanks for the comment.
Ah, the find call was just pseudo code to illustrate the point.
I only use Zend_Db_Table in very simple apps… for more complex cases, I use a data mapper to split persistence logic from business logic. It’s a bit more involved, but the end result is much cleaner… it’s on the “to-blog” list
I just wanted to say the following thing…. I’m not a programmer, but I was searching some tips about a diet and I digg over your blog. And I read with such intensity the first half, that I really thought was about how to lose some weight.
)) I even looked for some Zend tricks/book for weight
))) I know stupid… I just wanted to share this with you. Best regards and keep it fun working
Steve,
“A slightly more flexible approach is to use verbose ID parameters like “contact-id”. This gives you the ability to have model classes which don’t match the controller name and also allows multiple models to be instantiated by the ModelWatcher in one request, both of which can be useful. I use something similar in my own implementation.”
Could you provide a sample of this?
I’m trying to imagine how you would do this without doing a bunch of if logic.
Thanks.