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

Commit

Permalink
Merge remote-tracking branch 'SocalNick/hotfix/abstract-di-factory-ci…
Browse files Browse the repository at this point in the history
…rcular-dependency'
  • Loading branch information
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 7 deletions.
37 changes: 32 additions & 5 deletions src/ServiceManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ class ServiceManager implements ServiceLocatorInterface
*/
protected $abstractFactories = array();

/**
* @var array
*/
protected $pendingAbstractFactoryRequests = array();

/**
* @var array
*/
Expand Down Expand Up @@ -534,6 +539,13 @@ public function canCreateFromAbstractFactory($cName, $rName)
$this->abstractFactory[$index] = $abstractFactory = new $abstractFactory();
}

if (
isset($this->pendingAbstractFactoryRequests[get_class($abstractFactory)])
&& $this->pendingAbstractFactoryRequests[get_class($abstractFactory)] == $rName
) {
return false;
}

if ($abstractFactory->canCreateServiceWithName($this, $cName, $rName)) {
return true;
}
Expand Down Expand Up @@ -767,11 +779,26 @@ protected function createFromAbstractFactory($canonicalName, $requestedName)
($requestedName ? '(alias: ' . $requestedName . ')' : '')
));
}
$instance = $this->createServiceViaCallback(
array($abstractFactory, 'createServiceWithName'),
$canonicalName,
$requestedName
);
try {
$this->pendingAbstractFactoryRequests[get_class($abstractFactory)] = $requestedName;
$instance = $this->createServiceViaCallback(
array($abstractFactory, 'createServiceWithName'),
$canonicalName,
$requestedName
);
unset($this->pendingAbstractFactoryRequests[get_class($abstractFactory)]);
} catch (\Exception $e) {
unset($this->pendingAbstractFactoryRequests[get_class($abstractFactory)]);
throw new Exception\ServiceNotCreatedException(
sprintf(
'An abstract factory could not create an instance of %s%s.',
$canonicalName,
($requestedName ? '(alias: ' . $requestedName . ')' : '')
),
$e->getCode(),
$e
);
}
if (is_object($instance)) {
break;
}
Expand Down
10 changes: 8 additions & 2 deletions test/Di/DiServiceFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@

namespace ZendTest\ServiceManager\Di;

use Zend\ServiceManager\Di\DiServiceFactory,
Zend\ServiceManager\Di\DiInstanceManagerProxy;
use Zend\Di\Di;
use Zend\ServiceManager\Di\DiServiceFactory;
use Zend\ServiceManager\Di\DiInstanceManagerProxy;
use Zend\ServiceManager\Di\DiAbstractServiceFactory;
use Zend\ServiceManager\ServiceManager;

class DiServiceFactoryTest extends \PHPUnit_Framework_TestCase
{

/**
* @var DiServiceFactory
*/
protected $diServiceFactory = null;

/**@#+
Expand Down
13 changes: 13 additions & 0 deletions test/ServiceManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -478,4 +478,17 @@ public function testAssignAliasWithExistingServiceName()
// should throw an exception because 'foo' already exists in the service manager
$this->serviceManager->setAlias('foo', 'bar');
}

/**
* @covers Zend\ServiceManager\ServiceManager::createFromAbstractFactory
* @covers Zend\ServiceManager\ServiceManager::has
*/
public function testWillNotCreateCircularReferences()
{
$abstractFactory = new TestAsset\CircularDependencyAbstractFactory();
$sm = new ServiceManager();
$sm->addAbstractFactory($abstractFactory);
$foo = $sm->get('foo');
$this->assertSame($abstractFactory->expectedInstance, $foo);
}
}
35 changes: 35 additions & 0 deletions test/TestAsset/CircularDependencyAbstractFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php


namespace ZendTest\ServiceManager\TestAsset;

use Zend\ServiceManager\AbstractFactoryInterface,
Zend\ServiceManager\ServiceLocatorInterface;

/**
* Class used to try to simulate a cyclic dependency in ServiceManager.
*/
class CircularDependencyAbstractFactory implements AbstractFactoryInterface
{
public $expectedInstance = 'a retrieved value';

/**
* {@inheritDoc}
*/
public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
{
return true;
}

/**
* {@inheritDoc}
*/
public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
{
if ($serviceLocator->has($name)) {
return $serviceLocator->get($name);
}

return $this->expectedInstance;
}
}

0 comments on commit 32f4be5

Please sign in to comment.