Richard Holloway Blog

Interface injection in Zend Framework 2

Posted in January 2013 by under zend-framework

Getting dependencies into services and models using Zend\ServiceManager can be done in a few ways. Using factories for example provides a simple way to inject a service into a controller, or some configuration into a service.

But this can become tedious and repetitive when injecting something like database connection settings or a configured ORM instance into models for 300 database tables. You would end up with a factory for each model and each factory would be almost identical. This amount of duplication clearly cannot be right.

Using interface injection can help in situations like this and is very simple to set up.

Let's assume we want to inject a configured instance of RedbeanPHP into each model. The configured instance is referred to in the service locator as Redbean\RedbeanService.

First we create an interface

<?php
// module/Application/src/Application/Model/RedbeanAwareInterface.php

namespace Application\Model;

use Redbean\RedbeanService;

/**
 * RedbeanAwareInterface
 *
 * Implement to inject Redbean into models
 */
interface RedbeanAwareInterface
{
    /**
     * Assign the Redbean service to the model
     *
     * @param RedbeanService $redbean
     * @return void
     */
    public function setRedbean(RedbeanService $redbean);
}

Then in the configuration you add an 'initializers' section to the 'services'

// config/module.config.php

// .. existing code ...
'service' => array(
    // ... existing code ...
    'initializers' => array(
        'RedbeanAwareInterface' => function($model, $serviceLocator) {
            if($model instanceof RedbeanAwareInterface) {
                $redbean = $serviceLocator->get('Redbean\RedbeanService');
                $model->setRedbean($redbean);
            }
        }
    ),
),

// ... existing code ...
            

Then in the Models you can use this interface to get RedbeanService injected by the service manager by simply implementing the interface.

<?php
// module/Application/src/Application/Model/ExampleModel.php

namespace Application\Model

use Redbean\RedbeanService;

class ExampleModel implements RedbeanAwareInterface
{
    /**
     * @var Redbean $redbean
     */
    protected $redbean;

    /**
     * setRedbean
     *
     * Assign Redbean
     *
     * @param RedbeanService $redbean
     * @return void
     */
    public function setRedbean(RedbeanService $redbean)
    {
         $this->redbean = $redbean;
    }

    // rest of class ...
}
            

Then whenever you use the ExampleModel, the service manager sees that it is an instance of RedbeanAwareInterface and injects RedbeanService into the model.