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

Skip to content

Commit cf905b7

Browse files
committed
[DependencyInjection] Tweaked factories as callables feature
1 parent 1c24006 commit cf905b7

File tree

7 files changed

+216
-21
lines changed

7 files changed

+216
-21
lines changed

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

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

957957
$service = call_user_func_array(array($factory, $definition->getFactoryMethod()), $arguments);
958+
} elseif (null !== $definition->getFactory()) {
959+
$factory = $definition->getFactory();
960+
961+
if (is_string($factory)) {
962+
$callable = $definition->getFactory();
963+
} elseif (is_array($factory)) {
964+
$callable = array($this->resolveServices($factory[0]), $factory[1]);
965+
} else {
966+
throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id));
967+
}
968+
969+
$service = call_user_func_array($callable, $arguments);
958970
} else {
959971
$r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
960972

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

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -730,13 +730,13 @@ private function addNewInstance($id, Definition $definition, $return, $instantia
730730
$class = $this->dumpValue($callable[0]);
731731
// If the class is a string we can optimize cal 9E88 l_user_func away
732732
if (strpos($class, "'") === 0) {
733-
return sprintf(" $return{$instantiation}\%s::%s(%s);\n", substr($class, 1, -1), $callable[1], $arguments ? implode(', ', $arguments) : '');
733+
return sprintf(" $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : '');
734734
}
735735

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

739-
return sprintf(" $return{$instantiation}%s(%s);\n", $callable, $arguments ? implode(', ', $arguments) : '');
739+
return sprintf(" $return{$instantiation}\\%s(%s);\n", $callable, $arguments ? implode(', ', $arguments) : '');
740740
} elseif (null !== $definition->getFactoryMethod()) {
741741
if (null !== $definition->getFactoryClass()) {
742742
$class = $this->dumpValue($definition->getFactoryClass());
@@ -1212,7 +1212,7 @@ private function hasReference($id, array $arguments, $deep = false, array $visit
12121212
/**
12131213
* Dumps values.
12141214
*
1215-
* @param array $value
1215+
* @param mixed $value
12161216
* @param bool $interpolate
12171217
*
12181218
* @return string
@@ -1249,6 +1249,30 @@ private function dumpValue($value, $interpolate = true)
12491249
throw new RuntimeException('Cannot dump definitions which have a variable class name.');
12501250
}
12511251

1252+
if (null !== $value->getFactory()) {
1253+
$factory = $value->getFactory();
1254+
1255+
if (is_string($factory)) {
1256+
return sprintf('\\%s(%s)', $factory, implode(', ', $arguments));
1257+
}
1258+
1259+
if (is_array($factory)) {
1260+
if (is_string($factory[0])) {
1261+
return sprintf('\\%s::%s(%s)', $factory[0], $factory[1], implode(', ', $arguments));
1262+
}
1263+
1264+
if ($factory[0] instanceof Definition) {
1265+
return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($factory[0]), $factory[1], count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
1266+
}
1267+
1268+
if ($factory[0] instanceof Reference) {
1269+
return sprintf('%s->%s(%s)', $this->dumpValue($factory[0]), $factory[1], implode(', ', $arguments));
1270+
}
1271+
}
1272+
1273+
throw new RuntimeException('Cannot dump definition because of invalid factory');
1274+
}
1275+
12521276
if (null !== $value->getFactoryMethod()) {
12531277
if (null !== $value->getFactoryClass()) {
12541278
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: 17 additions & 0 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
*/

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,14 @@ public function testAddService()
101101
// without compilation
102102
$container = include self::$fixturesPath.'/containers/container9.php';
103103
$dumper = new PhpDumper($container);
104+
104105
$this->assertEquals(str_replace('%path%', str_replace('\\','\\\\',self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), file_get_contents(self::$fixturesPath.'/php/services9.php')), $dumper->dump(), '->dump() dumps services');
105106

106107
// with compilation
107108
$container = include self::$fixturesPath.'/containers/container9.php';
108109
$container->compile();
109110
$dumper = new PhpDumper($container);
111+
110112
$this->assertEquals(str_replace('%path%', str_replace('\\','\\\\',self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), file_get_contents(self::$fixturesPath.'/php/services9_compiled.php')), $dumper->dump(), '->dump() dumps services');
111113

112114
$dumper = new PhpDumper($container = new ContainerBuilder());

src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Symfony\Component\DependencyInjection\ContainerInterface;
66
use Symfony\Component\DependencyInjection\ContainerBuilder;
7+
use Symfony\Component\DependencyInjection\Definition;
78
use Symfony\Component\DependencyInjection\Reference;
89
use Symfony\Component\DependencyInjection\Parameter;
910
use Symfony\Component\ExpressionLanguage\Expression;
@@ -110,9 +111,28 @@
110111
->setPublic(false)
111112
;
112113
$container
113-
->register('new_factory_service', 'FooBarBaz')
114+
->register('service_from_referenced_factory', 'FooBarBaz')
114115
->setProperty('foo', 'bar')
115116
->setFactory(array(new Reference('new_factory'), 'getInstance'))
116117
;
118+
$container
119+
->register('service_from_anonymous_factory', 'Bar\FooClass')
120+
->setFactory(array(new Definition('Bar\FooClass'), 'getInstance'))
121+
;
122+
123+
$container
124+
->register('service_from_static_method1', 'Bar\FooClass')
125+
->setFactory('Bar\FooClass::getInstance')
126+
;
127+
$container
128+
->register('service_from_static_method2', 'Bar\FooClass')
129+
->setFactory(array('Bar\FooClass', 'getInstance'))
130+
;
131+
$anonymousServiceWithFactory = new Definition('Bar\FooClass');
132+
$anonymousServiceWithFactory->setFactory('Bar\FooClass::getInstance');
133+
$container
134+
->register('service_with_method_call_and_factory', 'Bar\FooClass')
135+
->addMethodCall('setBar', array($anonymousServiceWithFactory))
136+
;
117137

118138
return $container;

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,12 @@ public function __construct()
4545
'inlined' => 'getInlinedService',
4646
'method_call1' => 'getMethodCall1Service',
4747
'new_factory' => 'getNewFactoryService',
48-
'new_factory_service' => 'getNewFactoryServiceService',
4948
'request' => 'getRequestService',
49+
'service_from_anonymous_factory' => 'getServiceFromAnonymousFactoryService',
50+
'service_from_referenced_factory' => 'getServiceFromReferencedFactoryService',
51+
'service_from_static_method1' => 'getServiceFromStaticMethod1Service',
52+
'service_from_static_method2' => 'getServiceFromStaticMethod2Service',
53+
'service_with_method_call_and_factory' => 'getServiceWithMethodCallAndFactoryService',
5054
);
5155
$this->aliases = array(
5256
'alias_for_alias' => 'foo',
@@ -274,33 +278,89 @@ protected function getMethodCall1Service()
274278
}
275279

276280
/**
277-
* Gets the 'new_factory_service' service.
281+
* Gets the 'request' service.
282+
*
283+
* This service is shared.
284+
* This method always returns the same instance of the service.
285+
*
286+
* @throws RuntimeException always since this service is expected to be injected dynamically
287+
*/
288+
protected function getRequestService()
289+
{
290+
throw new RuntimeException('You have requested a synthetic service ("request"). The DIC does not know how to construct this service.');
291+
}
292+
293+
/**
294+
* Gets the 'service_from_anonymous_factory' service.
295+
*
296+
* This service is shared.
297+
* This method always returns the same instance of the service.
298+
*
299+
* @return \Bar\FooClass A Bar\FooClass instance.
300+
*/
301+
protected function getServiceFromAnonymousFactoryService()
302+
{
303+
return $this->services['service_from_anonymous_factory'] = call_user_func(array(new \Bar\FooClass(), 'getInstance'));
304+
}
305+
306+
/**
307+
* Gets the 'service_from_referenced_factory' service.
278308
*
279309
* This service is shared.
280310
* This method always returns the same instance of the service.
281311
*
282312
* @return \FooBarBaz A FooBarBaz instance.
283313
*/
284-
protected function getNewFactoryServiceService()
314+
protected function getServiceFromReferencedFactoryService()
285315
{
286-
$this->services['new_factory_service'] = $instance = $this->get('new_factory')->getInstance();
316+
$this->services['service_from_referenced_factory'] = $instance = $this->get('new_factory')->getInstance();
287317

288318
$instance->foo = 'bar';
289319

290320
return $instance;
291321
}
292322

293323
/**
294-
* Gets the 'request' service.
324+
* Gets the 'service_from_static_method1' service.
295325
*
296326
* This service is shared.
297327
* This method always returns the same instance of the service.
298328
*
299-
* @throws RuntimeException always since this service is expected to be injected dynamically
329+
* @return \Bar\FooClass A Bar\FooClass instance.
300330
*/
301-
protected function getRequestService()
331+
protected function getServiceFromStaticMethod1Service()
302332
{
303-
throw new RuntimeException('You have requested a synthetic service ("request"). The DIC does not know how to construct this service.');
333+
return $this->services['service_from_static_method1'] = \Bar\FooClass::getInstance();
334+
}
335+
336+
/**
337+
* Gets the 'service_from_static_method2' service.
338+
*
339+
* This service is shared.
340+
* This method always returns the same instance of the service.
341+
*
342+
* @return \Bar\FooClass A Bar\FooClass instance.
343+
*/
344+
protected function getServiceFromStaticMethod2Service()
345+
{
346+
return $this->services['service_from_static_method2'] = \Bar\FooClass::getInstance();
347+
}
348+
349+
/**
350+
* Gets the 'service_with_method_call_and_factory' service.
351+
*
352+
* This service is shared.
353+
* This method always returns the same instance of the service.
354+
*
355+
* @return \Bar\FooClass A Bar\FooClass instance.
356+
*/
357+
protected function getServiceWithMethodCallAndFactoryService()
358+
{
359+
$this->services['service_with_method_call_and_factory'] = $instance = new \Bar\FooClass();
360+
361+
$instance->setBar(\Bar\FooClass::getInstance());
362+
363+
return $instance;
304364
}
305365

306366
/**

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,12 @@ public function __construct()
4848
'foo_bar' => 'getFooBarService',
4949
'foo_with_inline' => 'getFooWithInlineService',
5050
'method_call1' => 'getMethodCall1Service',
51-
'new_factory_service' => 'getNewFactoryServiceService',
5251
'request' => 'getRequestService',
52+
'service_from_anonymous_factory' => 'getServiceFromAnonymousFactoryService',
53+
'service_from_referenced_factory' => 'getServiceFromReferencedFactoryService',
54+
'service_from_static_method1' => 'getServiceFromStaticMethod1Service',
55+
'service_from_static_method2' => 'getServiceFromStaticMethod2Service',
56+
'service_with_method_call_and_factory' => 'getServiceWithMethodCallAndFactoryService',
5357
);
5458
$this->aliases = array(
5559
'alias_for_alias' => 'foo',
@@ -273,36 +277,92 @@ protected function getMethodCall1Service()
273277
}
274278

275279
/**
276-
* Gets the 'new_factory_service' service.
280+
* Gets the 'request' service.
281+
*
282+
* This service is shared.
283+
* This method always returns the same instance of the service.
284+
*
285+
* @throws RuntimeException always since this service is expected to be injected dynamically
286+
*/
287+
protected function getRequestService()
288+
{
289+
throw new RuntimeException('You have requested a synthetic service ("request"). The DIC does not know how to construct this service.');
290+
}
291+
292+
/**
293+
* Gets the 'service_from_anonymous_factory' service.
294+
*
295+
* This service is shared.
296+
* This method always returns the same instance of the service.
297+
*
298+
* @return \Bar\FooClass A Bar\FooClass instance.
299+
*/
300+
protected function getServiceFromAnonymousFactoryService()
301+
{
302+
return $this->services['service_from_anonymous_factory'] = call_user_func(array(new \Bar\FooClass(), 'getInstance'));
303+
}
304+
305+
/**
306+
* Gets the 'service_from_referenced_factory' service.
277307
*
278308
* This service is shared.
279309
* This method always returns the same instance of the service.
280310
*
281311
* @return \FooBarBaz A FooBarBaz instance.
282312
*/
283-
protected function getNewFactoryServiceService()
313+
protected function getServiceFromReferencedFactoryService()
284314
{
285315
$a = new \FactoryClass();
286316
$a->foo = 'bar';
287317

288-
$this->services['new_factory_service'] = $instance = $a->getInstance();
318+
$this->services['service_from_referenced_factory'] = $instance = $a->getInstance();
289319

290320
$instance->foo = 'bar';
291321

292322
return $instance;
293323
}
294324

295325
/**
296-
* Gets the 'request' service.
326+
* Gets the 'service_from_static_method1' service.
297327
*
298328
* This service is shared.
299329
* This method always returns the same instance of the service.
300330
*
301-
* @throws RuntimeException always since this service is expected to be injected dynamically
331+
* @return \Bar\FooClass A Bar\FooClass instance.
302332
*/
303-
protected function getRequestService()
333+
protected function getServiceFromStaticMethod1Service()
304334
{
305-
throw new RuntimeException('You have requested a synthetic service ("request"). The DIC does not know how to construct this service.');
335+
return $this->services['service_from_static_method1'] = \Bar\FooClass::getInstance();
336+
}
337+
338+
/**
339+
* Gets the 'service_from_static_method2' service.
340+
*
341+
* This service is shared.
342+
* This method always returns the same instance of the service.
343+
*
344+
* @return \Bar\FooClass A Bar\FooClass instance.
345+
*/
346+
protected function getServiceFromStaticMethod2Service()
347+
{
348+
return $this->services['service_from_static_method2'] = \Bar\FooClass::getInstance();
349+
}
350+
351+
/**
352+
* Gets the 'service_with_method_call_and_factory' service.
353+
*
354+
* This service is shared.
355+
* This method always returns the same instance of the service.
356+
*
357+
* @return \Bar\FooClass A Bar\FooClass instance.
358+
*/
359+
protected function getServiceWithMethodCallAndFactoryService()
360+
{
361+
$this->services['service_with_method_call_and_factory'] = $instance = new \Bar\FooClass();
362+
363+
$instance->setBar(\Bar\FooClass::getInstance());
364+
365+
return $instance;
306366
}
307367

308368
/**

0 commit comments

Comments
 (0)
0