From 5010a96402f1b91da1d091d43582492a6983c9a3 Mon Sep 17 00:00:00 2001 From: fhein Date: Thu, 18 Jan 2018 22:49:07 +0100 Subject: [PATCH] Rest of #221 setter modifications. --- src/ServiceManager.php | 75 ++++++++++++++++--------------------- test/ServiceManagerTest.php | 46 +++++++++++++++-------- 2 files changed, 64 insertions(+), 57 deletions(-) diff --git a/src/ServiceManager.php b/src/ServiceManager.php index f982b4a1..7c75b207 100644 --- a/src/ServiceManager.php +++ b/src/ServiceManager.php @@ -249,35 +249,19 @@ public function build($name, array $options = null) */ public function has($name) { + $resolvedName = $this->aliases[$name] ?? $name; // Check services and factories first to speedup the most common requests. - if (isset($this->services[$name]) || isset($this->factories[$name])) { - return true; - } - - // Check abstract factories next. - foreach ($this->abstractFactories as $abstractFactory) { - if ($abstractFactory->canCreate($this->creationContext, $name)) { - return true; - } - } - - // If $name is not an alias, we are done. - if (! isset($this->aliases[$name])) { - return false; - } - - // Check aliases. - $resolvedName = $this->aliases[$name]; if (isset($this->services[$resolvedName]) || isset($this->factories[$resolvedName])) { return true; } - // Check abstract factories on the $resolvedName as well. + // Check abstract factories next. foreach ($this->abstractFactories as $abstractFactory) { if ($abstractFactory->canCreate($this->creationContext, $resolvedName)) { return true; } } + return false; } /** @@ -386,12 +370,8 @@ public function configure(array $config) // For abstract factories and initializers, we always directly // instantiate them to avoid checks during service construction. - if (isset($config['abstract_factories'])) { - $abstractFactories = $config['abstract_factories']; - // $key not needed, but foreach is faster than foreach + array_values. - foreach ($abstractFactories as $key => $abstractFactory) { - $this->resolveAbstractFactoryInstance($abstractFactory); - } + if (! empty($config['abstract_factories'])) { + $this->resolveAbstractFactories($config['abstract_factories']); } if (isset($config['initializers'])) { @@ -465,7 +445,12 @@ public function setFactory($name, $factory) */ public function mapLazyService($name, $class = null) { - $this->configure(['lazy_services' => ['class_map' => [$name => $class ?: $name]]]); + if (! isset($this->services[$name]) || $this->allowOverride) { + $this->lazyServices = array_merge_recursive(['class_map' => [$name => $class ?? $name]]); + $this->lazyServicesDelegator = null; + return; + } + throw ContainerModificationsNotAllowedException::fromExistingService($name); } /** @@ -476,7 +461,7 @@ public function mapLazyService($name, $class = null) */ public function addAbstractFactory($factory) { - $this->resolveAbstractFactoryInstance($factory); + $this->resolveAbstractFactories([$factory]); } /** @@ -488,7 +473,11 @@ public function addAbstractFactory($factory) */ public function addDelegator($name, $factory) { - $this->configure(['delegators' => [$name => [$factory]]]); + if (! isset($this->services[$name]) || $this->allowOverride) { + $this->delegators = array_merge_recursive($this->delegators, [$name => [$factory]]); + return; + } + throw ContainerModificationsNotAllowedException::fromExistingService($name); } /** @@ -498,7 +487,7 @@ public function addDelegator($name, $factory) */ public function addInitializer($initializer) { - $this->configure(['initializers' => [$initializer]]); + $this->resolveInitializers([$initializer]); } /** @@ -923,25 +912,27 @@ private function mapAliasesToTargets() /** * Instantiate abstract factories in order to avoid checks during service construction. * - * @param string|Factory\AbstractFactoryInterface $abstractFactories - * @return void + * @param string[]|Factory\AbstractFactoryInterface[] $abstractFactories */ - private function resolveAbstractFactoryInstance($abstractFactory) + private function resolveAbstractFactories($abstractFactories) { - if (is_string($abstractFactory) && class_exists($abstractFactory)) { - // Cached string factory name - if (! isset($this->cachedAbstractFactories[$abstractFactory])) { - $this->cachedAbstractFactories[$abstractFactory] = new $abstractFactory(); + foreach ($abstractFactories as $_ => $abstractFactory) { + if (is_string($abstractFactory) && class_exists($abstractFactory)) { + // cached string + if (! isset($this->cachedAbstractFactories[$abstractFactory])) { + $this->cachedAbstractFactories[$abstractFactory] = new $abstractFactory(); + } + + $abstractFactory = $this->cachedAbstractFactories[$abstractFactory]; } - $abstractFactory = $this->cachedAbstractFactories[$abstractFactory]; - } + if ($abstractFactory instanceof Factory\AbstractFactoryInterface) { + $abstractFactoryObjHash = spl_object_hash($abstractFactory); + $this->abstractFactories[$abstractFactoryObjHash] = $abstractFactory; + return; + } - if (! $abstractFactory instanceof Factory\AbstractFactoryInterface) { throw InvalidArgumentException::fromInvalidAbstractFactory($abstractFactory); } - - $abstractFactoryObjHash = spl_object_hash($abstractFactory); - $this->abstractFactories[$abstractFactoryObjHash] = $abstractFactory; } } diff --git a/test/ServiceManagerTest.php b/test/ServiceManagerTest.php index 9b2749dc..85a36597 100644 --- a/test/ServiceManagerTest.php +++ b/test/ServiceManagerTest.php @@ -8,18 +8,17 @@ namespace ZendTest\ServiceManager; use DateTime; -use Interop\Container\Exception\ContainerException; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use stdClass; -use Zend\ServiceManager\Exception\ServiceNotCreatedException; -use Zend\ServiceManager\Exception\ServiceNotFoundException; use Zend\ServiceManager\Factory\AbstractFactoryInterface; use Zend\ServiceManager\Factory\FactoryInterface; use Zend\ServiceManager\Factory\InvokableFactory; use Zend\ServiceManager\ServiceManager; use ZendTest\ServiceManager\TestAsset\InvokableObject; use ZendTest\ServiceManager\TestAsset\SimpleServiceManager; +use Zend\ServiceManager\Exception\CyclicAliasException; +use PHPUnit\Framework\MockObject\Invokable; /** * @covers \Zend\ServiceManager\ServiceManager @@ -284,20 +283,13 @@ public function testAbstractFactoryShouldBeCheckedForResolvedAliasesInsteadOfAli $abstractFactory, ], ]); - - $valueMap = [ - ['Alias', false], - ['ServiceName', true], - ]; - $abstractFactory - ->method('canCreate') - ->withConsecutive( - [ $this->anything(), $this->equalTo('Alias') ], - [ $this->anything(), $this->equalTo('ServiceName')] - ) - ->willReturn($this->returnValueMap($valueMap)); + ->expects($this->once()) + ->method('canCreate') + ->with($this->anything(), $this->equalTo('ServiceName')) + ->willReturn(true); $this->assertTrue($serviceManager->has('Alias')); + } public static function sampleFactory() @@ -315,4 +307,28 @@ public function testFactoryMayBeStaticMethodDescribedByCallableString() $serviceManager = new SimpleServiceManager($config); $this->assertEquals(stdClass::class, get_class($serviceManager->get(stdClass::class))); } + +// public function testMinimalCyclicAliasDefinitionShouldThrow() +// { +// $sm = new ServiceManager(); + +// $this->expectException(CyclicAliasException::class); +// $sm->setAlias('alias', 'alias'); +// } + +// public function testCoverageDepthFirstTaggingOnRecursiveAliasDefinitions() +// { +// $sm = new ServiceManager([ +// 'factories' => [ +// stdClass::class => InvokableFactory::class, +// ], +// 'aliases' => [ +// 'alias1' => 'alias2', +// 'alias2' => 'alias3', +// 'alias3' => stdClass::class, +// ], +// ]); +// $this->assertSame($sm->get('alias1'), $sm->get('alias2')); +// $this->assertSame($sm->get(stdClass::class), $sm->get('alias1')); +// } }