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

Commit

Permalink
Merge branch 'hotfix/5175' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
weierophinney committed Oct 23, 2013
174 parents 88622d8 + 2190833 + fa773c1 + 741de27 + 4d1adc8 + 8c5c414 + a7502a7 + 5058513 + 68f3d6e + f0a44c8 + 921096f + acfe55c + 35c857a + a9dd8d2 + 44d8daf + d1f9e24 + a36339c + 86f0f77 + 7ed9bcc + 754bd9a + c36f6c0 + 3ead99d + be05873 + 34e7aec + 2fcaf1c + 3f9b994 + ea3acc3 + fe35f10 + 45cc91b + aa77760 + 4959b82 + 35e2edb + 7717bd8 + 127fcbd + fc52973 + 528f461 + 8e251cd + d95b25a + 0f89697 + c941b0e + 3dc45ae + 180e140 + 67c3033 + 533cd3e + 29e7718 + 936c9be + 2d11657 + fa66751 + 2b778cc + ba628cd + ff761e1 + 5b64ee3 + 9456811 + 1c2d797 + 46b0d8f + 82264b3 + 39c88ce + cee064b + c303bed + ea247e3 + 1f87514 + 8896fc2 + 313a38d + 42848d4 + 8f5c457 + e035a2a + 544e341 + 467f8b2 + 30bb6f0 + f8cc896 + 2ee0afd + 656f0b0 + 7092cb4 + 5e1b259 + abb3ff8 + 39a873f + b6e6c92 + 83055d8 + 1dd5d72 + 9bc304a + 479b8c7 + 41fab24 + 80aee85 + 3962f1e + 6c6b004 + acb7af7 + 39aca71 + 9d55623 + c2210f2 + 50b7a31 + 327d366 + 00cfdb8 + 77c12db + 4a66170 + 4bd5c7f + 9549d20 + d3a95e2 + 5e04377 + d9da2cf + 1049b39 + 001d281 + ca437e5 + a5cb2da + e2db3b8 + 27f50b4 + 8008d6f + 4a6bead + e2df9ad + 9045ea9 + 0d18a05 + 48cc7df + dc08391 + ceec2bd + c5fc623 + 6335bda + 2a78ec6 + 56c198e + 3fab1eb + 6e15982 + 75f672f + 6efac6a + 7818a15 + fc61f7c + 0f89452 + 4ce1a3e + 8e87de6 + ff8bdbb + 30d8776 + df9df5b + 95173ad + 6f9a231 + b28d0cf + d4be36e + 335a3c1 + 6b736dd + 303ab92 + 4594eeb + 7db8ed5 + fecc97b + 5a47e2a + fdab45c + a4698e4 + 0eb7480 + d73e943 + cda61b2 + f5875b9 + 485d763 + e23536a + 7981849 + 388d6df + b3220c5 + 112a8ed + 9f981d8 + 5d39422 + 7bbeff8 + d9b366d + 2e1a8ce + 6c95b5a + 831b797 + 4a459ec + 18d7a25 + 90f630e + 0c71387 + 2f90b43 + c8deb2c + 4d3a9b8 + 0d718c7 + 7d9869d + c07a4ae + ec26a71 + cf75bf9 + d383ad4 + e7edbc6 + e27390d commit f8d5651
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 31 deletions.
83 changes: 54 additions & 29 deletions src/ServiceManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -555,25 +555,7 @@ public function create($name)
}

if (isset($this->delegators[$cName])) {
$serviceManager = $this;
$additionalDelegators = count($this->delegators[$cName]) - 1;
$creationCallback = function () use ($serviceManager, $rName, $cName) {
return $serviceManager->doCreate($rName, $cName);
};

for ($i = 0; $i < $additionalDelegators; $i += 1) {
$creationCallback = $this->createDelegatorCallback(
$this->delegators[$cName][$i],
$rName,
$cName,
$creationCallback
);
}

/* @var $delegatorFactory DelegatorFactoryInterface */
$delegatorFactory = $this->get($this->delegators[$cName][$i]);

return $delegatorFactory->createDelegatorWithName($this, $cName, $rName, $creationCallback);
return $this->createDelegatorFromFactory($cName, $rName);
}

