Skip to content

Commit

Permalink
Hotfix zendframework#279: fixed config merge
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasvargiu committed Jul 4, 2019
1 parent a1ed614 commit e88af67
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 2 deletions.
31 changes: 29 additions & 2 deletions src/ServiceManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Zend\ServiceManager\Exception\InvalidArgumentException;
use Zend\ServiceManager\Exception\ServiceNotCreatedException;
use Zend\ServiceManager\Exception\ServiceNotFoundException;
use Zend\Stdlib\ArrayUtils;

/**
* Service Manager.
Expand Down Expand Up @@ -337,7 +338,7 @@ public function configure(array $config)
}

if (isset($config['delegators'])) {
$this->delegators = array_merge_recursive($this->delegators, $config['delegators']);
$this->mergeDelegators($config['delegators']);
}

if (isset($config['shared'])) {
Expand All @@ -357,7 +358,7 @@ public function configure(array $config)
// If lazy service configuration was provided, reset the lazy services
// delegator factory.
if (isset($config['lazy_services']) && ! empty($config['lazy_services'])) {
$this->lazyServices = array_merge_recursive($this->lazyServices, $config['lazy_services']);
$this->lazyServices = ArrayUtils::merge($this->lazyServices, $config['lazy_services']);
$this->lazyServicesDelegator = null;
}

Expand Down Expand Up @@ -830,6 +831,32 @@ private function createLazyServiceDelegatorFactory()
return $this->lazyServicesDelegator;
}

/**
* Merge delegators avoiding multiple same delegators for the same service.
* It works with strings and class instances.
* It's not possibile to de-duple anonymous functions
*
* @param string[][]|Factory\DelegatorFactoryInterface[][] $config
* @return string[][]|Factory\DelegatorFactoryInterface[][]
*/
private function mergeDelegators(array $config)
{
foreach ($config as $key => $delegators) {
if (! isset($this->delegators[$key])) {
$this->delegators[$key] = $delegators;
continue;
}

foreach ($delegators as $delegator) {
if (! in_array($delegator, $this->delegators[$key], true)) {
$this->delegators[$key][] = $delegator;
}
}
}

return $this->delegators;
}

/**
* Create aliases for invokable classes.
*
Expand Down
48 changes: 48 additions & 0 deletions test/ServiceManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use stdClass;
use Zend\ServiceManager\Factory\FactoryInterface;
use Zend\ServiceManager\Factory\InvokableFactory;
use Zend\ServiceManager\Proxy\LazyServiceFactory;
use Zend\ServiceManager\ServiceManager;
use ZendTest\ServiceManager\TestAsset\InvokableObject;
use ZendTest\ServiceManager\TestAsset\SimpleServiceManager;
Expand Down Expand Up @@ -283,4 +284,51 @@ public function testFactoryMayBeStaticMethodDescribedByCallableString()
$serviceManager = new SimpleServiceManager($config);
$this->assertEquals(stdClass::class, get_class($serviceManager->get(stdClass::class)));
}

/**
* Hotfix #279
* @see https://github.com/zendframework/zend-servicemanager/issues/279
*/
public function testConfigureMultipleTimes()
{
$delegatorFactory = function (
ContainerInterface $container,
$name,
callable $callback
) {
/** @var InvokableObject $instance */
$instance = $callback();
$options = $instance->getOptions();
$inc = ! empty($options['inc']) ? $options['inc'] : 0;
return new InvokableObject(['inc' => ++$inc]);
};

$config = [
'factories' => [
'Foo' => function () {
return new InvokableObject();
},
],
'delegators' => [
'Foo' => [
$delegatorFactory,
LazyServiceFactory::class,
],
],
'lazy_services' => [
'class_map' => [
'Foo' => InvokableObject::class,
],
],
];

$serviceManager = new ServiceManager($config);
$serviceManager->configure($config);

/** @var InvokableObject $instance */
$instance = $serviceManager->get('Foo');

self::assertInstanceOf(InvokableObject::class, $instance);
self::assertSame(1, $instance->getOptions()['inc']);
}
}

0 comments on commit e88af67

Please sign in to comment.