Skip to content
This repository was archived by the owner on Feb 6, 2020. It is now read-only.

Commit 3fd0ca3

Browse files
committed
Forwards-compatibility changes
This patch modifies the `AbstractPluginManager` constructor to allow the following combination of arguments: - No arguments (current behavior). - Single `ConfigInterface` argument (current behavior); used to configure the instance. - Single `ContainerInterface` argument (v3 behavior); sets the "parent" locator/"creation context" - `ContainerInterface` as first argument, array as second (v3 behavior); sets the "parent" locator/"creation context", and uses the second argument to configure the instance. These changes allow developers the ability to continue to use existing plugin managers when upgrading to v3 (though they will also need to implement a `validate()` method, which will be in the migration guide). The changes presented are backwards compatible (loosens typehint on initial argument; new, second argument is optional).
1 parent 3b55b73 commit 3fd0ca3

File tree

2 files changed

+99
-3
lines changed

2 files changed

+99
-3
lines changed

src/AbstractPluginManager.php

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
namespace Zend\ServiceManager;
1111

12+
use Interop\Container\ContainerInterface;
1213
use Exception as BaseException;
1314

1415
/**
@@ -57,11 +58,56 @@ abstract class AbstractPluginManager extends ServiceManager implements ServiceLo
5758
* Add a default initializer to ensure the plugin is valid after instance
5859
* creation.
5960
*
60-
* @param null|ConfigInterface $configuration
61+
* Additionally, the constructor provides forwards compatibility with v3 by
62+
* overloading the initial argument. v2 usage expects either null or a
63+
* ConfigInterface instance, and will ignore any other arguments. v3 expects
64+
* a ContainerInterface instance, and will use an array of configuration to
65+
* seed the current instance with services. In most cases, you can ignore the
66+
* constructor unless you are writing a specialized factory for your plugin
67+
* manager or overriding it.
68+
*
69+
* @param null|ConfigInterface|ContainerInterface $configOrContainerInstance
70+
* @param array $v3config If $configOrContainerInstance is a container, this
71+
* value will be passed to the parent constructor.
72+
* @throws Exception\InvalidArgumentException if $configOrContainerInstance
73+
* is neither null, nor a ConfigInterface, nor a ContainerInterface.
6174
*/
62-
public function __construct(ConfigInterface $configuration = null)
75+
public function __construct($configOrContainerInstance = null, array $v3config = [])
6376
{
64-
parent::__construct($configuration);
77+
if (null !== $configOrContainerInstance
78+
&& ! $configOrContainerInstance instanceof ConfigInterface
79+
&& ! $configOrContainerInstance instanceof ContainerInterface
80+
) {
81+
throw new Exception\InvalidArgumentException(sprintf(
82+
'%s expects a ConfigInterface instance or ContainerInterface instance; received %s',
83+
get_class($this),
84+
(is_object($configOrContainerInstance)
85+
? get_class($configOrContainerInstance)
86+
: gettype($configOrContainerInstance)
87+
)
88+
));
89+
}
90+
91+
if ($configOrContainerInstance instanceof ContainerInterface) {
92+
if (property_exists($this, 'serviceLocator')) {
93+
if (! empty($v3config)) {
94+
parent::__construct(new Config($v3config));
95+
}
96+
$this->serviceLocator = $configOrContainerInstance;
97+
}
98+
99+
if (property_exists($this, 'creationContext')) {
100+
if (! empty($v3config)) {
101+
parent::__construct($v3config);
102+
}
103+
$this->creationContext = $configOrContainerInstance;
104+
}
105+
}
106+
107+
if ($configOrContainerInstance instanceof ConfigInterface) {
108+
parent::__construct($configOrContainerInstance);
109+
}
110+
65111
$this->addInitializer(function ($instance) {
66112
if ($instance instanceof ServiceLocatorAwareInterface) {
67113
$instance->setServiceLocator($this);

test/AbstractPluginManagerTest.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99

1010
namespace ZendTest\ServiceManager;
1111

12+
use Interop\Container\ContainerInterface;
1213
use ReflectionClass;
1314
use ReflectionObject;
1415
use Zend\ServiceManager\Config;
16+
use Zend\ServiceManager\Exception\InvalidArgumentException;
1517
use Zend\ServiceManager\Exception\RuntimeException;
1618
use Zend\ServiceManager\ServiceManager;
1719
use ZendTest\ServiceManager\TestAsset\FooPluginManager;
@@ -283,4 +285,52 @@ public function testWillResetAutoInvokableServiceIfNotValid()
283285
$this->assertTrue($pluginManager->has(__CLASS__));
284286
}
285287
}
288+
289+
/**
290+
* @group migration
291+
*/
292+
public function testConstructorAllowsPassingContainerAsFirstArgument()
293+
{
294+
$container = $this->prophesize(ContainerInterface::class);
295+
$pluginManager = new FooPluginManager($container->reveal());
296+
$this->assertSame($container->reveal(), $pluginManager->getServiceLocator());
297+
}
298+
299+
/**
300+
* @group migration
301+
*/
302+
public function testConstructorAllowsPassingContainerAndConfigurationArrayAsArguments()
303+
{
304+
$container = $this->prophesize(ContainerInterface::class);
305+
$pluginManager = new FooPluginManager($container->reveal(), ['services' => [
306+
__CLASS__ => $this,
307+
]]);
308+
$this->assertSame($container->reveal(), $pluginManager->getServiceLocator());
309+
$this->assertTrue($pluginManager->has(__CLASS__));
310+
}
311+
312+
public function invalidConstructorArguments()
313+
{
314+
return [
315+
'true' => [true],
316+
'false' => [false],
317+
'zero' => [0],
318+
'int' => [1],
319+
'zero-float' => [0.0],
320+
'float' => [1.1],
321+
'string' => ['invalid'],
322+
'array' => [['services' => [__CLASS__ => $this]]],
323+
'object' => [(object) ['services' => [__CLASS__ => $this]]],
324+
];
325+
}
326+
327+
/**
328+
* @group migration
329+
* @dataProvider invalidConstructorArguments
330+
*/
331+
public function testPassingArgumentsOtherThanNullConfigOrContainerAsFirstConstructorArgRaisesException($arg)
332+
{
333+
$this->setExpectedException(InvalidArgumentException::class);
334+
new FooPluginManager($arg);
335+
}
286336
}

0 commit comments

Comments
 (0)