Configuring the ServiceManager with Abstract Factories
In this tutorial, we see how to use abstract factories to configure the ServiceManager in Zend Framework 2. It’s one of the simplest approaches available.
One of the best features about Zend Framework 2 is undoubtedly the ServiceManager; because it makes it almost painless to configure and retrieve services in a consistent and predictable manner, anywhere in your application, at any time.
But the catch is, there’s quite a bit to learn if you want to use it properly. As well as that, there’s quite a number of ways to use it. For example, you can instantiate classes using the invokables, factories and abstract factories elements as well as being able to use closures.
Now each of these approaches have their place, as well as the pros and cons. For example, you can use closures when you creating a prototype and invokables for classes which require no constructor arguments.
You could then use factories for classes which have dependencies, managed via constructor injection. But it’s not all sweetness and light. Let’s have a quick look at the negative points.
You can use closures, but your configuration won’t be cacheable, resulting in a bottleneck in your application.
And if you create an invokable or factory configuration for each class, you may end up creating quite a lot of classes (and an accompanying maintenance headache).
Despite these points, throughout the manual you’ll see a lot of reference to these three approaches.
So I don’t blame you if you thought that these were the only options. But there’s a better option, one which I only started to appreciate recently.
So I’ve made it the subject of today’s post - abstract factories. Abstract Factories in Zend Framework 2 allow you to implement the pattern of the same name. If you’re not familiar with it,
The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes. This pattern separates the details of implementation of a set of objects from their general usage and relies on object composition, as object creation is implemented in methods exposed in the factory interface.
What Are Abstract Factories?
In Zend Framework 2 specifically, abstract factories are a fallback instantiation method for the ServiceManager, allowing it to instantiate and return services if all of the other methods fail.
When a service is requested and the ServiceManager can’t find it, because you’ve not setup an explicit configuration for it, it will iterate through the configured abstract factories and see if one of them can provide a matching service.
Similar to the factories classes, abstract factories classes implements two interfaces:
As a result of these interfaces, they need to implement two methods:
canCreateServiceWithName returns a boolean value, confirming whether the class can return the service requested or not. If true, then createServiceWithName is called which carries out the instantiation of the service, returning the object requested.
Both of these methods take three parameters, a ServiceLocatorInterface object and two strings, commonly set as $name and $requestedName.
The ServiceLocatorInterface object, provides access to the ServiceLocator. So if you need other services, then you’re able to access them through it.
The $requestedName parameter is the service name being requested which, for today’s post, will be
A Working Example
Right, now that we’ve talked about what they are and why they’re good to use, let’s work through an example. Firstly we’ll create the class, then we’ll cover the Module.php configuration required.
The first thing we need to do is to bring in the required use statements, specifically AbstractFactoryInterface and ServiceLocatorInterface. The other two are there as I’ve based this example on an existing codebase.
Next, we need to ensure that the class always implements AbstractFactoryInterface.
Now we create the canCreateServiceWithName function. First, we’re going to inspect the $requestedName argument. For this example, I’m attempting to retrieve a service called “YourModule\Table\MyUserTable”.
As this is a TableAbstractGateway file, responsible for instantiating table classes, we first check if the service name ends in Table. If it does, we then check if the class exists. If it does, we return true, otherwise false. For the rest of the example, we’ll assume that it does.
Next we implement the createServiceWithName method. This one handles instantiation and return of the service object. As the canCreateService method checks if we can do it, I’ve not checked the file name pattern again.
Instead I’ve checked if the class exists and if so, instantiated and returned it. The net result is that one class can now handle instantiation of nearly any object of a specific type; just like the abstract factory pattern is meant to do.
How Do You Configure Them
Now that we’ve setup the class to instantiate all of our table objects, we need to configure the ServiceManager in Module.php to make use of it. Honestly, I would have thought it would be more complicated than it is; it only requires one line. Have a look at the example below:
In the associative array returned from the getServiceConfig method, we just add the namespaced path to the new class we’ve just created. I’ve been rather explicit about mine for the sakes of clarity. That’s it.
Save Module.php and now if you when your tables are attempted to be retrieved from the ServiceManager, if they’re not explicitly defined, the new abstract factory class will attempt to instantiate them for you.
This will result in a more cacheable configuration, less development and maintenance effort.
So, have you tried out abstract factories yet? Are you tempted to do so now? Would you do this differently? Let me know in the comments.
You might also be interested in...
- Easy Cache Configuration With StorageCacheAbstractServiceFactory
- Accessing ServiceManager Services in Controller Plugins
- Howto Use Constructor Injection In ZF2
- Building and Executing SQL Queries In Zend
- Make Module Configs Cacheable with the ZF2 Factory Interface
comments powered by Disqus