Zend ServiceManager - Web Application Development Simplified

The Zend ServiceManager simplifies the web application development process by making configuration a breeze. In this, the 4th post introducing Zend Framework 2, you will learn what the ServiceManager is how to use it and how it simplifies applicaiton development time.


Summary

The Zend ServiceManager simplifies web application development in a number of ways, primarily by making configuration a breeze. In this, the 4th post introducing Zend Framework 2, you will learn what the ServiceManager is, how to use it and how it simplifies app development time.

Getting Started

Welcome to the Zend Framework 2 Introduction 4-part series finale. Recapping the series so far:

In this, the fourth and final installment, we look at the ServiceManager component. This is a highly critical, but potentially misunderstood, aspect of the framework. One that, when understood, makes the rest of the framework a breeze (well, close).

From reading various blog posts and comments, it’s often believed that the ServiceManager over-complicates the entire framework. Some people say it’s an attempt to: out Java Java.

I - completely - disagree!

I believe that it’s this fundamental concept that makes the framework simpler, that makes developing web applications with it easier, less stressful and more maintainable. I hear scoffing, I hear peals of laughter, I hear the embers of a flame war being stoked to burn me alive at the stake.

To support my point, in this post, I’m going to do 3 things:

  1. Give you a good introduction to what the ServiceManager is
  2. Show you how to configure it
  3. Step you through a hands-on example of using it

Stay on to the end as we consider the critical question.

What is the ZF2 ServiceManager

Put in simplest terms, the ZF ServiceManager component is an implementation of the Service Locator pattern; in short a simple application registry that provides objects (in a lazy loaded fashion) within application as needed - but with some nice additions.

It allows us to perform Inversion of Control (IoC), which allows us to remove dependencies and tight coupling from our applications. The result of this, when combined with dependency injection and simple event management is applications that are simpler to build, test and maintain.

You can try to think of it in more complex ways if you’d like to, but really there’s no need. Where it does get a little complicated however, at least initially, is how it’s all configured. I grant you, that does take a bit of getting your head around - but not too much.

How Do You Configure It?

The Service Manager is able to be configured in 7 key ways. These are:

  • abstract factories: This is one of a fully qualified class name, or an object implementing Zend\ServiceManager\AbstractFactoryInterface. This approach provides flexibility and extensibility to the ServiceManager. If, on request, the ServiceManager isn’t able to locate a class, it iterates through the registered Abstract Factories to see if any of them are able to satisfy the object request.
  • factories: A fully qualified class name, PHP callable object, or a class implementing Zend\ServiceManager\FactoryInterface. These handle the dependency injection aspect of the ServiceManager.
  • invokables: A string, which is a fully qualified class name, able to be instantiated later.
  • initializers: A fully qualified class name, PHP callable object, or a class implementing Zend\ServiceManager\InitializerInterface. If listed, will be applied to objects retrieved from the Service Manager to perform additional initialization.
  • configuration classes: This is a class implementing Zend\ServiceManager\ConfigInterface. Classes implementing this interface are able to configure the Service Manager, performing the initialization that is covered in these seven points.
  • aliases: An associative array of aliases to services (or aliases to aliases). It may not seem like a good idea, but from a readability perspective, I believe this is an excellent technique to have available.
  • shared: Depending on your application or circumstance, you may want to provide single access to an object, or return a new copy on each request. By default, when an object is retrieved from the Service Manager if it’s the first request, the object is instantiated and returned. If it’s any after that, the original object is returned.

What’s really great about this approach, is that each module loaded or created can also be a service provider. To do so, they need to do one of the following:

  1. Implement the Zend\ModuleManager\Feature\ServiceProviderInterface
  2. Implement getServiceConfig()

As the manual indicates, this function needs to return:

  1. An array or Traversable object
  2. The name of a class implementing Zend\ServiceManager\ConfigInterface
  3. An instance of either Zend\ServiceManager\Config, or an object implementing Zend\ServiceManager\ConfigInterface.

A Simple Code Example

I’ve been creating a Generic module throughout this series and in it, I’ve added a simple model that lets me retrieve information from a SQLite database. So what better choice to use for an example that that.

