Skip to content

Commit

Permalink
Improved program flow of the service manager.
Browse files Browse the repository at this point in the history
  • Loading branch information
kokx committed Jul 2, 2012
1 parent 7883692 commit 949a335
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 57 deletions.
92 changes: 67 additions & 25 deletions library/Zend/ServiceManager/ServiceManager.php
Expand Up @@ -364,16 +364,10 @@ public function get($name, $usePeeringServiceManagers = true)
$instance = $this->retrieveFromPeeringManager($name);
}
if (!$instance) {
try {
if ($this->canCreate(array($cName, $rName))) {
$instance = $this->create(array($cName, $rName));
} catch (Exception\ServiceNotFoundException $selfException) {
if ($usePeeringServiceManagers && !$retrieveFromPeeringManagerFirst) {
$instance = $this->retrieveFromPeeringManager($name);
}
} catch (Exception\ServiceNotCreatedException $selfException) {
if ($usePeeringServiceManagers && !$retrieveFromPeeringManagerFirst) {
$instance = $this->retrieveFromPeeringManager($name);
}
} else if ($usePeeringServiceManagers && !$retrieveFromPeeringManagerFirst) {
$instance = $this->retrieveFromPeeringManager($name);
}
}
}
Expand Down Expand Up @@ -427,7 +421,7 @@ public function create($name)
$instance = $this->createFromInvokable($cName, $rName);
}

if (!$instance && !empty($this->abstractFactories)) {
if (!$instance && $this->canCreateFromAbstractFactory($cName, $rName)) {
$instance = $this->createFromAbstractFactory($cName, $rName);
}

Expand All @@ -453,18 +447,23 @@ public function create($name)
}

/**
* @param $nameOrAlias
* Determine if we can create an instance.
* @param $name
* @return bool
*/
public function has($nameOrAlias, $usePeeringServiceManagers = true)
public function canCreate($name)
{
if (is_array($nameOrAlias)) {
list($cName, $rName) = $nameOrAlias;
$instance = false;
$rName = null;

if (is_array($name)) {
list($cName, $rName) = $name;
} else {
$cName = $this->canonicalizeName($nameOrAlias);
$rName = $nameOrAlias;
$cName = $name;
}

$cName = $this->canonicalizeName($cName);

$has = (
isset($this->invokableClasses[$cName])
|| isset($this->factories[$cName])
Expand All @@ -476,16 +475,36 @@ public function has($nameOrAlias, $usePeeringServiceManagers = true)
return true;
}

// check abstract factories
foreach ($this->abstractFactories as $index => $abstractFactory) {
// Support string abstract factory class names
if (is_string($abstractFactory) && class_exists($abstractFactory, true)) {
$this->abstractFactory[$index] = $abstractFactory = new $abstractFactory();
}
if (isset($this->factories[$cName])) {
return true;
}

if ($abstractFactory->canCreateServiceWithName($this, $cName, $rName)) {
return true;
}
if (isset($this->invokableClasses[$cName])) {
return true;
}

if ($this->canCreateFromAbstractFactory($cName, $rName)) {
return true;
}

return false;
}

/**
* @param $nameOrAlias
* @return bool
*/
public function has($nameOrAlias, $usePeeringServiceManagers = true)
{
if (is_array($nameOrAlias)) {
list($cName, $rName) = $nameOrAlias;
} else {
$cName = $this->canonicalizeName($nameOrAlias);
$rName = $nameOrAlias;
}

if ($this->canCreate(array($cName, $rName))) {
return true;
}

if ($usePeeringServiceManagers) {
Expand All @@ -499,6 +518,29 @@ public function has($nameOrAlias, $usePeeringServiceManagers = true)
return false;
}

/**
* Determine if we can create an instance from an abstract factory.
*
* @param string $cName
* @param string $rName
* @return bool
*/
public function canCreateFromAbstractFactory($cName, $rName)
{
// check abstract factories
foreach ($this->abstractFactories as $index => $abstractFactory) {
// Support string abstract factory class names
if (is_string($abstractFactory) && class_exists($abstractFactory, true)) {
$this->abstractFactory[$index] = $abstractFactory = new $abstractFactory();
}

if ($abstractFactory->canCreateServiceWithName($this, $cName, $rName)) {
return true;
}
}
return false;
}

/**
* @param $alias
* @param $nameOrAlias
Expand Down
38 changes: 6 additions & 32 deletions tests/Zend/ServiceManager/ServiceManagerTest.php
Expand Up @@ -398,19 +398,6 @@ public function testConfigureWithInvokableClass()
$this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $foo);
}

public function testCanUseStringAbstractFactoryClassName()
{
$config = new Configuration(array(
'abstract_factories' => array(
'ZendTest\ServiceManager\TestAsset\FooAbstractFactory',
),
));
$serviceManager = new ServiceManager($config);
$serviceManager->setFactory('foo', 'ZendTest\ServiceManager\TestAsset\FooFactory');
$foo = $serviceManager->get('unknownObject');
$this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $foo);
}

public function testPeeringService()
{
$di = new Di();
Expand All @@ -422,21 +409,6 @@ public function testPeeringService()
$this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Bar', $bar);
}

public function testPeeringServiceFallbackOnCreateFailure()
{
$factory = function ($sm) {
return new TestAsset\Bar();
};
$serviceManager = new ServiceManager();
$serviceManager->setFactory('ZendTest\ServiceManager\TestAsset\Bar', $factory);
$sm = $serviceManager->createScopedServiceManager(ServiceManager::SCOPE_CHILD);
$di = new Di();
$di->instanceManager()->setParameters('ZendTest\ServiceManager\TestAsset\Bar', array('foo' => array('a')));
$sm->addAbstractFactory(new DiAbstractServiceFactory($di));
$bar = $serviceManager->get('ZendTest\ServiceManager\TestAsset\Bar');
$this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Bar', $bar);
}

public function testDiAbstractServiceFactory()
{
$di = $this->getMock('Zend\Di\Di');
Expand All @@ -450,12 +422,14 @@ public function testDiAbstractServiceFactory()
$this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Bar', $bar);
}

/**
* @expectedException TestAsset\FooException
*/
public function testExceptionThrowingFactory()
{
$this->serviceManager->setFactory('foo', 'ZendTest\ServiceManager\TestAsset\ExceptionThrowingFactory');
$this->serviceManager->get('foo');
try {
$this->serviceManager->get('foo');
$this->fail("No exception thrown");
} catch (Exception\ServiceNotCreatedException $e) {
$this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\FooException', $e->getPrevious());
}
}
}
3 changes: 3 additions & 0 deletions tests/Zend/ServiceManager/TestAsset/FooAbstractFactory.php
Expand Up @@ -9,6 +9,9 @@ class FooAbstractFactory implements AbstractFactoryInterface
{
public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
{
if ($name == 'foo') {
return true;
}
}
public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
{
Expand Down

0 comments on commit 949a335

Please sign in to comment.