From e33a0b0f943bbc86f5d46cc15fd6837599b166a8 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 30 Sep 2020 17:20:21 +0200 Subject: [PATCH] [DI] fix dumping non-shared lazy services --- .../DependencyInjection/Dumper/PhpDumper.php | 39 ++++++++++++++++--- .../Tests/Dumper/PhpDumperTest.php | 1 + .../Fixtures/php/services_non_shared_lazy.php | 8 ++-- .../php/services_non_shared_lazy_as_files.txt | 36 ++++++++++++++--- 4 files changed, 68 insertions(+), 16 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index fd25b64f7a..b504a8fc21 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -863,18 +863,45 @@ EOF; } } - if ($this->getProxyDumper()->isProxyCandidate($definition)) { - $factoryCode = $definition->isShared() ? ($asFile ? "\$this->load('%s', false)" : '$this->%s(false)') : '$this->factories[%2$s](false)'; - $factoryCode = $this->getProxyDumper()->getProxyFactoryCode($definition, $id, sprintf($factoryCode, $methodName, $this->doExport($id))); + if (!$definition->isShared()) { + $factory = sprintf('$this->factories%s[%s]', $definition->isPublic() ? '' : "['service_container']", $this->doExport($id)); + } + + if ($isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition)) { + if (!$definition->isShared()) { + $code .= sprintf(' %s = %1$s ?? ', $factory); + + if ($asFile) { + $code .= "function () {\n"; + $code .= " return self::do(\$container);\n"; + $code .= " };\n\n"; + } else { + $code .= sprintf("\\Closure::fromCallable([\$this, '%s']);\n\n", $methodName); + } + } + + $factoryCode = $asFile ? 'self::do($container, false)' : sprintf('$this->%s(false)', $methodName); + $factoryCode = $this->getProxyDumper()->getProxyFactoryCode($definition, $id, $factoryCode); $code .= $asFile ? preg_replace('/function \(([^)]*+)\) {/', 'function (\1) use ($container) {', $factoryCode) : $factoryCode; } - $code .= $this->addServiceInclude($id, $definition); + $c = $this->addServiceInclude($id, $definition); + + if ('' !== $c && $isProxyCandidate && !$definition->isShared()) { + $c = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $c))); + $code .= " static \$include = true;\n\n"; + $code .= " if (\$include) {\n"; + $code .= $c; + $code .= " \$include = false;\n"; + $code .= " }\n\n"; + } else { + $code .= $c; + } + $c = $this->addInlineService($id, $definition); - if (!$definition->isShared()) { + if (!$isProxyCandidate && !$definition->isShared()) { $c = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $c))); - $factory = sprintf('$this->factories%s[%s]', $definition->isPublic() ? '' : "['service_container']", $this->doExport($id)); $lazyloadInitialization = $definition->isLazy() ? '$lazyLoad = true' : ''; $c = sprintf(" %s = function (%s) {\n%s };\n\n return %1\$s();\n", $factory, $lazyloadInitialization, $c); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index f66959d0eb..1335d60e69 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -307,6 +307,7 @@ class PhpDumperTest extends TestCase ->setLazy(true); $container->compile(); $dumper = new PhpDumper($container); + $dumper->setProxyDumper(new \DummyProxyDumper()); $dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'inline_factories_parameter' => false, 'inline_class_loader_parameter' => false]), true); if ('\\' === \DIRECTORY_SEPARATOR) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy.php index 048e4fdf59..ab3e1bd6df 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy.php @@ -67,13 +67,11 @@ class ProjectServiceContainer extends Container */ protected function getFooService($lazyLoad = true) { + $this->factories['service_container']['foo'] = $this->factories['service_container']['foo'] ?? \Closure::fromCallable([$this, 'getFooService']); + // lazy factory for stdClass - $this->factories['service_container']['foo'] = function ($lazyLoad = true) { - return new \stdClass(); - }; - - return $this->factories['service_container']['foo'](); + return new \stdClass(); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy_as_files.txt b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy_as_files.txt index d2cfe6eede..0a5dd64122 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy_as_files.txt +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy_as_files.txt @@ -28,16 +28,34 @@ class getNonSharedFooService extends ProjectServiceContainer */ public static function do($container, $lazyLoad = true) { - include_once $container->targetDir.''.'/Fixtures/includes/foo_lazy.php'; - - $container->factories['non_shared_foo'] = function ($lazyLoad = true) use ($container) { - return new \Bar\FooLazyClass(); + $container->factories['non_shared_foo'] = $container->factories['non_shared_foo'] ?? function () use ($container) { + return self::do($container); }; - return $container->factories['non_shared_foo'](); + // lazy factory for Bar\FooLazyClass + + static $include = true; + + if ($include) { + include_once $container->targetDir.''.'/Fixtures/includes/foo_lazy.php'; + + $include = false; + } + + return new \Bar\FooLazyClass(); } } + [Container%s/proxy.php] =>