In module/Generic/Module.php, I have an implementation of getServiceConfig which is as follows (formatted for readability):

// Add this method:
public function getServiceConfig()
{
    return array(
        'factories' => array(
            'Generic\Model\AlbumTable' =>  function($sm) {
                $tableGateway = $sm->get('AlbumTableGateway');
                $table = new AlbumTable($tableGateway);
                return $table;
            },
            'AlbumTableGateway' => function ($sm) {
                $dbAdapter = $sm->get(
                    'Zend\Db\Adapter\Adapter'
                );
                $resultSetPrototype = new ResultSet();
                $resultSetPrototype->setArrayObjectPrototype(
                    new Album()
                );
                return new TableGateway(
                    'album',
                    $dbAdapter,
                    null,
                    $resultSetPrototype
                );
            },
        )
    );
}

You can see here I’m configuring it with the &’factories&’ option. In there I have two options:

  • Generic\Model\AlbumTable
  • AlbumTableGateway

Both of these use anonymous functions for the configuration. Now, let’s pop over to where they’re used in the IndexController. The default action, Index, goes as follows:

public function indexAction()
{
    return new ViewModel(array(
        'albums' => $this->getAlbumTable()->fetchAll(),
    ));
}

It calls the getAlbumTable method, which is as follows:

public function getAlbumTable()
{
    if (!$this->albumTable) {
        $sm = $this->getServiceLocator();
        $this->albumTable = $sm->get('Generic\Model\AlbumTable');
    }
    return $this->albumTable;
}

Now that we have the configuration and usage together, let’s see how it works. In indexAction, we set a variable &’albums&’, which is the result of calling the fetchAll method on the object returned from the getAlbumTable method.

In the getAlbumTable method, we retrieve a copy of the application Service Locator object via the getServiceLocator method. We then retrieve the AlbumTableGateway object, by passing the name, as a string, to the get method of the Service Locator object.

Assuming the object is in the Service Locator registry and suitably configured, it’s then passed as the return value from the function, allowing us to call the method on it.

Looking back in to the configuration of the object we see it as follows:

'AlbumTableGateway' => function ($sm) {
    $dbAdapter = $sm->get(
        'Zend\Db\Adapter\Adapter'
    );
    $resultSetPrototype = new ResultSet();
    $resultSetPrototype->setArrayObjectPrototype(
        new Album()
    );
    return new TableGateway(
        'album',
        $dbAdapter,
        null,
        $resultSetPrototype
    );
},

We see we have a factory configuration, labelled AlbumTableGateway configured by an anonymous function.

You can see we first we use the ServiceManager to get access to the application-wide database adapter (I’ll cover it in a sec), by retrieving the object configured with the string Zend\Db\Adapter\Adapter.

We then create a new ResultSet object and set the prototype to be an Album object. When that’s done, we then create and return a new TableGateway object, specifying the type, database adapter and result set prototype.

Now, I’m deliberately skipping over delving in to the intricacies of the Zend_Db class here - as it’s really, a bit outside the purposes of this post. But I encourage you to give it a good read in addition to what you read here.

Now, for the final part, in config/autoload/global.php I have the following configuration:

$dbDSN = 'sqlite:' . dirname(__DIR__) .
    '/../data/databases/zf2skeleton.sq3.sqlite';

return array(
    'db' => array(
        'driver' => 'Pdo',
        'dsn'    => $dbDSN,
        'driver_options' => array(
            PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
        ),
    ),
    'service_manager' => array(
        'factories' => array(
            'Zend\Db\Adapter\Adapter'
                => 'Zend\Db\Adapter\AdapterServiceFactory',
        ),
    ),
);

You can see how the Database adapter is made available, configured using the same convention - allowing me to query a SQLite version 3 database throughout the application.

Don’t forget, all code is available for download from the Malt Blue Github repository. Grab a copy of it and tell me what you think.

What We Have Learned?