return $this->doCreate($rName, $cName);
Expand All @@ -582,22 +564,21 @@ public function create($name)
/**
* Creates a callback that uses a delegator to create a service
*
* @param string $delegatorFactoryName name of the delegator factory service
* @param string $rName requested service name
* @param string $cName canonical service name
* @param callable $creationCallback callback that is responsible for instantiating the service
* @param DelegatorFactoryInterface|callable $delegatorFactory the delegator factory
* @param string $rName requested service name
* @param string $cName canonical service name
* @param callable $creationCallback callback for instantiating the real service
*
* @return callable
*/
private function createDelegatorCallback($delegatorFactoryName, $rName, $cName, $creationCallback)
private function createDelegatorCallback($delegatorFactory, $rName, $cName, $creationCallback)
{
$serviceManager = $this;

return function () use ($serviceManager, $delegatorFactoryName, $rName, $cName, $creationCallback) {
/* @var $delegatorFactory DelegatorFactoryInterface */
$delegatorFactory = $serviceManager->get($delegatorFactoryName);

return $delegatorFactory->createDelegatorWithName($serviceManager, $cName, $rName, $creationCallback);
return function () use ($serviceManager, $delegatorFactory, $rName, $cName, $creationCallback) {
return $delegatorFactory instanceof DelegatorFactoryInterface
? $delegatorFactory->createDelegatorWithName($serviceManager, $cName, $rName, $creationCallback)
: $delegatorFactory($serviceManager, $cName, $rName, $creationCallback);
};
}

Expand Down Expand Up @@ -1104,6 +1085,50 @@ protected function createFromAbstractFactory($canonicalName, $requestedName)
return $instance;
}

/**
* @param $canonicalName
* @param $requestedName
* @return mixed
* @throws Exception\ServiceNotCreatedException
*/
protected function createDelegatorFromFactory($canonicalName, $requestedName)
{
$serviceManager = $this;
$delegatorsCount = count($this->delegators[$canonicalName]);
$creationCallback = function () use ($serviceManager, $requestedName, $canonicalName) {
return $serviceManager->doCreate($requestedName, $canonicalName);
};

for ($i = 0; $i < $delegatorsCount; $i += 1) {

$delegatorFactory = $this->delegators[$canonicalName][$i];

if (is_string($delegatorFactory)) {
$delegatorFactory = !$this->has($delegatorFactory) && class_exists($delegatorFactory, true) ?
new $delegatorFactory
: $this->get($delegatorFactory);
$this->delegators[$canonicalName][$i] = $delegatorFactory;
}

if (!$delegatorFactory instanceof DelegatorFactoryInterface && !is_callable($delegatorFactory)) {
throw new Exception\ServiceNotCreatedException(sprintf(
'While attempting to create %s%s an invalid factory was registered for this instance type.',
$canonicalName,
($requestedName ? '(alias: ' . $requestedName . ')' : '')
));
}

$creationCallback = $this->createDelegatorCallback(
$delegatorFactory,
$requestedName,
$canonicalName,
$creationCallback
);
}

return $creationCallback($serviceManager, $canonicalName, $requestedName, $creationCallback);
}

