diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 36a576e99d739..412d4388de2f1 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +5.4 +--- + +* Add `service_closure()` to the PHP-DSL + 5.3 --- diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractConfigurator.php index 475d060432251..e5b1888892af6 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractConfigurator.php @@ -14,6 +14,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator; use Symfony\Component\DependencyInjection\Argument\AbstractArgument; use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Parameter; @@ -77,7 +78,9 @@ public static function processValue($value, $allowServices = false) } if ($value instanceof ReferenceConfigurator) { - return new Reference($value->id, $value->invalidBehavior); + $reference = new Reference($value->id, $value->invalidBehavior); + + return $value instanceof ClosureReferenceConfigurator ? new ServiceClosureArgument($reference) : $reference; } if ($value instanceof InlineServiceConfigurator) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ClosureReferenceConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ClosureReferenceConfigurator.php new file mode 100644 index 0000000000000..ba83d91ef054b --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ClosureReferenceConfigurator.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Loader\Configurator; + +class ClosureReferenceConfigurator extends ReferenceConfigurator +{ +} diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php index c905fcf4962cb..53f96a516a52d 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php @@ -202,3 +202,11 @@ function env(string $name): EnvConfigurator { return new EnvConfigurator($name); } + +/** + * Creates a closure service reference. + */ +function service_closure(string $serviceId): ClosureReferenceConfigurator +{ + return new ClosureReferenceConfigurator($serviceId); +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/services_closure_argument.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/services_closure_argument.php new file mode 100644 index 0000000000000..8864df8a4e842 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/services_closure_argument.php @@ -0,0 +1,15 @@ +services()->defaults()->public(); + + $s->set('foo', 'Foo'); + + $s->set('service_closure', 'Bar') + ->args([service_closure('foo')]); + + $s->set('service_closure_invalid', 'Bar') + ->args([service_closure('invalid_service')->nullOnInvalid()]); +}; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_closure_argument_compiled.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_closure_argument_compiled.php new file mode 100644 index 0000000000000..2a82f2dcc662f --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_closure_argument_compiled.php @@ -0,0 +1,82 @@ +services = $this->privates = []; + $this->methodMap = [ + 'foo' => 'getFooService', + 'service_closure' => 'getServiceClosureService', + 'service_closure_invalid' => 'getServiceClosureInvalidService', + ]; + + $this->aliases = []; + } + + public function compile(): void + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + public function isCompiled(): bool + { + return true; + } + + public function getRemovedIds(): array + { + return [ + 'Psr\\Container\\ContainerInterface' => true, + 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, + ]; + } + + /** + * Gets the public 'foo' shared service. + * + * @return \Foo + */ + protected function getFooService() + { + return $this->services['foo'] = new \Foo(); + } + + /** + * Gets the public 'service_closure' shared service. + * + * @return \Bar + */ + protected function getServiceClosureService() + { + return $this->services['service_closure'] = new \Bar(function () { + return ($this->services['foo'] ?? ($this->services['foo'] = new \Foo())); + }); + } + + /** + * Gets the public 'service_closure_invalid' shared service. + * + * @return \Bar + */ + protected function getServiceClosureInvalidService() + { + return $this->services['service_closure_invalid'] = new \Bar(function () { + return NULL; + }); + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/PhpFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/PhpFileLoaderTest.php index f3dcb820f81fd..4ef80ddaab46c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/PhpFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/PhpFileLoaderTest.php @@ -57,6 +57,17 @@ public function testConfigServices() $this->assertStringEqualsFile($fixtures.'/php/services9_compiled.php', str_replace(str_replace('\\', '\\\\', $fixtures.\DIRECTORY_SEPARATOR.'includes'.\DIRECTORY_SEPARATOR), '%path%', $dumper->dump())); } + public function testConfigServiceClosure() + { + $fixtures = realpath(__DIR__.'/../Fixtures'); + $loader = new PhpFileLoader($container = new ContainerBuilder(), new FileLocator()); + $loader->load($fixtures.'/config/services_closure_argument.php'); + + $container->compile(); + $dumper = new PhpDumper($container); + $this->assertStringEqualsFile($fixtures.'/php/services_closure_argument_compiled.php', $dumper->dump()); + } + /** * @dataProvider provideConfig */