Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 23cb83f

Browse files
zanbaldwinfabpot
authored andcommitted
[DependencyInjection] Invokable Factory Services
1 parent 3895acd commit 23cb83f

File tree

10 files changed

+40
-5
lines changed

10 files changed

+40
-5
lines changed

src/Symfony/Component/DependencyInjection/Definition.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public function setChanges(array $changes)
9595
/**
9696
* Sets a factory.
9797
*
98-
* @param string|array $factory A PHP function or an array containing a class/Reference and a method to call
98+
* @param string|array|Reference $factory A PHP function, reference or an array containing a class/Reference and a method to call
9999
*
100100
* @return $this
101101
*/
@@ -105,6 +105,8 @@ public function setFactory($factory)
105105

106106
if (\is_string($factory) && false !== strpos($factory, '::')) {
107107
$factory = explode('::', $factory, 2);
108+
} elseif ($factory instanceof Reference) {
109+
$factory = [$factory, '__invoke'];
108110
}
109111

110112
$this->factory = $factory;
@@ -782,7 +784,7 @@ public function getDeprecationMessage($id)
782784
/**
783785
* Sets a configurator to call after the service is fully initialized.
784786
*
785-
* @param string|array $configurator A PHP callable
787+
* @param string|array|Reference $configurator A PHP function, reference or an array containing a class/Reference and a method to call
786788
*
787789
* @return $this
788790
*/
@@ -792,6 +794,8 @@ public function setConfigurator($configurator)
792794

793795
if (\is_string($configurator) && false !== strpos($configurator, '::')) {
794796
$configurator = explode('::', $configurator, 2);
797+
} elseif ($configurator instanceof Reference) {
798+
$configurator = [$configurator, '__invoke'];
795799
}
796800

797801
$this->configurator = $configurator;

src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults)
317317
$class = $factory->hasAttribute('class') ? $factory->getAttribute('class') : null;
318318
}
319319

320-
$definition->setFactory([$class, $factory->getAttribute('method')]);
320+
$definition->setFactory([$class, $factory->getAttribute('method') ?: '__invoke']);
321321
}
322322
}
323323

@@ -332,7 +332,7 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults)
332332
$class = $configurator->getAttribute('class');
333333
}
334334

335-
$definition->setConfigurator([$class, $configurator->getAttribute('method')]);
335+
$definition->setConfigurator([$class, $configurator->getAttribute('method') ?: '__invoke']);
336336
}
337337
}
338338

