How to use dependency injection in Zend Framework?

Viewed 8461

Currently I am trying to learn the Zend Framework and therefore I bought the book "Zend Framework in Action".

In chapter 3, a basic model and controller is introduced along with unit tests for both of them. The basic controller looks like this:

class IndexController extends Zend_Controller_Action 
{
    public function indexAction()
    {
        $this->view->title = 'Welcome';
        $placesFinder = new Places();
        $this->view->places = $placesFinder->fetchLatest();
    }
}

Places is the model class that fetches the latest places from the database. What bugs me here: how should I test the IndexController in isolation? As the reference to the Places class is "hardcoded", I cant inject any stubs or mocks in IndexController.

What I would rather like to have is something like this:

class IndexController extends Zend_Controller_Action 
{
    private $placesFinder;

    // Here I can inject anything: mock, stub, the real instance
    public function setPlacesFinder($places)
    {
        $this->placesFinder = $places;
    }

    public function indexAction()
    {
        $this->view->title = 'Welcome';
        $this->view->places = $this->placesFinder->fetchLatest();
    }
}

The first code sample I posted is most definately NOT unit test friendly as IndexController cannot be tested in isolation. The second one is much better. Now I just need some way to inject the model instances into the controller objects.

I know that the Zend Framework per se has no component for dependency injection. But there are some good frameworks out there for PHP, can any be used together with Zend Framework? Or is there some other way to do this in Zend Framework?

5 Answers

I'm currently working on the same question, and after deep research I've decide to use Symfony Dependency Injection component. You can get good info from official website http://symfony.com/doc/current/book/service_container.html.

I've build custom getContainer() method in bootstrap, which resturns now service container, and it simply can be used in controllers like

public function init()
{
    $sc = $this->getInvokeArg('bootstrap')->getContainer();
    $this->placesService = $sc->get('PlacesService');
}

Here you can find how to do that http://blog.starreveld.com/2009/11/using-symfony-di-container-with.html. But I changed ContainerFactory, because of using Symfony2 component, instead of first version.

Related