Zend Framework 2 : Using $creationOptions in PluginManager
$creationOptions is an optional parameter that we can pass on 2nd parameter when we get service from PluginManager. It can ease coding process when we need to pass a different parameter or injection on the fly while service is created. We can apply it in $invokableClasses or $factories.
Let’s take a look more deep with example. Let’s say, we have a module with PluginManager that collect service in there like this :

We need to call ‘bar’ service with injected Foo class. Ok, let’s start.
1. create PluginInterface
namespace ExamplePluginManagerCreationOptions\Service;
interface PluginInterface
{
/*
* @return void
*/
public function getProperty();
}
2. create a Foo class that implements PluginInterface
namespace ExamplePluginManagerCreationOptions\Service;
class Foo implements PluginInterface
{
/**
* @var string
*/
protected $fooProperty;
/**
* Construct with $fooProperty param
* @param array $fooProperty
*/
public function __construct(array $fooProperty)
{
$this->fooProperty = $fooProperty;
}
/**
* {@inheritdoc}
*/
public function getProperty()
{
var_dump($this);
}
}
3. create a Bar class that implements PluginInterface and use Foo in __construct.
namespace ExamplePluginManagerCreationOptions\Service;
class Bar implements PluginInterface
{
/**
* @var Foo
*/
protected $foo;
/**
* Construct with $foo param
* @param Foo $foo
*/
public function __construct(Foo $foo)
{
$this->foo = $foo;
}
/**
* {@inheritdoc}
*/
public function getProperty()
{
var_dump($this);
}
}
4. When realizing the dependency above. We usually use factory to create service, but with $creationOptions, we can make it as invokables like the following :
namespace ExamplePluginManagerCreationOptions\Service;
use Zend\ServiceManager\AbstractPluginManager;
class PluginManager extends AbstractPluginManager
{
protected $invokableClasses = array(
'bar' => 'ExamplePluginManagerCreationOptions\Service\Bar',
);
/**
* {@inheritdoc}
*/
public function validatePlugin($plugin)
{
if ($plugin instanceof PluginInterface) {
// we're okay
return;
}
throw new \InvalidArgumentException(sprintf(
'Plugin of type %s is invalid; must implement %s\PluginInterface',
(is_object($plugin) ? get_class($plugin) : gettype($plugin)),
__NAMESPACE__
));
}
}
5. Then, we register the pluginmanager at PluginManagerFactory as PLUGIN_MANAGER_CLASS const as usual.
namespace ExamplePluginManagerCreationOptions\Factory;
use Zend\Mvc\Service\AbstractPluginManagerFactory;
class PluginManagerFactory extends AbstractPluginManagerFactory
{
const PLUGIN_MANAGER_CLASS = 'ExamplePluginManagerCreationOptions\Service\PluginManager';
}
6. Now, we can register at service_manager key in module.config.php
return array(
'service_manager' => array(
'factories' => array(
'testpluginmanager' => 'ExamplePluginManagerCreationOptions\Factory\PluginManagerFactory',
),
),
);
7. Ok, then now we can call it :
$testpluginmanager = $this->getServiceLocator()->get('testpluginmanager');
$bar = $testpluginmanager->get(
'bar',
new \ExamplePluginManagerCreationOptions\Service\Foo(array('test'))
);
$bar->getProperty();
Hm.., do you feel pass everything of instance(s) on the fly when creating service is too much but still want “on the fly” freedom ? Then we can create a factory for it. We can then add “BarServiceFactory” like the following structure :

The “BarServiceFactory” can be like the following :
namespace ExamplePluginManagerCreationOptions\Factory\Service;
use ExamplePluginManagerCreationOptions\Service\Bar;
use ExamplePluginManagerCreationOptions\Service\Foo;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\MutableCreationOptionsInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
/**
* a factory to create ExamplePluginManagerCreationOptions\Service\Bar
* service
*/
class BarServiceFactory implements
FactoryInterface,
MutableCreationOptionsInterface
{
/**
* {@inheritdoc}
*/
public function setCreationOptions(array $creationOptions)
{
$this->creationOptions = $creationOptions;
}
/**
* {@inheritdoc}
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
//you can call other service by $serviceLocator()->get('servicename')
//as far as the service implements PluginInterface defined in
//your pluginmanager
//otherwise, you need to call top serviceManager
//by $serviceLocator->getServiceLocator()->get('servicename')
return new Bar(new Foo($this->creationOptions));
}
}
Now, we can register it at out PluginManager.
namespace ExamplePluginManagerCreationOptions\Service;
use Zend\ServiceManager\AbstractPluginManager;
class PluginManager extends AbstractPluginManager
{
protected $invokableClasses = array(
'bar' => 'ExamplePluginManagerCreationOptions\Service\Bar',
);
protected $factories = array(
'barservice' => 'ExamplePluginManagerCreationOptions\Factory\Service\BarServiceFactory',
);
/**
* {@inheritdoc}
*/
public function validatePlugin($plugin)
{
if ($plugin instanceof PluginInterface) {
// we're okay
return;
}
throw new \InvalidArgumentException(sprintf(
'Plugin of type %s is invalid; must implement %s\PluginInterface',
(is_object($plugin) ? get_class($plugin) : gettype($plugin)),
__NAMESPACE__
));
}
}
And now, we can call it with :
$testpluginmanager = $this->getServiceLocator()->get('testpluginmanager');
$bar = $testpluginmanager->get(
'barservice',
array('test')
);
$bar->getProperty();
When everything is ok, then we can get the following data output :
object(ExamplePluginManagerCreationOptions\Service\Bar)[303]
protected 'foo' =>
object(ExamplePluginManagerCreationOptions\Service\Foo)[298]
protected 'fooProperty' =>
array (size=1)
0 => string 'test' (length=4)
Done ;). I hope it is useful.
Note : We can make $this->creationOptions as collection of array of instances too.
References :
1. http://zend-framework-community.634137.n4.nabble.com/Abstract-Factory-for-custom-Validators-options-discarded-td4661990.html
2. http://zend-framework-community.634137.n4.nabble.com/AbstractPluginManager-amp-options-creationOptions-will-not-work-as-newInstanceArgs-td4656077.html#a4656083
2 comments