8000 [DependencyInjection] Tweaked factories as callables feature · symfony/symfony@4264436 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4264436

Browse files
committed
[DependencyInjection] Tweaked factories as callables feature
1 parent 4e0021b commit 4264436

File tree

5 files changed

+190
-20
lines changed

5 files changed

+190
-20
lines changed

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,18 @@ public function createService(Definition $definition, $id, $tryProxy = true)
949949
}
950950

951951
$service = call_user_func_array(array($factory, $definition->getFactoryMethod()), $arguments);
952+
} elseif (null !== $definition->getFactory()) {
953+
$factory = $definition->getFactory();
954+
955+
if (is_string($factory)) {
956+
$callable = $definition->getFactory();
957+
} elseif (is_array($factory)) {
958+
$callable = array($this->resolveServices($factory[0]), $factory[1]);
959+
} else {
960+
throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id));
961+
}
962+
963+
$service = call_user_func_array($callable, $arguments);
952964
} else {
953965
$r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
954966

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,7 @@ public function dump(array $options = array())
118118
$this->addServices().
119119
$this->addDefaultParametersMethod().
120120
$this->endClass().
121-
$this->addProxyClasses()
122-
;
121+
$this->addProxyClasses();
123122

124123
return $code;
125124
}
@@ -618,8 +617,7 @@ private function addService($id, $definition)
618617
$this->addServiceMethodCalls($id, $definition).
619618
$this->addServiceProperties($id, $definition).
620619
$this->addServiceConfigurator($id, $definition).
621-
$this->addServiceReturn($id, $definition)
622-
;
620+
$this->addServiceReturn($id, $definition);
623621
}
624622

