Easy Setter Injection in Zend Framework 2

Want to learn how to have initialized objects with minimal code and nearly no hands-on configuration in Zend Framework 2? Come learn about setter injection.


Recently I’ve been learning loads, thanks @ocramius, about dependency injection, and how it’s implemented in Zend Framework 2. Despite being conversant with constructor injection, I’ve not been as familiar with setter injection as I’d like to be.

I’ve been learning how to do it, through ServiceManager-aware interfaces, and will share how it’s done, in today’s post.

For configuring objects, reused throughout the application, I’ve found it to be nothing short of amazing. With next to no code, one Module configuration setting, along with the magic of OOP, classes are suitably initialized throughout the application, without any hands-on configuration on my part.

Whilst Zend Framework 2 is great without this. When you start using setter injection, it becomes so much more. In today’s post, I’ll take you through an example which uses setter injection to ensure that the AuthService, or authenticated user object is always available to a class and any of its descendents.

NOTE: There are likely better ways than how I’ve implimented it. But that’s for another day. It makes for a simple example.

How It’s Implimented

There are 3 things which you need to do to have a dependency automatically injected, by Zend Framework, into your class.

  1. Define an interface. This keeps things neat and tidy and really just ensures that your class has a function which can be called by the service manager, to inject the desired dependency
  2. Implement that interface in your class
  3. Define an initializers element in the getServiceConfig method of your module’s Module.php class

Let’s do all three, where I want to have a simple object injected into my class.

The Interface

namespace MaltBlue\Table;

use Zend\Authentication\AuthenticationService;

interface AuthAwareInterface
{
    /**
     * @param $authUser
     * @return mixed
     */
    public function setAuthUser(AuthenticationService $authUser);

    /**
     * @return mixed
     */
    public function getAuthUser();
}

Here I’ve created a simple interface with two methods, setAuthUser which accepts a AuthenticationService object, and getAuthUser. They set and return the auth user object in the implementing class, callable by the ServiceManager.

Implimenting the Interface

use MaltBlue\Table\AuthAwareInterface;

class CacheableTable implements AuthAwareInterface
{
    protected $authUser;

    public function setAuthUser(AuthenticationService $authUser)
    {
        $this->authUser = $authUser;
    }

    public function getAuthUser()
    {
        return $this->authUser;
    }
}

This class, is intended as a base implementation of the TableGateway pattern, which impliments the new Interface.

Initializers Configuration

MaltBlue\Table\AuthAwareInterface

public function getServiceConfig()
{
    return array(
        // ... existing code ...
        'initializers' => array(
            'AuthAwareInterface' => function($model, $serviceLocator) {
                if ($model instanceof AuthAwareInterface) {
                    $authObj = $serviceLocator->get('MaltBlue\AuthService');
                    $model->setAuthUser($authObj);
                }
            }
        ),
    )
}

Finally, we have the module configuration in Module.php. Here, in an initializers element, I’ve specified the interface name and defined what will happen, when a class implimenting it is encountered by the ServiceManager, via a closure.

Simply, if the class implements AuthAwareInterface, then MaltBlue\AuthService is retrieved and set in the object via calling setAuthUser. What I like about it is that there’s not a lot of work, for a lot of gain, and it’s very clear, very structured in the implimentation.

Now, just retrieve your instantiated objects, via the ServiceManager, and they’ll have the dependencies injected for you.

A Word of Warning

I need to point out that you should use setter injection with some care, always being very methodical about it. If the configuration were disparate, or not managed through a framework, it would get very difficult to keep track of what was being injected, when, and where, leading to a very hard to maintain application.

The way that Zend Framework 2’s designed, having a specific &‘initializers’ section of the getServiceConfig return array, does a lot of this for you. If you manage setter injection in a single location, as Zend Framework 2 can, to me that’s fine. Because you only have one place to look to know what’s being injected. But please bear this in mind when using it.

Why the Warning?

The reason for this warning was because of a Twitter conversation I had with Ocramius, which started as follows:

@maltblue yes, magic works until it works fine - that’s common. The problem comes up when it doesn’t work 😉 #php #di

I’ll write more about the downside of setter injection soon. But for the time being, please handle with care. A big thanks to Ocramius for being a great mentor on this topic.

Over To You

So, what do you think? Have you experience with it already? What do you think? Are you keen to use them, despite the objections? Share your feedback in the comments.

Want to Know More?

If you’d like to know more about setter injection vs. constructor injection, here are some excellent links:


You might also be interested in these tutorials too...

Thu, Apr 4, 2013

Zend Framework 2 Forms - Simple and Available Everywhere

In Zend Framework 2, so much has been changed, updated and improved - with Forms receiving a lot of attention. In this post, I show you a simple, flexible and powerful approach to compose and use them everywhere in your applications.

Tue, Jun 5, 2012

Zend Form Mastery with Zend Config – Part 4 Configuring Zend Validators

Welcome to the fourth and final part in the Zend Form Mastery with Zend Config series. Previously we looked at the basic form options, element and form wide prefixes, filters and element options. In this installment, we’re going to look at configuring Zend Validators via our XML config.

Fri, Apr 27, 2012

Zend Form Mastery with Zend Config - Part 1 Custom Filter Paths

When you’re working with Zend Form you keep your configuration as much out of code as you can - right? Well, if you’ve been working withZend Form for more than a little while, you know that Zend Config really makes that pretty simple - well, some of the time. In this series we look, comprehensively at how to do it all with Zend_Config.

Mon, Jan 9, 2012

Beginning cloud development with cloudControl – Part 4 – Memcache

Here we are at part four of the Beginning Cloud Development with cloudControl series and in this part, we’re adding Memcached support. In part one of the series, we laid the foundation for the application and got up to speed with what cloudControl is, why it works and how to get started using it.

Then in part two, we started to flesh out the application that we started building in part one and added MySQL support to it. We showed how to work with cloudControl to manage the key requirements, such as enabling MySQL support, connecting to the MySQL database and keeping the database up to date from a maintenance perspective (creating the database schema and loading data in to the database).

Then in the third part of the series, we replaced MySQL with mongoDB support. Now, in this, the third part of the series, we’re going to finish up with adding Memcached support. As the core of the work’s already been done in the application, this tutorial will be shorter and simpler than the previous three. So, get out the code that you worked through from part 2, or download a copy of it from the github repository and let’s get started.


Want more tutorials like this?

If so, enter your email address in the field below and click subscribe.

You can unsubscribe at any time by clicking the link in the footer of the emails you'll receive. Here's my privacy policy, if you'd like to know more. I use Mailchimp to send emails. You can learn more about their privacy practices here.

Join the discussion

comments powered by Disqus