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

Commit fb7340a

Browse files
committed
Ability to disable shared services with Pimple container
By default all services created through the `get` method were shared, first call creates an instance, and every another call return the previously created instance. Providing service name in "shared" allows to disable this functionality for a specific service. Then every call of the `get` method creates brand new instance of the service. It is possoble to disable shared services by default for all services by using `shared_by_default` option to boolean `false`.
1 parent 111a895 commit fb7340a

File tree

3 files changed

+136
-10
lines changed

3 files changed

+136
-10
lines changed

README.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@ $factory = new ContainerFactory();
3232
$container = $factory(
3333
new Config([
3434
'dependencies' => [
35-
'services' => [],
36-
'invokables' => [],
37-
'factories' => [],
38-
'aliases' => [],
39-
'delegators' => [],
40-
'extensions' => [],
35+
'services' => [],
36+
'invokables' => [],
37+
'factories' => [],
38+
'aliases' => [],
39+
'delegators' => [],
40+
'extensions' => [],
41+
'shared' => [],
42+
'shared_by_default' => true,
4143
],
4244
// ... other configuration
4345
])
@@ -62,6 +64,11 @@ The `dependencies` sub associative array can contain the following keys:
6264
for more details.
6365
- `extensions`: an associative array that maps service names to lists of
6466
extension factory names, see the [the section below](#extensions).
67+
- `shared`: associative array that map a service name to a boolean, in order to
68+
indicate the service manager if it should cache or not a service created
69+
through the get method, independant of the shared_by_default setting.
70+
- `shared_by_default`: boolean that indicates whether services created through
71+
the `get` method should be cached. This is `true` by default.
6572

6673
> Please note, that the whole configuration is available in the `$container`
6774
> on `config` key:

src/Config.php

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ public function configureContainer(Container $container)
2929
) {
3030
$dependencies = $this->config['dependencies'];
3131
}
32+
$dependencies['shared_by_default'] = isset($dependencies['shared_by_default'])
33+
? (bool) $dependencies['shared_by_default']
34+
: true;
3235

3336
$this->injectServices($container, $dependencies);
3437
$this->injectFactories($container, $dependencies);
@@ -62,15 +65,15 @@ private function injectFactories(Container $container, array $dependencies)
6265
}
6366

6467
foreach ($dependencies['factories'] as $name => $object) {
65-
$container[$name] = function (Container $c) use ($object, $name) {
68+
$this->setService($container, $dependencies, $name, function (Container $c) use ($object, $name) {
6669
if ($c->offsetExists($object)) {
6770
$factory = $c->offsetGet($object);
6871
} else {
6972
$factory = new $object();
7073
$c[$object] = $c->protect($factory);
7174
}
7275
return $factory(new PsrContainer($c), $name);
73-
};
76+
});
7477
}
7578
}
7679

@@ -83,9 +86,9 @@ private function injectInvokables(Container $container, array $dependencies)
8386
}
8487

8588
foreach ($dependencies['invokables'] as $name => $object) {
86-
$container[$name] = function (Container $c) use ($object) {
89+
$this->setService($container, $dependencies, $name, function (Container $c) use ($object) {
8790
return new $object();
88-
};
91+
});
8992
}
9093
}
9194

@@ -142,4 +145,15 @@ private function injectDelegators(Container $container, array $dependencies)
142145
}
143146
}
144147
}
148+
149+
private function setService(Container $container, array $dependencies, string $name, callable $callback)
150+
{
151+
if (($dependencies['shared_by_default'] === true && ! isset($dependencies['shared'][$name]))
152+
|| (isset($dependencies['shared'][$name]) && $dependencies['shared'][$name] === true)
153+
) {
154+
$container[$name] = $callback;
155+
} else {
156+
$container[$name] = $container->factory($callback);
157+
}
158+
}
145159
}

test/ContainerTest.php

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
/**
3+
* @see https://github.com/zendframework/zend-pimple-config for the canonical source repository
4+
* @copyright Copyright (c) 2018 Zend Technologies USA Inc. (https://www.zend.com)
5+
* @license https://github.com/zendframework/zend-pimple-config/blob/master/LICENSE.md New BSD License
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace ZendTest\Pimple\Config;
11+
12+
use PHPUnit\Framework\TestCase;
13+
use Zend\Pimple\Config\Config;
14+
use Zend\Pimple\Config\ContainerFactory;
15+
16+
class ContainerTest extends TestCase
17+
{
18+
public function config()
19+
{
20+
yield 'factories' => [['factories' => ['service' => TestAsset\Factory::class]]];
21+
yield 'invokables' => [['invokables' => ['service' => TestAsset\Service::class]]];
22+
yield 'aliases-invokables' => [
23+
[
24+
'aliases' => ['service' => TestAsset\Service::class],
25+
'invokables' => [TestAsset\Service::class => TestAsset\Service::class],
26+
],
27+
];
28+
yield 'aliases-factories' => [
29+
[
30+
'aliases' => ['service' => TestAsset\Service::class],
31+
'factories' => [TestAsset\Service::class => TestAsset\Factory::class],
32+
],
33+
];
34+
}
35+
36+
/**
37+
* @dataProvider config
38+
*/
39+
public function testIsSharedByDefault(array $config)
40+
{
41+
$container = $this->createContainer($config);
42+
43+
$service1 = $container->get('service');
44+
$service2 = $container->get('service');
45+
46+
$this->assertSame($service1, $service2);
47+
}
48+
49+
/**
50+
* @dataProvider config
51+
*/
52+
public function testCanDisableSharedByDefault(array $config)
53+
{
54+
$container = $this->createContainer(array_merge($config, [
55+
'shared_by_default' => false,
56+
]));
57+
58+
$service1 = $container->get('service');
59+
$service2 = $container->get('service');
60+
61+
$this->assertNotSame($service1, $service2);
62+
}
63+
64+
/**
65+
* @dataProvider config
66+
*/
67+
public function testCanDisableSharedForSingleService(array $config)
68+
{
69+
$container = $this->createContainer(array_merge($config, [
70+
'shared' => [
71+
'service' => false,
72+
],
73+
]));
74+
75+
$service1 = $container->get('service');
76+
$service2 = $container->get('service');
77+
78+
$this->assertNotSame($service1, $service2);
79+
}
80+
81+
/**
82+
* @dataProvider config
83+
*/
84+
public function testCanEnableSharedForSingleService(array $config)
85+
{
86+
$container = $this->createContainer(array_merge($config, [
87+
'shared_by_default' => false,
88+
'shared' => [
89+
'service' => true,
90+
],
91+
]));
92+
93+
$service1 = $container->get('service');
94+
$service2 = $container->get('service');
95+
96+
$this->assertSame($service1, $service2);
97+
}
98+
99+
private function createContainer(array $config)
100+
{
101+
$factory = new ContainerFactory();
102+
103+
return $factory(new Config(['dependencies' => $config]));
104+
}
105+
}

0 commit comments

Comments
 (0)