625623
$this->definitionVariables = null;
@@ -724,13 +722,13 @@ private function addNewInstance($id, Definition $definition, $return, $instantia
724722
$class = $this->dumpValue($callable[0]);
725723
// If the class is a string we can optimize call_user_func away
726724
if (strpos($class, "'") === 0) {
727-
return sprintf(" $return{$instantiation}\%s::%s(%s);\n", substr($class, 1, -1), $callable[1], $arguments ? implode(', ', $arguments) : '');
725+
return sprintf(" $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : '');
728726
}
729727

730-
return sprintf(" $return{$instantiation}call_user_func(array(%s, '%s'), %s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? ', '.implode(', ', $arguments) : '');
728+
return sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? ', '.implode(', ', $arguments) : '');
731729
}
732730

733-
return sprintf(" $return{$instantiation}%s(%s);\n", $callable, $arguments ? implode(', ', $arguments) : '');
731+
return sprintf(" $return{$instantiation}\\%s(%s);\n", $callable, $arguments ? implode(', ', $arguments) : '');
734732
} elseif (null !== $definition->getFactoryMethod()) {
735733
if (null !== $definition->getFactoryClass()) {
736734
$class = $this->dumpValue($definition->getFactoryClass());
@@ -1206,7 +1204,7 @@ private function hasReference($id, array $arguments, $deep = false, array $visit
12061204
/**
12071205
* Dumps values.
12081206
*
1209-
* @param array $value
1207+
* @param mixed $value
12101208
* @param bool $interpolate
12111209
*
12121210
* @return string
@@ -1243,6 +1241,30 @@ private function dumpValue($value, $interpolate = true)
12431241
throw new RuntimeException('Cannot dump definitions which have a variable class name.');
12441242
}
12451243

1244+
if (null !== $value->getFactory()) {
1245+
$factory = $value->getFactory();
1246+
1247+
if (is_string($factory)) {
1248+
return sprintf('\\%s(%s)', $factory, implode(', ', $arguments));
1249+
}
1250+
1251+
if (is_array($factory)) {
1252+
if (is_string($factory[0])) {
1253+
return sprintf('\\%s::%s(%s)', $factory[0], $factory[1], implode(', ', $arguments));
1254+
}
1255+
1256+
if ($factory[0] instanceof Definition) {
1257+
return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($factory[0]), $factory[1], count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
1258+
}
1259+
1260+
if ($factory[0] instanceof Reference) {
1261+
return sprintf('%s->%s(%s)', $this->dumpValue($factory[0]), $factory[1], implode(', ', $arguments));
1262+
}
1263+
}
1264+
1265+
throw new RuntimeException('Cannot dump definition because of invalid factory');
1266+
}
1267+
12461268
if (null !== $value->getFactoryMethod()) {
12471269
if (null !== $value->getFactoryClass()) {
12481270
return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($value->getFactoryClass()), $value->getFactoryMethod(), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');

src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,23 @@ public function testCreateServiceFactoryService()
341341
$this->assertInstanceOf('BazClass', $builder->get('baz_service'));
342342
}
343343

344+
/**
345+
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::createService
346+
*/
347+
public function testCreateServiceFactory()
348+
{
349+
$builder = new ContainerBuilder();
350+
$builder->register('foo', 'Bar\FooClass')->setFactory('Bar\FooClass::getInstance');
351+
$builder->register('qux', 'Bar\FooClass')->setFactory(array('Bar\FooClass', 'getInstance'));
352+
$builder->register('bar', 'Bar\FooClass')->setFactory(array(new Definition('Bar\FooClass'), 'getInstance'));
353+
$builder->register('baz', 'Bar\FooClass')->setFactory(array(new Reference('bar'), 'getInstance'));
354+
355+
$this->assertTrue($builder->get('foo')->called, '->createService() calls the factory method to create the service instance');
356+
$this->assertTrue($builder->get('qux')->called, '->createService() calls the factory method to create the service instance');
357+
$this->assertTrue($builder->get('bar')->called, '->createService() uses anonymous service as factory');
358+
$this->assertTrue($builder->get('baz')->called, '->createService() uses another service as factory');
359+
}
360+
344361
/**
345362
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::createService
346363
*/
@@ -480,8 +497,8 @@ public function testfindTaggedServiceIds()
480497
->register('foo', 'Bar\FooClass')
481498
->addTag('foo', array('foo' => 'foo'))
482499
->addTag('bar', array('bar' => 'bar'))
483-
->addTag('foo', array('foofoo' => 'foofoo'))
484-
;
500+
->addTag('foo', array('foofoo' => 'foofoo'));
501+
485502
$this->assertEquals($builder->findTaggedServiceIds('foo'), array(
486503
'foo' => array(
487504
array('foo' => 'foo'),
@@ -695,12 +712,8 @@ public function testNoExceptionWhenSetSyntheticServiceOnAFrozenContainer()
695712
public function testSetOnSynchronizedService()
696713
{
697714
$container = new ContainerBuilder();
698-
$container->register('baz', 'BazClass')
699-
->setSynchronized(true)
700-
;
701-
$container->register('bar', 'BarClass')
702-
->addMethodCall('setBaz', array(new Reference('baz')))
703-
;
715+
$container->register('baz', 'BazClass')->setSynchronized(true);
716+
$container->register('bar', 'BarClass')->addMethodCall('setBaz', array(new Reference('baz')));
704717

705718
$container->set('baz', $baz = new \BazClass());
706719
$this->assertSame($baz, $container->get('bar')->getBaz());
@@ -716,11 +729,9 @@ public function testSynchronizedServiceWithScopes()
716729
$container->register('baz', 'BazClass')
717730
->setSynthetic(true)
718731
->setSynchronized(true)
719-
->setScope('foo')
720-
;
732+
->setScope('foo');
721733
$container->register('bar', 'BarClass')
722-
->addMethodCall('setBaz', array(new Reference('baz', ContainerInterface::NULL_ON_INVALID_REFERENCE, false)))
723-
;
734+
->addMethodCall('setBaz', array(new Reference('baz', ContainerInterface::NULL_ON_INVALID_REFERENCE, false)));
724735
$container->compile();
725736

726737
$container->enterScope('foo');

src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,4 +196,23 @@ public function testCircularReference()
196196< F438 /code>
$dumper = new PhpDumper($container);
197197
$dumper->dump();
198198
}
199+
200+
public function testServiceFactoryDumping()
201+
{
202+
require_once self::$fixturesPath.'/includes/foo.php';
203+
204+
$container = new ContainerBuilder();
205+
206+
$container->register('foo', 'Bar\FooClass')->setFactory('Bar\FooClass::getInstance');
207+
$container->register('qux', 'Bar\FooClass')->setFactory(array('Bar\FooClass', 'getInstance'));
208+
$container->register('bar', 'Bar\FooClass')->setFactory(array(new Definition('Bar\FooClass'), 'getInstance'));
209+
$container->register('baz', 'Bar\FooClass')->setFactory(array(new Reference('bar'), 'getInstance'));
210+
211+
$anonymousServiceWithFactory = new Definition('Bar\FooClass');
212+
$anonymousServiceWithFactory->setFactory('Bar\FooClass::getInstance');
213+
$container->register('quux', 'Bar\FooClass')->addMethodCall('setBar', array($anonymousServiceWithFactory));
214+
215+
$dumper = new PhpDumper($container);
216+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services12.php', $dumper->dump());
217+
}
199218
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
use Symfony\Component\DependencyInjection\ContainerInterface;
4+
use Symfony\Component\DependencyInjection\Container;
5+
use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
6+
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
7+
use Symfony\Component\DependencyInjection\Exception\LogicException;
8+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
9+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
10+
11+
/**
12+
* ProjectServiceContainer
13+
*
14+
* This class has been auto-generated
15+
* by the Symfony Dependency Injection Component.
16+
*/
17+
class ProjectServiceContainer extends Container
18+
{
19+
private static $parameters = array(
20+
21+
);
22+
23+
/**
24+
* Constructor.
25+
*/
26+
public function __construct()
27+
{
28+
parent::__construct(new ParameterBag(self::$parameters));
29+
$this->methodMap = array(
30+
'bar' => 'getBarService',
31+
'baz' => 'getBazService',
32+
'foo' => 'getFooService',
33+
'quux' => 'getQuuxService',
34+
'qux' => 'getQuxService',
35+
);
36+
}
37+
38+
/**
39+
* Gets the 'bar' service.
40+
*
41+
* This service is shared.
42+
* This method always returns the same instance of the service.
43+
*
44+
* @return \Bar\FooClass A Bar\FooClass instance.
45+
*/
46+
protected function getBarService()
47+
{
48+
return $this->services['bar'] = call_user_func(array(new \Bar\FooClass(), 'getInstance'));
49+
}
50+
51+
/**
52+
* Gets the 'baz' service.
53+
*
54+
* This service is shared.
55+
* This method always returns the same instance of the service.
56+
*
57+
* @return \Bar\FooClass A Bar\FooClass instance.
58+
*/
59+
protected function getBazService()
60+
{
61+
return $this->services['baz'] = $this->get('bar')->getInstance();
62+
}
63+
64+
/**
65+
* Gets the 'foo' service.
66+
*
67+
* This service is shared.
68+
* This method always returns the same instance of the service.
69+
*
70+
* @return \Bar\FooClass A Bar\FooClass instance.
71+
*/
72+
protected function getFooService()
73+
{
74+
return $this->services['foo'] = \Bar\FooClass::getInstance();
75+
}
76+
77+
/**
78+
* Gets the 'quux' service.
79+
*
80+
* This service is shared.
81+
* This method always returns the same instance of the service.
82+
*
83+
* @return \Bar\FooClass A Bar\FooClass instance.
84+
*/
85+
protected function getQuuxService()
86+
{
87+
$this->services['quux'] = $instance = new \Bar\FooClass();
88+
89+
$instance->setBar(\Bar\FooClass::getInstance());
90+
91+
return $instance;
92+
}
93+
94+
/**
95+
* Gets the 'qux' service.
96+
*
97+
* This service is shared.
98+
* This method always returns the same instance of the service.
99+
*
100+
* @return \Bar\FooClass A Bar\FooClass instance.
101+
*/
102+
protected function getQuxService()
103+
{
104+
return $this->services['qux'] = \Bar\FooClass::getInstance();
105+
}
106+
}

0 commit comments

Comments
 (0)
0