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

Commit eec98b5

Browse files
committed
Add support for invokable factories to ServiceManager
- If the name and value match, creates a factory mapping the name to an InvokableFactory. - If the name and value DO NOT match, creates an alias of the name to the value, and a factory mapping the value to an InvokableFactory.
1 parent 34f42a8 commit eec98b5

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

src/ServiceManager.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ public function has($name, $checkAbstractFactories = false)
212212
* Valid top keys are:
213213
*
214214
* - services: service name => service instance pairs
215+
* - invokables: service name => class name pairs for classes that do not
216+
* have required constructor arguments; internally, maps the class to an
217+
* InvokableFactory instance, and creates an alias if the service name
218+
* and class name do not match.
215219
* - factories: service name => factory pairs; factories may be any
216220
* callable, string name resolving to an invokable class, or string name
217221
* resolving to a FactoryInterface instance.
@@ -245,6 +249,21 @@ protected function configure(array $config)
245249
$this->services = $config['services'] + $this->services;
246250
}
247251

252+
if (isset($config['invokables']) && ! empty($config['invokables'])) {
253+
$aliases = $this->createAliasesForInvokables($config['invokables']);
254+
$factories = $this->createFactoriesForInvokables($config['invokables']);
255+
256+
if (! empty($aliases)) {
257+
$config['aliases'] = (isset($config['aliases']))
258+
? array_merge($config['aliases'], $aliases)
259+
: $aliases;
260+
}
261+
262+
$config['factories'] = (isset($config['factories']))
263+
? array_merge($config['factories'], $factories)
264+
: $factories;
265+
}
266+
248267
if (isset($config['factories'])) {
249268
$this->factories = $config['factories'] + $this->factories;
250269
}
@@ -577,4 +596,50 @@ private function createLazyServiceDelegatorFactory()
577596

578597
return $this->lazyServicesDelegator;
579598
}
599+
600+
/**
601+
* Create aliases for invokable classes.
602+
*
603+
* If an invokable service name does not match the class it maps to, this
604+
* creates an alias to the class (which will later be mapped as an
605+
* invokable factory).
606+
*
607+
* @param array $invokables
608+
* @return array
609+
*/
610+
private function createAliasesForInvokables(array $invokables)
611+
{
612+
$aliases = [];
613+
foreach ($invokables as $name => $class) {
614+
if ($name === $class) {
615+
continue;
616+
}
617+
$aliases[$name] = $class;
618+
}
619+
return $aliases;
620+
}
621+
622+
/**
623+
* Create invokable factories for invokable classes.
624+
*
625+
* If an invokable service name does not match the class it maps to, this
626+
* creates an invokable factory entry for the class name; otherwise, it
627+
* creates an invokable factory for the entry name.
628+
*
629+
* @param array $invokables
630+
* @return array
631+
*/
632+
private function createFactoriesForInvokables(array $invokables)
633+
{
634+
$factories = [];
635+
foreach ($invokables as $name => $class) {
636+
if ($name === $class) {
637+
$factories[$name] = Factory\InvokableFactory::class;
638+
continue;
639+
}
640+
641+
$factories[$class] = Factory\InvokableFactory::class;
642+
}
643+
return $factories;
644+
}
580645
}

test/ServiceManagerTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,35 @@ public function testShareability($sharedByDefault, $serviceShared, $serviceDefin
148148

149149
$this->assertEquals($shouldBeSameInstance, $a === $b);
150150
}
151+
152+
public function testMapsOneToOneInvokablesAsInvokableFactoriesInternally()
153+
{
154+
$config = [
155+
'invokables' => [
156+
InvokableObject::class => InvokableObject::class,
157+
],
158+
];
159+
160+
$serviceManager = new ServiceManager($config);
161+
$this->assertAttributeSame([
162+
InvokableObject::class => InvokableFactory::class,
163+
], 'factories', $serviceManager, 'Invokable object factory not found');
164+
}
165+
166+
public function testMapsNonSymmetricInvokablesAsAliasPlusInvokableFactory()
167+
{
168+
$config = [
169+
'invokables' => [
170+
'Invokable' => InvokableObject::class,
171+
],
172+
];
173+
174+
$serviceManager = new ServiceManager($config);
175+
$this->assertAttributeSame([
176+
'Invokable' => InvokableObject::class,
177+
], 'aliases', $serviceManager, 'Alias not found for non-symmetric invokable');
178+
$this->assertAttributeSame([
179+
InvokableObject::class => InvokableFactory::class,
180+
], 'factories', $serviceManager, 'Factory not found for non-symmetric invokable target');
181+
}
151182
}

0 commit comments

Comments
 (0)