8000 [DependencyInjection] Tweaked factories · symfony/symfony@ee82392 · GitHub
[go: up one dir, main page]

Skip to content

Commit ee82392

Browse files
committed
[DependencyInjection] Tweaked factories
1 parent 6acf3e7 commit ee82392

17 files changed

+203
-7
lines changed

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,19 @@ public function createService(Definition $definition, $id, $tryProxy = true)
941941

942942
$arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())));
943943

944-
if (null !== $definition->getFactoryMethod()) {
944+
if (null !== $definition->getFactory()) {
945+
$factory = $definition->getFactory();
946+
947+
if (is_string($factory)) {
948+
$callable = $definition->getFactory();
949+
} elseif (is_array($factory)) {
950+
$callable = array($this->resolveServices($factory[0]), $factory[1]);
951+
} else {
952+
throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id));
953+
}
954+
955+
$service = call_user_func_array($callable, $arguments);
956+
} elseif (null !== $definition->getFactoryMethod()) {
945957
if (null !== $definition->getFactoryClass()) {
946958
$factory = $parameterBag->resolveValue($definition->getFactoryClass());
947959
} elseif (null !== $definition->getFactoryService()) {

src/Symfony/Component/DependencyInjection/Definition.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ public function __construct($class = null, array $arguments = array())
6666
*/
6767
public function setFactory($factory)
6868
{
69+
if (is_string($factory) && strpos($factory, '::') !== false) {
70+
$factory = explode('::', $factory, 2);
71+
}
72+
6973
$this->factory = $factory;
7074

7175
return $this;

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 call_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/Loader/YamlFileLoader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ private function parseDefinition($id, $service, $file)
196196

197197
if (isset($service['factory'])) {
198198
if (is_string($service['factory'])) {
199-
if (strpos($service['factory'], ':')) {
199+
if (strpos($service['factory'], ':') !== false && strpos($service['factory'], '::') === false) {
200200
$parts = explode(':', $service['factory']);
201201
$definition->setFactory(array($this->resolveServices('@'.$parts[0]), $parts[1]));
202202
} else {

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/DefinitionTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ public function testConstructor()
3434
public function testSetGetFactory()
3535
{
3636
$def = new Definition('stdClass');
37+
3738
$this->assertSame($def, $def->setFactory('foo'), '->setFactory() implements a fluent interface');
3839
$this->assertEquals('foo', $def->getFactory(), '->getFactory() returns the factory');
40+
41+
$def->setFactory('Foo::bar');
42+
$this->assertEquals(array('Foo', 'bar'), $def->getFactory(), '->setFactory() converts string static method call to the array');
3943
}
4044

4145
public function testSetGetFactoryClass()

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,14 @@ public function testAddService()
120120
}
121121
}
122122

123+
public function testServicesWithAnonymousFactories()
124+
{
125+
$container = include self::$fixturesPath.'/containers/container19.php';
126+
$dumper = new PhpDumper($container);
127+
128+
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services19.php', $dumper->dump(), '->dump() dumps services with anonymous factories');
129+
}
130+
123131
/**
124132
* @expectedException \InvalidArgumentException
125133
* @expectedExceptionMessage Service id "bar$" cannot be converted to a valid PHP method name.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
use Symfony\Component\DependencyInjection\ContainerBuilder;
4+
use Symfony\Component\DependencyInjection\Definition;
5+
6+
require_once __DIR__.'/../includes/classes.php';
7+
8+
$container = new ContainerBuilder();
9+
10+
$container
11+
->register('service_from_anonymous_factory', 'Bar\FooClass')
12+
->setFactory(array(new Definition('Bar\FooClass'), 'getInstance'))
13+
;
14+
15+
$anonymousServiceWithFactory = new Definition('Bar\FooClass');
16+
$anonymousServiceWithFactory->setFactory('Bar\FooClass::getInstance');
17+
$container
18+
->register('service_with_method_call_and_factory', 'Bar\FooClass')
19+
->addMethodCall('setBar', array($anonymousServiceWithFactory))
20+
;
21+
22+
return $container;

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,5 +114,9 @@
114114
->setProperty('foo', 'bar')
115115
->setFactory(array(new Reference('new_factory'), 'getInstance'))
116116
;
117+
$container
118+
->register('service_from_static_method', 'Bar\FooClass')
119+
->setFactory(array('Bar\FooClass', 'getInstance'))
120+
;
117121

118122
return $container;

src/Symfony/Component/DependencyInjection/Tests/Fixtures/graphviz/services9.dot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ digraph sc {
2121
node_decorator_service_with_name [label="decorator_service_with_name\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
2222
node_new_factory [label="new_factory\nFactoryClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
2323
node_new_factory_service [label="new_factory_service\nFooBarBaz\n", shape=record, fillcolor="#eeeeee", style="filled"];
24+
node_service_from_static_method [label="service_from_static_method\nBar\\FooClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
2425
node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"];
2526
node_foo2 [label="foo2\n\n", shape=record, fillcolor="#ff9999", style="filled"];
2627
node_foo3 [label="foo3\n\n", shape=record, fillcolor="#ff9999", style="filled"];
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
'service_from_anonymous_factory' => 'getServiceFromAnonymousFactoryService',
31+
'service_with_method_call_and_factory' => 'getServiceWithMethodCallAndFactoryService',
32+
);
33+
}
34+
35+
/**
36+
* Gets the 'service_from_anonymous_factory' service.
37+
*
38+
* This service is shared.
39+
* This method always returns the same instance of the service.
40+
*
41+
* @return \Bar\FooClass A Bar\FooClass instance.
42+
*/
43+
protected function getServiceFromAnonymousFactoryService()
44+
{
45+
return $this->services['service_from_anonymous_factory'] = call_user_func(array(new \Bar\FooClass(), 'getInstance'));
46+
}
47+
48+
/**
49+
* Gets the 'service_with_method_call_and_factory' service.
50+
*
51+
* This service is shared.
52+
* This method always returns the same instance of the service.
53+
*
54+
* @return \Bar\FooClass A Bar\FooClass instance.
55+
*/
56+
protected function getServiceWithMethodCallAndFactoryService()
57+
{
58+
$this->services['service_with_method_call_and_factory'] = $instance = new \Bar\FooClass();
59+
60+
$instance->setBar(\Bar\FooClass::getInstance());
61+
62+
return $instance;
63+
}
64+
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public function __construct()
4747
'new_factory' => 'getNewFactoryService',
4848
'new_factory_service' => 'getNewFactoryServiceService',
4949
'request' => 'getRequestService',
50+
'service_from_static_method' => 'getServiceFromStaticMethodService',
5051
);
5152
$this->aliases = array(
5253
'alias_for_alias' => 'foo',
@@ -303,6 +304,19 @@ protected function getRequestService()
303304
throw new RuntimeException('You have requested a synthetic service ("request"). The DIC does not know how to construct this service.');
304305
}
305306

307+
/**
308+
* Gets the 'service_from_static_method' service.
309+
*
310+
* This service is shared.
311+
* This method always returns the same instance of the service.
312+
*
313+
* @return \Bar\FooClass A Bar\FooClass instance.
314+
*/
315+
protected function getServiceFromStaticMethodService()
316+
{
317+
return $this->services['service_from_static_method'] = \Bar\FooClass::getInstance();
318+
}
319+
306320
/**
307321
* Updates the 'request' service.
308322
*/

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public function __construct()
5050
'method_call1' => 'getMethodCall1Service',
5151
'new_factory_service' => 'getNewFactoryServiceService',
5252
'request' => 'getRequestService',
53+
'service_from_static_method' => 'getServiceFromStaticMethodService',
5354
);
5455
$this->aliases = array(
5556
'alias_for_alias' => 'foo',
@@ -305,6 +306,19 @@ protected function getRequestService()
305306
throw new RuntimeException('You have requested a synthetic service ("request"). The DIC does not know how to construct this service.');
306307
}
307308

309+
/**
310+
* Gets the 'service_from_static_method' service.
311+
*
312+
* This service is shared.
313+
* This method always returns the same instance of the service.
314+
*
315+
* @return \Bar\FooClass A Bar\FooClass instance.
316+
*/
317+
protected function getServiceFromStaticMethodService()
318+
{
319+
return $this->services['service_from_static_method'] = \Bar\FooClass::getInstance();
320+
}
321+
308322
/**
309323
* Updates the 'request' service.
310324
*/

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@
9898
<property name="foo">bar</property>
9999
<factory service="new_factory" method="getInstance"/>
100100
</service>
101+
<service id="service_from_static_method" class="Bar\FooClass">
102+
<factory class="Bar\FooClass" method="getInstance"/>
103+
</service>
101104
<service id="alias_for_foo" alias="foo"/>
102105
<service id="alias_for_alias" alias="foo"/>
103106
</services>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
services:
22
factory: { class: FooBarClass, factory: baz:getClass}
3+
factory_with_static_call: { class: FooBarClass, factory: FooBacFactory::createFooBar}

src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,8 @@ services:
9696
class: FooBarBaz
9797
properties: { foo: bar }
9898
factory: ['@new_factory', getInstance]
99+
service_from_static_method:
100+
class: Bar\FooClass
101+
factory: [Bar\FooClass, getInstance]
99102
alias_for_foo: @foo
100103
alias_for_alias: @foo

src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@ public function testLoadFactoryShortSyntax()
169169
$loader->load('services14.yml');
170170
$services = $container->getDefinitions();
171171

172-
$this->assertEquals(array(new Reference('baz'), 'getClass'), $services['factory']->getFactory(), '->load() parses the factory tag');
172+
$this->assertEquals(array(new Reference('baz'), 'getClass'), $services['factory']->getFactory(), '->load() parses the factory tag with service:method');
173+
$this->assertEquals(array('FooBacFactory', 'createFooBar'), $services['factory_with_static_call']->getFactory(), '->load() parses the factory tag with Class::method');
173174
}
174175

175176
public function testExtensions()

0 commit comments

Comments
 (0)
0