Lately I've been working on a site based on the Zend Framework. It's
been a good chance to get more intimate with ZF, learning the inner
workings and quirks of the framework. Today I came across the question
of how to do dependency injection for your controllers - I was looking
for a way to rid the code of the 'new' keyword as well as static
methods, coupling things more loosely.
Controllers aren't meant to override the __construct() method in ZF -
sure you can do it, but there are meant to be better ways. That leads to
the question: how? Well, if you do have a look at the __construct()
method of Zend_Controller_Action, you'll notice that it takes three
parameters. The last one is the interesting one here: it's an array
called invokeArgs. This should immediately set you off testing what gets
passed in - a bunch of goodies, it turns out. Among other things, you'll
be getting a copy of the Bootstrap object.
ZF Controller Dependency Injection, #1
The above leads to the first, not too good way of injecting things. Just
stick whatever you want injected into the bootstrap object - your
controller has access to that through the invokeArgs parameter. That's
not a very good solution though, as you'll be breaking the Law of
Demeter: your controller
needs to know that your injected param sits inside the bootstrap
element, so you'll be accessing the injected elemented indirectly. Not
nice.
ZF Controller Dependency Injection, #2
I googled a bit and came across Dependency Injection and Zend Framework
Controllers,
which has a nice solution to the problem. As the param name suggests,
invokeArgs can be modified - you can add to the args to your heart's
content. You need to use the setParam() method of
Zend_Controller_Front - so, in the bootstrap object for instance, you
can do the following:
$front = Zend_Controller_Front::getInstance();
$front->setParam('factory', new MyFactory);
Your object will then get passed to the controller in the invokeArgs
array. You can access this either through
\$this->_invokeArgs['factory'] or the getInvokeArg() method of
Zend_Controller_Action - the latter being preferable.