This process of stepping through the configuration and usage of the ServiceManager has shown us X things:

  1. Configuration Is Simple: Whilst a bit involved (because of all the locations where configurations can be located) it actually is simple because it follows a clearly defined set of conventions and stored in a standard set of locations.
  2. It’s Easy to Debug: By having standard conventions and locations, we can track configurations in the application logically and systematically.
  3. It Works with Across Modules: Whereas in Zend Framework 1, we had to jump through hoops to work with multiple modules, in ZF2 it’s all baked in. Just follow the conventions and it works.
  4. Applications Are More Dependable: This is a bit of a reiteration of the previous points. But by being able to configure applications reliably, simpler, in a readily debuggable manner, you spend less time and effort, effort which can be spent more meaningfully in other aspects of development (and your business).
  5. Easier to Maintain: When applications as more consistent, predictable, debuggable, logically (in my mind if nowhere else), they’re easier to optimise. Why? Because you’re working with a known quantity. Possibly a little “boring” but following convention makes adding new components quicker and more predictable. Being a maintainer, you know how applications hang together, you know where to look, the options which can be used, how to override them and so on.

Does it Really Make Development Simpler?

This is the burning question in this post. Does it really make web application development simpler? In short, yes. Now, at first, there’s a lot to cover, there’s a lot to learn. I grant you that.

There’s the 7 points mentioned above and you have to work with the different ways in which each work. Fine - I agree it does require work.

But think about any skill you’ve learned. Whether it was riding a bike, learning calligraphy, building running fitness, or what I’m doing - learning German.

At first it requires effort, it requires discipline and it requires concentration. It’s not easy, sure. But with time, this new skill makes doing what you used to do much simpler, such that you do more in less time, with less effort, with less concentration.

Consider the amount of work that went in to Zend Framework 1 applications and configuring them - especially integrating modules and the associated configurations.

As Evan Coury well said - they sucked!

There was the application.ini file, the module configuration that you could choose from a number of good implementations to get it to work, you could roll your own option and more.

Now, we have the option to spend some time learning, but with the result of ultimately writing cleaner applications, which are simpler to maintain both in terms of time and effort.

We’ll have applications which are much more:

  • Flexible
  • Testable
  • Configurable
  • Optimizable

I believe, therefore, it’s worth the investment of your time to learn. I believe it really is a blessing (potentially in disguise). I’m a learner, like you. So I want to know what you think, if you disagree with me. If you do, comment and tell me.

Get the Code

The code for this post - and all the posts in the Zend Framework 2 introductory series - is available on the Malt Blue GitHub account. I encourage you to clone a copy, play with it, comment on it, improve on it.

Over to You

Do you agree with me or want to flame me right now? If you agree with me that the ServiceManager will simplify use of Zend Framework 2, share with us how in the comments.

Alternatively, if you agree more with others, that it’s a pointless, over-complication, of what should be kept simple, say that too.

We can all grow through shared, constructive, opinions.


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

Wed, Jan 2, 2013

Zend Framework 2 Modules - The Application's Heart

Zend Framework 2 Modules - The Application's Heart

If I have seen further it is by standing on the shoulders of giants.

It’s a really exciting time at the moment with Zend Framework 2 gaining so much traction, after being stable for some time now.

Though I and countless others really enjoyed the 1.x series, it did leave some things to be desired - to be fair.

But the more I explore of the 2.x series, the more I honestly can say that I’m very impressed with it. It may not be as fast as the previous series, but with respect to development, there’s so much going for it it’s worth shouting about.

So it really is rewarding and exciting to begin covering all that it has to offer us. In part one of this series, I looked at a central concept of the revised framework - Dependency Injection.

Thu, Jun 20, 2013

\Zend\Db\Sql - Build SQL Where Clauses Easily and Efficiently

In this tutorial we’re working through the basics of \Zend\Db\Sql\Where, showing how to build SQL Where clauses for database queries. We’ll show how to create different predicates from simple to nested queries using of and, or, like, between and in conditions.

Wed, Aug 8, 2012

How to Use the Zend Form ViewScript Decorator In All Modules

If you’ve been using Zend Forms for any length of time, you’ll know just how flexible and configurable they are. There’s not much that you can’t do with them, But it’s not always easy and there are catches. Today we look at ensuring that module-based Zend Forms using the ViewScript decorator can always be initialised no matter what.


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