Skip to content

Commit

Permalink
Rest of zendframework#221 setter modifications.
Browse files Browse the repository at this point in the history
  • Loading branch information
fhein committed Jan 30, 2018
1 parent 586e94d commit 5010a96
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 57 deletions.
75 changes: 33 additions & 42 deletions src/ServiceManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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'])) {
Expand Down Expand Up @@ -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);
}

/**
Expand All @@ -476,7 +461,7 @@ public function mapLazyService($name, $class = null)
*/
public function addAbstractFactory($factory)
{
$this->resolveAbstractFactoryInstance($factory);
$this->resolveAbstractFactories([$factory]);
}

/**
Expand All @@ -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);
}

/**
Expand All @@ -498,7 +487,7 @@ public function addDelegator($name, $factory)
*/
public function addInitializer($initializer)
{
$this->configure(['initializers' => [$initializer]]);
$this->resolveInitializers([$initializer]);
}

/**
Expand Down Expand Up @@ -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;
}
}
46 changes: 31 additions & 15 deletions test/ServiceManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand All @@ -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'));
// }
}

0 comments on commit 5010a96

Please sign in to comment.