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

Commit 559baca

Browse files
committed
Allow mutability of the container
This patch reverts the changes that implemented immutability, and re-instates the various set/add methods used in v2 for configuring the container. Specifically: - `withConfig()` was removed. - `configure()` was made public. - Re-added: - `setAlias()` - `setInvokableClass()` - `setFactory()` - `addAbstractFactory()` - `addDelegator()` - `addInitializer()` - `setService()` - `setShared()` - all of which proxy to `configure()` - Added `mapLazyService($name, $class = null)`, for creating a lazy service mapping from a service name to a given class. - Re-added `setAllowOverride()` for toggling immutability. When toggled on, all calls to `configure()` raise `ContainerModificationsNotAllowedException`. Its counterpart getter, `getAllowOverride()`, was also re-isntated. Tests were added for all new behaviors, and the tests for `withConfig()` were removed.
1 parent 5ae2199 commit 559baca

File tree

6 files changed

+389
-82
lines changed

6 files changed

+389
-82
lines changed

src/Config.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,11 @@ public function __construct(array $config = [])
6666
* Configure service manager
6767
*
6868
* @param ServiceManager $serviceManager
69-
* @return ServiceManager Returns a new instance with the merged configuration.
69+
* @return ServiceManager Returns the updated service manager instance.
7070
*/
7171
public function configureServiceManager(ServiceManager $serviceManager)
7272
{
73-
return $serviceManager->withConfig($this->config);
73+
return $serviceManager->configure($this->config);
7474
}
7575

7676
/**
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
/**
3+
* Zend Framework (http://framework.zend.com/)
4+
*
5+
* @link http://github.com/zendframework/zf2 for the canonical source repository
6+
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7+
* @license http://framework.zend.com/license/new-bsd New BSD License
8+
*/
9+
10+
namespace Zend\ServiceManager\Exception;
11+
12+
use DomainException;
13+
14+
/**
15+
* @inheritDoc
16+
*/
17+
class ContainerModificationsNotAllowedException extends DomainException implements ExceptionInterface
18+
{
19+
}

src/ServiceManager.php

Lines changed: 141 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use ProxyManager\Configuration as ProxyConfiguration;
1616
use ProxyManager\Factory\LazyLoadingValueHolderFactory;
1717
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
18+
use Zend\ServiceManager\Exception\ContainerModificationsNotAllowedException;
1819
use Zend\ServiceManager\Exception\InvalidArgumentException;
1920
use Zend\ServiceManager\Exception\ServiceNotCreatedException;
2021
use Zend\ServiceManager\Factory\AbstractFactoryInterface;
@@ -53,6 +54,13 @@ class ServiceManager implements ServiceLocatorInterface
5354
*/
5455
protected $aliases = [];
5556

57+
/**
58+
* Whether or not changes may be made to this instance.
59+
*
60+
* @param bool
61+
*/
62+
protected $allowOverride = true;
63+
5664
/**
5765
* @var ContainerInterface
5866
*/
@@ -132,26 +140,6 @@ public function __construct(array $config = [])
132140
$this->configure($config);
133141
}
134142

135-
/**
136-
* Create a new service locator that merges the provided configuration.
137-
*
138-
* Note that the original service locator is left untouched (as with PSR-7
139-
* interfaces).
140-
*
141-
* See {@see \Zend\ServiceManager\ServiceManager::configure()} for details
142-
* on what $config accepts.
143-
*
144-
* @param array $config
145-
* @return ContainerInterface
146-
*/
147-
public function withConfig(array $config)
148-
{
149-
$container = clone $this;
150-
$container->creationContext = ($this === $this->creationContext) ? $container : $this->creationContext;
151-
$container->configure($config);
152-
return $container;
153-
}
154-
155143
/**
156144
* {@inheritDoc}
157145
*/
@@ -230,6 +218,26 @@ public function has($name)
230218
return false;
231219
}
232220

221+
/**
222+
* Indicate whether or not the instance is immutable.
223+
*
224+
* @param bool $flag
225+
*/
226+
public function setAllowOverride($flag)
227+
{
228+
$this->allowOverride = (bool) $flag;
229+
}
230+
231+
/**
232+
* Retrieve the flag indicating immutability status.
233+
*
234+
* @return bool
235+
*/
236+
public function getAllowOverride()
237+
{
238+
return $this->allowOverride;
239+
}
240+
233241
/**
234242
* Configure the service manager
235243
*
@@ -265,10 +273,18 @@ public function has($name)
265273
* should be shared by default.
266274
*
267275
* @param array $config
268-
* @return void
276+
* @return self
277+
* @throws ContainerModificationsNotAllowedException if the allow
278+
* override flag has been toggled off.
269279
*/
270-
protected function configure(array $config)
280+
public function configure(array $config)
271281
{
282+
if ($this->allowOverride === false) {
283+
throw new ContainerModificationsNotAllowedException(
284+
'Overrides have been disabled on this container instance'
285+
);
286+
}
287+
272288
if (isset($config['services'])) {
273289
$this->services = $config['services'] + $this->services;
274290
}
@@ -326,6 +342,109 @@ protected function configure(array $config)
326342
}
327343

