[DependencyInjection] Invokable Factory Services
This commit is contained in:
parent
3895acd175
commit
23cb83f726
|
@ -95,7 +95,7 @@ class Definition
|
|||
/**
|
||||
* Sets a factory.
|
||||
*
|
||||
* @param string|array $factory A PHP function or an array containing a class/Reference and a method to call
|
||||
* @param string|array|Reference $factory A PHP function, reference or an array containing a class/Reference and a method to call
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
@ -105,6 +105,8 @@ class Definition
|
|||
|
||||
if (\is_string($factory) && false !== strpos($factory, '::')) {
|
||||
$factory = explode('::', $factory, 2);
|
||||
} elseif ($factory instanceof Reference) {
|
||||
$factory = [$factory, '__invoke'];
|
||||
}
|
||||
|
||||
$this->factory = $factory;
|
||||
|
@ -782,7 +784,7 @@ class Definition
|
|||
/**
|
||||
* Sets a configurator to call after the service is fully initialized.
|
||||
*
|
||||
* @param string|array $configurator A PHP callable
|
||||
* @param string|array|Reference $configurator A PHP function, reference or an array containing a class/Reference and a method to call
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
@ -792,6 +794,8 @@ class Definition
|
|||
|
||||
if (\is_string($configurator) && false !== strpos($configurator, '::')) {
|
||||
$configurator = explode('::', $configurator, 2);
|
||||
} elseif ($configurator instanceof Reference) {
|
||||
$configurator = [$configurator, '__invoke'];
|
||||
}
|
||||
|
||||
$this->configurator = $configurator;
|
||||
|
|
|
@ -317,7 +317,7 @@ class XmlFileLoader extends FileLoader
|
|||
$class = $factory->hasAttribute('class') ? $factory->getAttribute('class') : null;
|
||||
}
|
||||
|
||||
$definition->setFactory([$class, $factory->getAttribute('method')]);
|
||||
$definition->setFactory([$class, $factory->getAttribute('method') ?: '__invoke']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,7 +332,7 @@ class XmlFileLoader extends FileLoader
|
|||
$class = $configurator->getAttribute('class');
|
||||
}
|
||||
|
||||
$definition->setConfigurator([$class, $configurator->getAttribute('method')]);
|
||||
$definition->setConfigurator([$class, $configurator->getAttribute('method') ?: '__invoke']);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -571,12 +571,15 @@ class YamlFileLoader extends FileLoader
|
|||
*
|
||||
* @throws InvalidArgumentException When errors occur
|
||||
*
|
||||
* @return string|array A parsed callable
|
||||
* @return string|array|Reference A parsed callable
|
||||
*/
|
||||
private function parseCallable($callable, $parameter, $id, $file)
|
||||
{
|
||||
if (\is_string($callable)) {
|
||||
if ('' !== $callable && '@' === $callable[0]) {
|
||||
if (false === strpos($callable, ':')) {
|
||||
return [$this->resolveServices($callable, $file), '__invoke'];
|
||||
}
|
||||
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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection\Tests;
|
|||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
class DefinitionTest extends TestCase
|
||||
{
|
||||
|
@ -35,6 +36,9 @@ class DefinitionTest extends TestCase
|
|||
|
||||
$def->setFactory('Foo::bar');
|
||||
$this->assertEquals(['Foo', 'bar'], $def->getFactory(), '->setFactory() converts string static method call to the array');
|
||||
|
||||
$def->setFactory($ref = new Reference('baz'));
|
||||
$this->assertSame([$ref, '__invoke'], $def->getFactory(), '->setFactory() converts service reference to class invoke call');
|
||||
$this->assertSame(['factory' => true], $def->getChanges());
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,9 @@
|
|||
<service id="new_factory4" class="BazClass">
|
||||
<factory method="getInstance" />
|
||||
</service>
|
||||
<service id="new_factory5" class="FooBarClass">
|
||||
<factory service="baz" />
|
||||
</service>
|
||||
<service id="alias_for_foo" alias="foo" />
|
||||
<service id="another_alias_for_foo" alias="foo" public="false" />
|
||||
<service id="0" class="FooClass" />
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
services:
|
||||
factory:
|
||||
class: Baz
|
||||
invalid_factory:
|
||||
class: FooBarClass
|
||||
factory: '@factory:method'
|
|
@ -1,3 +1,4 @@
|
|||
services:
|
||||
factory: { class: FooBarClass, factory: baz:getClass}
|
||||
factory_with_static_call: { class: FooBarClass, factory: FooBacFactory::createFooBar}
|
||||
invokable_factory: { class: FooBarClass, factory: '@factory' }
|
||||
|
|
|
@ -34,6 +34,7 @@ services:
|
|||
new_factory2: { class: FooBarClass, factory: ['@baz', getClass]}
|
||||
new_factory3: { class: FooBarClass, factory: [BazClass, getInstance]}
|
||||
new_factory4: { class: BazClass, factory: [~, getInstance]}
|
||||
new_factory5: { class: FooBarClass, factory: '@baz' }
|
||||
Acme\WithShortCutArgs: [foo, '@baz']
|
||||
alias_for_foo: '@foo'
|
||||
another_alias_for_foo:
|
||||
|
|
|
@ -268,6 +268,7 @@ class XmlFileLoaderTest extends TestCase
|
|||
$this->assertEquals([new Reference('baz'), 'getClass'], $services['new_factory2']->getFactory(), '->load() parses the factory tag');
|
||||
$this->assertEquals(['BazClass', 'getInstance'], $services['new_factory3']->getFactory(), '->load() parses the factory tag');
|
||||
$this->assertSame([null, 'getInstance'], $services['new_factory4']->getFactory(), '->load() accepts factory tag without class');
|
||||
$this->assertEquals([new Reference('baz'), '__invoke'], $services['new_factory5']->getFactory(), '->load() accepts service reference as invokable factory');
|
||||
|
||||
$aliases = $container->getAliases();
|
||||
$this->assertArrayHasKey('alias_for_foo', $aliases, '->load() parses <service> elements');
|
||||
|
|
|
@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\Argument\BoundArgument;
|
|||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
|
@ -158,6 +159,7 @@ class YamlFileLoaderTest extends TestCase
|
|||
$this->assertEquals([new Reference('baz'), 'getClass'], $services['new_factory2']->getFactory(), '->load() parses the factory tag');
|
||||
$this->assertEquals(['BazClass', 'getInstance'], $services['new_factory3']->getFactory(), '->load() parses the factory tag');
|
||||
$this->assertSame([null, 'getInstance'], $services['new_factory4']->getFactory(), '->load() accepts factory tag without class');
|
||||
$this->assertEquals([new Reference('baz'), '__invoke'], $services['new_factory5']->getFactory(), '->load() accepts service reference as invokable factory');
|
||||
$this->assertEquals(['foo', new Reference('baz')], $services['Acme\WithShortCutArgs']->getArguments(), '->load() parses short service definition');
|
||||
|
||||
$aliases = $container->getAliases();
|
||||
|
@ -196,6 +198,16 @@ class YamlFileLoaderTest extends TestCase
|
|||
|
||||
$this->assertEquals([new Reference('baz'), 'getClass'], $services['factory']->getFactory(), '->load() parses the factory tag with service:method');
|
||||
$this->assertEquals(['FooBacFactory', 'createFooBar'], $services['factory_with_static_call']->getFactory(), '->load() parses the factory tag with Class::method');
|
||||
$this->assertEquals([new Reference('factory'), '__invoke'], $services['invokable_factory']->getFactory(), '->load() parses string service reference');
|
||||
}
|
||||
|
||||
public function testFactorySyntaxError()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$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").');
|
||||
$loader->load('bad_factory_syntax.yml');
|
||||
}
|
||||
|
||||
public function testLoadConfiguratorShortSyntax()
|
||||
|
|
Reference in New Issue