/**
* Checks if the object has this class as one of its parents
*
Expand Down
75 changes: 75 additions & 0 deletions test/AbstractPluginManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

use ZendTest\ServiceManager\TestAsset\FooCounterAbstractFactory;
use ZendTest\ServiceManager\TestAsset\FooPluginManager;
use ZendTest\ServiceManager\TestAsset\MockSelfReturningDelegatorFactory;

class AbstractPluginManagerTest extends \PHPUnit_Framework_TestCase
{
Expand Down Expand Up @@ -117,4 +118,78 @@ public function testCallableObjectWithMutableCreationOptions()
$method->setAccessible(true);
$method->invoke($this->pluginManager, $callable, 'foo', 'bar');
}

public function testValidatePluginIsCalledWithDelegatorFactoryIfItsAService()
{
$pluginManager = $this->getMockForAbstractClass('Zend\ServiceManager\AbstractPluginManager');
$delegatorFactory = $this->getMock('Zend\\ServiceManager\\DelegatorFactoryInterface');

$pluginManager->setService('delegator-factory', $delegatorFactory);
$pluginManager->addDelegator('foo-service', 'delegator-factory');

$pluginManager->expects($this->once())
->method('validatePlugin')
->with($delegatorFactory);

$pluginManager->create('foo-service');
}

public function testSingleDelegatorUsage()
{
$delegatorFactory = $this->getMock('Zend\\ServiceManager\\DelegatorFactoryInterface');
$pluginManager = $this->getMockForAbstractClass('Zend\ServiceManager\AbstractPluginManager');
$realService = $this->getMock('stdClass', array(), array(), 'RealService');
$delegator = $this->getMock('stdClass', array(), array(), 'Delegator');

$delegatorFactory
->expects($this->once())
->method('createDelegatorWithName')
->with(
$pluginManager,
'fooservice',
'foo-service',
$this->callback(function ($callback) use ($realService) {
if (!is_callable($callback)) {
return false;
}

return call_user_func($callback) === $realService;
})
)
->will($this->returnValue($delegator));

$pluginManager->setFactory('foo-service', function() use ($realService) {
return $realService;
});
$pluginManager->addDelegator('foo-service', $delegatorFactory);

$pluginManager->expects($this->once())
->method('validatePlugin')
->with($delegator);

$this->assertSame($delegator, $pluginManager->get('foo-service'));
}

public function testMultipleDelegatorsUsage()
{
$pluginManager = $this->getMockForAbstractClass('Zend\ServiceManager\AbstractPluginManager');

$fooDelegator = new MockSelfReturningDelegatorFactory();
$barDelegator = new MockSelfReturningDelegatorFactory();

$pluginManager->addDelegator('foo-service', $fooDelegator);
$pluginManager->addDelegator('foo-service', $barDelegator);
$pluginManager->setInvokableClass('foo-service', 'stdClass');

$pluginManager->expects($this->once())
->method('validatePlugin')
->with($barDelegator);

$this->assertSame($barDelegator, $pluginManager->get('foo-service'));
$this->assertCount(1, $barDelegator->instances);
$this->assertCount(1, $fooDelegator->instances);
$this->assertInstanceOf('stdClass', array_shift($fooDelegator->instances));
$this->assertSame($fooDelegator, array_shift($barDelegator->instances));

}
}
106 changes: 104 additions & 2 deletions test/ServiceManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,7 @@ public function testRetrieveServiceFromPeeringServiceManagerIfretrieveFromPeerin

/**
* @covers Zend\ServiceManager\ServiceManager::create
* @covers Zend\ServiceManager\ServiceManager::createDelegatorFromFactory
* @covers Zend\ServiceManager\ServiceManager::createDelegatorCallback
* @covers Zend\ServiceManager\ServiceManager::addDelegator
*/
Expand Down Expand Up @@ -783,13 +784,12 @@ public function testUsesDelegatorWhenAvailable()
)
->will($this->returnValue($delegator));

//die(var_dump($this->serviceManager));

$this->assertSame($delegator, $this->serviceManager->create('foo-service'));
}

/**
* @covers Zend\ServiceManager\ServiceManager::create
* @covers Zend\ServiceManager\ServiceManager::createDelegatorFromFactory
* @covers Zend\ServiceManager\ServiceManager::createDelegatorCallback
* @covers Zend\ServiceManager\ServiceManager::addDelegator
*/
Expand Down Expand Up @@ -852,4 +852,106 @@ public function testResolveCircularAliasReferenceThrowsException()
// This should throw the exception
$this->serviceManager->get('baz-alias');
}