328344
$this->resolveAliases();
345+
346+
return $this;
347+
}
348+
349+
/**
350+
* Add an alias.
351+
*
352+
* @param string $alias
353+
* @param string $target
354+
*/
355+
public function setAlias($alias, $target)
356+
{
357+
$this->configure(['aliases' => [$alias => $target]]);
358+
}
359+
360+
/**
361+
* Add an invokable class mapping.
362+
*
363+
* @param string $name Service name
364+
* @param null|string $class Class to which to map; if omitted, $name is
365+
* assumed.
366+
*/
367+
public function setInvokableClass($name, $class = null)
368+
{
369+
$this->configure(['invokables' => [$name => $class ?: $name]]);
370+
}
371+
372+
/**
373+
* Specify a factory for a given service name.
374+
*
375+
* @param string $name Service name
376+
* @param string|callable|Factory\FactoryInterface $factory Factory to which
377+
* to map.
378+
*/
379+
public function setFactory($name, $factory)
380+
{
381+
$this->configure(['factories' => [$name => $factory]]);
382+
}
383+
384+
/**
385+
* Create a lazy service mapping to a class.
386+
*
387+
* @param string $name Service name to map
388+
* @param null|string $class Class to which to map; if not provided, $name
389+
* will be used for the mapping.
390+
*/
391+
public function mapLazyService($name, $class = null)
392+
{
393+
$this->configure(['lazy_services' => ['class_map' => [$name => $class ?: $name]]]);
394+
}
395+
396+
/**
397+
* Add an abstract factory for resolving services.
398+
*
399+
* @param string|Factory\AbstractFactoryInterface $name Service name
400+
*/
401+
public function addAbstractFactory($factory)
402+
{
403+
$this->configure(['abstract_factories' => [$factory]]);
404+
}
405+
406+
/**
407+
* Add a delegator for a given service.
408+
*
409+
* @param string $name Service name
410+
* @param string|callable|Factory\DelegatorFactoryInterface $factory Delegator
411+
* factory to assign.
412+
*/
413+
public function addDelegator($name, $factory)
414+
{
415+
$this->configure(['delegators' => [$name => [$factory]]]);
416+
}
417+
418+
/**
419+
* Add an initializer.
420+
*
421+
* @param string|callable|Initalizer\InitializerInterface $initalizer
422+
*/
423+
public function addInitializer($initializer)
424+
{
425+
$this->configure(['initializers' => [$initializer]]);
426+
}
427+
428+
/**
429+
* Map a service.
430+
*
431+
* @param string $name Service name
432+
* @param array|object $service
433+
*/
434+
public function setService($name, $service)
435+
{
436+
$this->configure(['services' => [$name => $service]]);
437+
}
438+
439+
/**
440+
* Add a service sharing rule.
441+
*
442+
* @param string $name Service name
443+
* @param boolean $flag Whether or not the service should be shared.
444+
*/
445+
public function setShared($name, $flag)
446+
{
447+
$this->configure(['shared' => [$name => (bool) $flag]]);
329448
}
330449

331450
/**

test/AbstractPluginManagerTest.php

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -164,52 +164,4 @@ function ($container, $name, $callback) {
164164
);
165165
$this->assertEquals('bar', $instance->foo);
166166
}
167-
168-
public function testWithConfigProperlySetsCreationContextToOriginalCreationContext()
169-
{
170-
$config = [
171-
'factories' => [
172-
InvokableObject::class => new InvokableFactory(),
173-
],
174-
];
175-
176-
$services = new ServiceManager();
177-
$plugins = new SimplePluginManager($services);
178-
179-
$revised = $plugins->withConfig(['factories' => [
180-
'foo' => function ($container, $name) {
181-
},
182-
]]);
183-
184-
$this->assertAttributeSame($services, 'creationContext', $revised);
185-
}
186-
187-
/**
188-
* Overrides test from CommonServiceLocatorBehaviorsTrait
189-
*
190-
* Behavior of creation context differs for plugin managers.
191-
*/
192-
public function testCanCreateNewLocatorWithMergedConfig()
193-
{
194-
$serviceManager = $this->createContainer([
195-
'factories' => [
196-
DateTime::class => InvokableFactory::class
197-
]
198-
]);
199-
200-
$newServiceManager = $serviceManager->withConfig([
201-
'factories' => [
202-
stdClass::class => InvokableFactory::class
203-
]
204-
]);
205-
206-
$this->assertTrue($serviceManager->has(DateTime::class));
207-
$this->assertFalse($serviceManager->has(stdClass::class));
208-
209-
$this->assertTrue($newServiceManager->has(DateTime::class));
210-
$this->assertTrue($newServiceManager->has(stdClass::class));
211-
212-
// Make sure the context has been updated for the new container
213-
$this->assertAttributeSame($this->creationContext, 'creationContext', $newServiceManager);
214-
}
215167
}

0 commit comments

Comments
 (0)