Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Jan 8, 2020. It is now read-only.

Delegate factories #4145

Merged
merged 6 commits into from
Apr 15, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions library/Zend/ServiceManager/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,17 @@ public function getShared()
return (isset($this->config['shared'])) ? $this->config['shared'] : array();
}

/**
* Get the delegator services map, with keys being the services acting as delegates,
* and values being the delegator factories names
*
* @return array
*/
public function getDelegators()
{
return (isset($this->config['delegators'])) ? $this->config['delegators'] : array();
}

/**
* Configure service manager
*
Expand Down Expand Up @@ -145,5 +156,11 @@ public function configureServiceManager(ServiceManager $serviceManager)
foreach ($this->getShared() as $name => $isShared) {
$serviceManager->setShared($name, $isShared);
}

foreach ($this->getDelegators() as $originalServiceName => $delegators) {
foreach ($delegators as $delegator) {
$serviceManager->addDelegator($originalServiceName, $delegator);
}
}
}
}
28 changes: 28 additions & 0 deletions library/Zend/ServiceManager/DelegatorFactoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace Zend\ServiceManager;

/**
* Interface for factories that can create delegators for services
*/
interface DelegatorFactoryInterface
{
/**
* A factory that creates delegators of a given service
*
* @param ServiceLocatorInterface $serviceLocator the service locator which requested the service
* @param string $name the normalized service name
* @param string $requestedName the requested service name
* @param callable $callback the callback that is responsible for creating the service
*
* @return mixed
*/
public function createDelegatorWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName, $callback);
}
92 changes: 87 additions & 5 deletions library/Zend/ServiceManager/ServiceManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ class ServiceManager implements ServiceLocatorInterface
*/
protected $abstractFactories = array();

/**
* @var array[]
*/
protected $delegators = array();

/**
* @var array
*/
Expand Down Expand Up @@ -311,6 +316,25 @@ public function addAbstractFactory($factory, $topOfStack = true)
return $this;
}

/**
* Sets the given service name as to be handled by a delegator factory
*
* @param string $serviceName name of the service being the delegate
* @param string $delegatorFactoryName name of the service being the delegator factory
*
* @return ServiceManager
*/
public function addDelegator($serviceName, $delegatorFactoryName)
{
if (!isset($this->delegators[$this->canonicalizeName($serviceName)])) {
$this->delegators[$this->canonicalizeName($serviceName)] = array();
}

$this->delegators[$this->canonicalizeName($serviceName)][] = $delegatorFactoryName;

return $this;
}

/**
* Add initializer
*
Expand Down Expand Up @@ -475,17 +499,14 @@ public function get($name, $usePeeringServiceManagers = true)
}

/**
* Create an instance
* Create an instance of the requested service
*
* @param string|array $name
*
* @return bool|object
* @throws Exception\ServiceNotFoundException
* @throws Exception\ServiceNotCreatedException
*/
public function create($name)
{
$instance = false;

if (is_array($name)) {
list($cName, $rName) = $name;
} else {
Expand All @@ -499,6 +520,67 @@ 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->doCreate($rName, $cName);
}

/**
* 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
*
* @return callable
*/
private function createDelegatorCallback($delegatorFactoryName, $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);
};
}

/**
* Actually creates the service
*
* @param string $rName real service name
* @param string $cName canonicalized service name
*
* @return bool|mixed|null|object
* @throws Exception\ServiceNotFoundException
*
* @internal this method is internal because of PHP 5.3 compatibility - do not explicitly use it
*/
public function doCreate($rName, $cName)
{
$instance = false;

if (isset($this->factories[$cName])) {
$instance = $this->createFromFactory($cName, $rName);
Expand Down
59 changes: 59 additions & 0 deletions tests/ZendTest/ServiceManager/ServiceManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Zend\ServiceManager\Config;

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

class ServiceManagerTest extends \PHPUnit_Framework_TestCase
{
Expand Down Expand Up @@ -728,4 +729,62 @@ public function testRetrieveServiceFromPeeringServiceManagerIfretrieveFromPeerin
$this->assertEquals($serviceManagerChild->get($foo1), $boo2);
$this->assertEquals($this->serviceManager->get($foo1), $boo2);
}

/**
* @covers Zend\ServiceManager\ServiceManager::create
* @covers Zend\ServiceManager\ServiceManager::createDelegatorCallback
* @covers Zend\ServiceManager\ServiceManager::addDelegator
*/
public function testUsesDelegatorWhenAvailable()
{
$delegator = $this->getMock('Zend\\ServiceManager\\DelegatorFactoryInterface');

$this->serviceManager->setService('foo-delegator', $delegator);
$this->serviceManager->addDelegator('foo-service', 'foo-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::createDelegatorCallback
* @covers Zend\ServiceManager\ServiceManager::addDelegator
*/
public function testUsesMultipleDelegates()
{
$fooDelegator = new MockSelfReturningDelegatorFactory();
$barDelegator = new MockSelfReturningDelegatorFactory();

$this->serviceManager->setService('foo-delegate', $fooDelegator);
$this->serviceManager->setService('bar-delegate', $barDelegator);
$this->serviceManager->addDelegator('foo-service', 'foo-delegate');
$this->serviceManager->addDelegator('foo-service', 'bar-delegate');
$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));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @package Zend_ServiceManager
*/

namespace ZendTest\ServiceManager\TestAsset;

use Zend\ServiceManager\DelegatorFactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

/**
* Mock factory that logs delegated service instances and returns itself instead of the original service
*/
class MockSelfReturningDelegatorFactory implements DelegatorFactoryInterface
{
/**
* @var mixed[]
*/
public $instances = array();

/**
* {@inheritDoc}
*/
public function createDelegatorWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName, $callback)
{
$this->instances[] = call_user_func($callback);

return $this;
}
}