/**
* @covers Zend\ServiceManager\ServiceManager::createDelegatorFromFactory
*/
public function testDelegatorFactoryWhenNotRegisteredAsService()
{
$delegator = $this->getMock('Zend\\ServiceManager\\DelegatorFactoryInterface');

$this->serviceManager->addDelegator('foo-service', $delegator);
$this->serviceManager->setInvokableClass('foo-service', 'stdClass');

$delegator
->expects($this->once())
->method('createDelegatorWithName')
->with(
$this->serviceManager,
'fooservice',
'foo-service',
$this->callback(function ($callback) {
if (!is_callable($callback)) {
return false;
}

$service = call_user_func($callback);

return $service instanceof \stdClass;
})
)
->will($this->returnValue($delegator));

$this->assertSame($delegator, $this->serviceManager->create('foo-service'));
}

/**
* @covers Zend\ServiceManager\ServiceManager::create
* @covers Zend\ServiceManager\ServiceManager::createDelegatorFromFactory
* @covers Zend\ServiceManager\ServiceManager::createDelegatorCallback
* @covers Zend\ServiceManager\ServiceManager::addDelegator
*/
public function testMultipleDelegatorFactoriesWhenNotRegisteredAsServices()
{
$fooDelegator = new MockSelfReturningDelegatorFactory();
$barDelegator = new MockSelfReturningDelegatorFactory();

$this->serviceManager->addDelegator('foo-service', $fooDelegator);
$this->serviceManager->addDelegator('foo-service', $barDelegator);
$this->serviceManager->setInvokableClass('foo-service', 'stdClass');

$this->assertSame($barDelegator, $this->serviceManager->create('foo-service'));
$this->assertCount(1, $barDelegator->instances);
$this->assertCount(1, $fooDelegator->instances);
$this->assertInstanceOf('stdClass', array_shift($fooDelegator->instances));
$this->assertSame($fooDelegator, array_shift($barDelegator->instances));
}

public function testInvalidDelegatorFactoryThrowsException()
{
$delegatorFactory = new \stdClass;
$this->serviceManager->addDelegator('foo-service', $delegatorFactory);

try {
$this->serviceManager->create('foo-service');
$this->fail('Expected exception was not raised');
}catch (Exception\ServiceNotCreatedException $expected) {
$this->assertRegExp('/invalid factory/', $expected->getMessage());
return;
}
}

public function testInvalidDelegatorFactoryAmongMultipleOnesThrowsException()
{
$this->serviceManager->addDelegator('foo-service', new MockSelfReturningDelegatorFactory());
$this->serviceManager->addDelegator('foo-service', new MockSelfReturningDelegatorFactory());
$this->serviceManager->addDelegator('foo-service', 'stdClass');

try {
$this->serviceManager->create('foo-service');
$this->fail('Expected exception was not raised');
}catch (Exception\ServiceNotCreatedException $expected) {
$this->assertRegExp('/invalid factory/', $expected->getMessage());
return;
}
}

public function testDelegatorFromCallback()
{
$realService = $this->getMock('stdClass', array(), array(), 'RealService');
$delegator = $this->getMock('stdClass', array(), array(), 'Delegator');

$delegatorFactoryCallback = function($serviceManager, $cName, $rName, $callback) use ($delegator) {
$delegator->real = call_user_func($callback);
return $delegator;
};

$this->serviceManager->setFactory('foo-service', function() use ($realService) { return $realService; } );
$this->serviceManager->addDelegator('foo-service', $delegatorFactoryCallback);

$service = $this->serviceManager->create('foo-service');

$this->assertSame($delegator, $service);
$this->assertSame($realService, $service->real);
}
}

0 comments on commit f8d5651

Please sign in to comment.