diff --git a/src/AbstractPluginManager.php b/src/AbstractPluginManager.php index 9e7e78b1..3fb7f8df 100644 --- a/src/AbstractPluginManager.php +++ b/src/AbstractPluginManager.php @@ -202,10 +202,6 @@ protected function createFromFactory($canonicalName, $requestedName) } if ($factory instanceof FactoryInterface) { - if ($hasCreationOptions && $factory instanceof MutableCreationOptionsInterface) { - $factory->setCreationOptions($this->creationOptions); - } - $instance = $this->createServiceViaCallback(array($factory, 'createService'), $canonicalName, $requestedName); } elseif (is_callable($factory)) { $instance = $this->createServiceViaCallback($factory, $canonicalName, $requestedName); @@ -217,4 +213,35 @@ protected function createFromFactory($canonicalName, $requestedName) return $instance; } + + /** + * Create service via callback + * + * @param callable $callable + * @param string $cName + * @param string $rName + * @throws Exception\ServiceNotCreatedException + * @throws Exception\ServiceNotFoundException + * @throws Exception\CircularDependencyFoundException + * @return object + */ + protected function createServiceViaCallback($callable, $cName, $rName) + { + if (is_object($callable)) { + $factory = $callable; + } elseif (is_array($callable)) { + // reset both rewinds and returns the value of the first array element + $factory = reset($callable); + } + + if (isset($factory) + && ($factory instanceof MutableCreationOptionsInterface) + && is_array($this->creationOptions) + && !empty($this->creationOptions) + ) { + $factory->setCreationOptions($this->creationOptions); + } + + return parent::createServiceViaCallback($callable, $cName, $rName); + } } diff --git a/test/AbstractPluginManagerTest.php b/test/AbstractPluginManagerTest.php index 86c5920d..6d151221 100644 --- a/test/AbstractPluginManagerTest.php +++ b/test/AbstractPluginManagerTest.php @@ -11,6 +11,7 @@ namespace ZendTest\ServiceManager; use ReflectionClass; +use ReflectionObject; use Zend\ServiceManager\Exception; use Zend\ServiceManager\ServiceManager; use Zend\ServiceManager\Config; @@ -29,6 +30,14 @@ class AbstractPluginManagerTest extends \PHPUnit_Framework_TestCase public function setup() { $this->serviceManager = new ServiceManager; + $this->pluginManager = new FooPluginManager(new Config(array( + 'factories' => array( + 'Foo' => 'ZendTest\ServiceManager\TestAsset\FooFactory', + ), + 'shared' => array( + 'Foo' => false, + ), + ))); } public function testSetMultipleCreationOptions() @@ -61,4 +70,52 @@ public function testSetMultipleCreationOptions() $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\FooFactory', $value['foo']); $this->assertEquals(array('key2' => 'value2'), $value['foo']->getCreationOptions()); } + + public function testAbstractFactoryWithMutableCreationOptions() + { + $creationOptions = array('key1' => 'value1'); + $mock = 'ZendTest\ServiceManager\TestAsset\AbstractFactoryWithMutableCreationOptions'; + $abstractFactory = $this->getMock($mock, array('setCreationOptions')); + $abstractFactory->expects($this->once()) + ->method('setCreationOptions') + ->with($creationOptions); + + $this->pluginManager->addAbstractFactory($abstractFactory); + $instance = $this->pluginManager->get('classnoexists', $creationOptions); + $this->assertTrue(is_object($instance)); + } + + public function testMutableMethodNeverCalledWithoutCreationOptions() + { + $mock = 'ZendTest\ServiceManager\TestAsset\CallableWithMutableCreationOptions'; + $callable = $this->getMock($mock, array('setCreationOptions')); + $callable->expects($this->never()) + ->method('setCreationOptions'); + + $ref = new ReflectionObject($this->pluginManager); + + $method = $ref->getMethod('createServiceViaCallback'); + $method->setAccessible(true); + $method->invoke($this->pluginManager, $callable, 'foo', 'bar'); + } + + public function testCallableObjectWithMutableCreationOptions() + { + $creationOptions = array('key1' => 'value1'); + $mock = 'ZendTest\ServiceManager\TestAsset\CallableWithMutableCreationOptions'; + $callable = $this->getMock($mock, array('setCreationOptions')); + $callable->expects($this->once()) + ->method('setCreationOptions') + ->with($creationOptions); + + $ref = new ReflectionObject($this->pluginManager); + + $property = $ref->getProperty('creationOptions'); + $property->setAccessible(true); + $property->setValue($this->pluginManager, $creationOptions); + + $method = $ref->getMethod('createServiceViaCallback'); + $method->setAccessible(true); + $method->invoke($this->pluginManager, $callable, 'foo', 'bar'); + } } diff --git a/test/TestAsset/AbstractFactoryWithMutableCreationOptions.php b/test/TestAsset/AbstractFactoryWithMutableCreationOptions.php new file mode 100644 index 00000000..8e9dcab7 --- /dev/null +++ b/test/TestAsset/AbstractFactoryWithMutableCreationOptions.php @@ -0,0 +1,38 @@ +options = $options; + } +} diff --git a/test/TestAsset/CallableWithMutableCreationOptions.php b/test/TestAsset/CallableWithMutableCreationOptions.php new file mode 100644 index 00000000..03a06420 --- /dev/null +++ b/test/TestAsset/CallableWithMutableCreationOptions.php @@ -0,0 +1,30 @@ +options = $options; + } + + public function __invoke(ServiceLocatorInterface $serviceLocator, $cName, $rName) + { + return new stdClass; + } +}