src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,12 +571,15 @@ private function parseDefinition($id, $service, $file, array $defaults)
571571
*
572572
* @throws InvalidArgumentException When errors occur
573573
*
574-
* @return string|array A parsed callable
574+
* @return string|array|Reference A parsed callable
575575
*/
576576
private function parseCallable($callable, $parameter, $id, $file)
577577
{
578578
if (\is_string($callable)) {
579579
if ('' !== $callable && '@' === $callable[0]) {
580+
if (false === strpos($callable, ':')) {
581+
return [$this->resolveServices($callable, $file), '__invoke'];
582+
}
580583
throw new InvalidArgumentException(sprintf('The value of the "%s" option for the "%s" service must be the id of the service without the "@" prefix (replace "%s" with "%s").', $parameter, $id, $callable, substr($callable, 1)));
581584
}
582585

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\DependencyInjection\Definition;
16+
use Symfony\Component\DependencyInjection\Reference;
1617

1718
class DefinitionTest extends TestCase
1819
{
@@ -35,6 +36,9 @@ public function testSetGetFactory()
3536

3637
$def->setFactory('Foo::bar');
3738
$this->assertEquals(['Foo', 'bar'], $def->getFactory(), '->setFactory() converts string static method call to the array');
39+
40+
$def->setFactory($ref = new Reference('baz'));
41+
$this->assertSame([$ref, '__invoke'], $def->getFactory(), '->setFactory() converts service reference to class invoke call');
3842
$this->assertSame(['factory' => true], $def->getChanges());
3943
}
4044

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@
5959
<service id="new_factory4" class="BazClass">
6060
<factory method="getInstance" />
6161
</service>
62+
<service id="new_factory5" class="FooBarClass">
63+
<factory service="baz" />
64+
</service>
6265
<service id="alias_for_foo" alias="foo" />
6366
<service id="another_alias_for_foo" alias="foo" public="false" />
6467
<service id="0" class="FooClass" />
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
services:
2+
factory:
3+
class: Baz
4+
invalid_factory:
5+
class: FooBarClass
6+
factory: '@factory:method'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
services:
22
factory: { class: FooBarClass, factory: baz:getClass}
33
factory_with_static_call: { class: FooBarClass, factory: FooBacFactory::createFooBar}
4+
invokable_factory: { class: FooBarClass, factory: '@factory' }

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ services:
3434
new_factory2: { class: FooBarClass, factory: ['@baz', getClass]}
3535
new_factory3: { class: FooBarClass, factory: [BazClass, getInstance]}
3636
new_factory4: { class: BazClass, factory: [~, getInstance]}
37+
new_factory5: { class: FooBarClass, factory: '@baz' }
3738
Acme\WithShortCutArgs: [foo, '@baz']
3839
alias_for_foo: '@foo'
3940
another_alias_for_foo:

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ public function testLoadServices()
268268
$this->assertEquals([new Reference('baz'), 'getClass'], $services['new_factory2']->getFactory(), '->load() parses the factory tag');
269269
$this->assertEquals(['BazClass', 'getInstance'], $services['new_factory3']->getFactory(), '->load() parses the factory tag');
270270
$this->assertSame([null, 'getInstance'], $services['new_factory4']->getFactory(), '->load() accepts factory tag without class');
271+
$this->assertEquals([new Reference('baz'), '__invoke'], $services['new_factory5']->getFactory(), '->load() accepts service reference as invokable factory');
271272

272273
$aliases = $container->getAliases();
273274
$this->assertArrayHasKey('alias_for_foo', $aliases, '->load() parses <service> elements');

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
2121
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
2222
use Symfony\Component\DependencyInjection\ContainerBuilder;
23+
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
2324
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
2425
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
2526
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
@@ -158,6 +159,7 @@ public function testLoadServices()
158159
$this->assertEquals([new Reference('baz'), 'getClass'], $services['new_factory2']->getFactory(), '->load() parses the factory tag');
159160
$this->assertEquals(['BazClass', 'getInstance'], $services['new_factory3']->getFactory(), '->load() parses the factory tag');
160161
$this->assertSame([null, 'getInstance'], $services['new_factory4']->getFactory(), '->load() accepts factory tag without class');
162+
$this->assertEquals([new Reference('baz'), '__invoke'], $services['new_factory5']->getFactory(), '->load() accepts service reference as invokable factory');
161163
$this->assertEquals(['foo', new Reference('baz')], $services['Acme\WithShortCutArgs']->getArguments(), '->load() parses short service definition');
162164

163165
$aliases = $container->getAliases();
@@ -196,6 +198,16 @@ public function testLoadFactoryShortSyntax()
196198

197199
$this->assertEquals([new Reference('baz'), 'getClass'], $services['factory']->getFactory(), '->load() parses the factory tag with service:method');
198200
$this->assertEquals(['FooBacFactory', 'createFooBar'], $services['factory_with_static_call']->getFactory(), '->load() parses the factory tag with Class::method');
201+
$this->assertEquals([new Reference('factory'), '__invoke'], $services['invokable_factory']->getFactory(), '->load() parses string service reference');
202+
}
203+
204+
public function testFactorySyntaxError()
205+
{
206+
$container = new ContainerBuilder();
207+
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
208+
$this->expectException(InvalidArgumentException::class);
209+
$this->expectExceptionMessage('The value of the "factory" option for the "invalid_factory" service must be the id of the service without the "@" prefix (replace "@factory:method" with "factory:method").');
210+
$loader->load('bad_factory_syntax.yml');
199211
}
200212

201213
public function testLoadConfiguratorShortSyntax()

0 commit comments

Comments
 (0)