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.
Want an easy way to configure caching in ZF2 applications? Today’s shows you how with a little-known option StorageCacheAbstractServiceFactory.
If you’ve been playing with Zend Framework 2 for some time, specifically the ZF2 Skeleton Application, you still may not have come across some of the pre-registered service manager abstract factory options.
As I was browsing through the Application module’s module.config.php
recently, I came across this snippet
'service_manager' => array( 'abstract_factories' => array( 'Zend\Cache\Service\StorageCacheAbstractServiceFactory', 'Zend\Log\Logger\AbstractServiceFactory', ), )
It was at that point I wondered why I’d spent time setting up caching using other methods, when this approach was already there and seemed to do a lot of the heavy lifting for me.
So in this week’s tutorial, I’m going to take you through how to use it, working with the default configuration provided in the manual.
In the manual, specifically in the default services section, you’ll find the below configuration option.
array( 'Cache\Transient' => array( 'adapter' => 'redis', 'ttl' => 60, 'plugins' => array( 'exception_handler' => array( 'throw_exceptions' => false, ), ), ), 'Cache\Persistent' => array( 'adapter' => 'filesystem', 'ttl' => 86400, ), ), );
This will set up two caches:
This can be quite handy and is a bit reminiscent of the 2-stage slow/fast cache configuration, available in Zend Framework 1.
When you have this configuration available, you can retrieve a cache object simply by referring to it in a controller, factory or abstract factory class, as we’ll see soon.
This is because Zend\Cache\Service\StorageCacheAbstractServiceFactory
uses the available storage adapters, along with their accompanying options classes, in vendor/zendframework/zendframework/library/Zend/Cache/Storage/Adapter
, to manage instantiating a cache object.
There’s a number of storage adapters available, including the following:
The benefit of this is that you don’t need to worry about setting it up for yourself, creating custom solutions and configurations. However, if your option of choice isn’t listed, you’ll have to find or create a storage adapter and options class for it.
So let’s step through the process of configuring it. I’ll assume that you already have a project based on the ZF2 Skeleton App repository, that it’s running without configuration issues and that the default Application module’s in place with no major changes.
You’ll need a Redis server for this tutorial. If you don’t have one setup, then either add one to your environment or for a minimum of effort, check out the excellent Laravel Homestead project.
This is an excellent project, which provides a simple, effective and properly working virtual machine designed with PHP developers in mind. I’ll leave you to read over the documentation, but out of the box, it comes with:
What’s more, it has a really, really, simple configuration file and is nicely configured out of the box.
The first thing you want to do is to add the configuration above to a new file called caches.local.php (or caches.global.php) in the config/autoload
directory.
That basic configuration will provide for two cache objects. Rename them if you like and feel free to add more or remove one as best you see fit.
Then you need to add in a bit more information, if you’re going to use the Cache\Persistent option. If you attempt to use it as is, it won’t work, as there’s no default directory set in the Filesystem class.
So after &’ttl’ add in the following extra configuration:
'options' => array( 'cache_dir' => __DIR__ . '/../../data/cache/' )
This assumes that you have a directory structure of data/cache off the root of your project directory. If you don’t, or it’s located somewhere else, then change it to suit your needs.
The Cache\Persistent
option will work fine, so long as your Redis server’s located on localhost and using the standard port of 6379. If it’s not, you’ll need to add in an extra configuration as follows:
'server' => array( 'host' => 'localhost', 'port' => '6379', )
This took a little bit of hunting through the classes to find. In Zend\Cache\Storage\Adapter\RedisOptions
you’ll find a function called setServer, where you’ll see other configuration options.
Now I don’t overly advocate this way, but will cover it just so that it’s documented. The simplest and least portable (and documentable) approach is to use the following in a controller action.
$this->getServiceLocator()->get('Cache\Persistent')
This way, whilst easy and quick as well as handy for rapid prototyping isn’t a good solution long term. So please consider the next approach.
This is my preferred method. Following the previous tutorial on using either ServiceManager factories or abstract factories, in the createServiceWithName method, instantiate your controller as follows:
$sm = $serviceLocator->getServiceLocator(); $cache = array(); if ($sm->has('Cache\Persistent')) { $cache['CachePersistent'] = $sm->get('CachePersistent'); } if ($sm->has('Cache\Transient')) { $cache['CacheTransient'] = $sm->get('CacheTransient'); } $controller = new YourController($cache);
This checks if the two cache items are available and if so, adds them to an array, called $cache
, which is then passed to the YourController’s constructor.
Then in the controller use a constructor like the following:
public function __construct($cache = null) { if (!is_null($cache)) { $this->cache = $cache; } }
Assuming that you already have a class member variable, called cache
, this will initialise it, if the cache argument is set, but not force it to be set.
After all that’s done, let’s look at the code to use the cache. Taking the simple example below, we’ll store some facts about one of the greatest movies of all time, Ghostbusters!
$cacheObj = $this->cache['Cache\Persistent']; if (!$cacheObj->hasItem('Ghostbusters')) { $cacheObj->addItem('Ghostbusters', 'Harold Ramis Rocks!!!'); } else { print $cacheObj->getItem('Ghostbusters'); }
That’s it. You can then use the cache as you would normally, calling getItem, setItem, addItem, hasItem and so on.
And that’s one of the simplest ways I’ve found to configure and use caching in Zend Framework 2 applications. Have you tried it already? Share your thoughts in the comments.
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.
Do you need access to a service from the ServiceManager in a custom Controller Plugin you’re creating? Today’s tutorial shows you just how to do it, in a testable and documentable way.
Is it right to use setter injection? Or is it evil, to be avoided at all costs, for the explicitness of constructor injection? In today’s post, we explore that and how to implement constructor injection in ZF2 controller classes.
Please consider buying me a coffee. It really helps me to keep producing new tutorials.
Join the discussion
comments powered by Disqus