From f8c14acd518ccf2adeb9a5f86f014134668258e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Mon, 18 Jan 2021 13:58:47 +0100 Subject: [PATCH] Fix container injection with TypedReference --- .../DependencyInjection/Dumper/PhpDumper.php | 5 +- .../Tests/Dumper/PhpDumperTest.php | 20 +++ .../Fixtures/php/services10_as_files.txt | 167 ++++++++++++++++++ 3 files changed, 189 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10_as_files.txt diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index f3091bd9ce0a6..ccdf3af67b536 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -904,7 +904,7 @@ protected function {$methodName}($lazyInitialization) $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 .= $asFile ? preg_replace('/function \(([^)]*+)\)( {|:)/', 'function (\1) use ($container)\2', $factoryCode) : $factoryCode; } $c = $this->addServiceInclude($id, $definition); @@ -934,8 +934,7 @@ protected function {$methodName}($lazyInitialization) if ($asFile) { $code = str_replace('$this', '$container', $code); - $code = str_replace('function () {', 'function () use ($container) {', $code); - $code = str_replace('function ($lazyLoad = true) {', 'function ($lazyLoad = true) use ($container) {', $code); + $code = preg_replace('/function \(([^)]*+)\)( {|:)/', 'function (\1) use ($container)\2', $code); } $code .= " }\n"; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index d81404f4c4905..c833794d7bf4d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -244,6 +244,26 @@ public function testDumpAsFiles() $this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services9_as_files.txt', $dump); } + public function testDumpAsFilesWithTypedReference() + { + $container = include self::$fixturesPath.'/containers/container10.php'; + $container->getDefinition('foo')->addTag('hot'); + $container->register('bar', 'stdClass'); + $container->register('closure', 'stdClass') + ->setProperty('closures', [ + new ServiceClosureArgument(new TypedReference('foo', \stdClass::class, $container::IGNORE_ON_UNINITIALIZED_REFERENCE)), + ]) + ->setPublic(true); + $container->compile(); + $dumper = new PhpDumper($container); + $dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'hot_path_tag' => 'hot', 'inline_factories_parameter' => false, 'inline_class_loader_parameter' => false]), true); + if ('\\' === \DIRECTORY_SEPARATOR) { + $dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump); + } + + $this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services10_as_files.txt', $dump); + } + public function testDumpAsFilesWithFactoriesInlined() { $container = include self::$fixturesPath.'/containers/container9.php'; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10_as_files.txt b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10_as_files.txt new file mode 100644 index 0000000000000..ee674249b6844 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10_as_files.txt @@ -0,0 +1,167 @@ +Array +( + [Container%s/removed-ids.php] => true, + 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, + 'bar' => true, +]; + + [Container%s/getClosureService.php] => services['closure'] = $instance = new \stdClass(); + + $instance->closures = [0 => function () use ($container): ?\stdClass { + return ($container->services['foo'] ?? null); + }]; + + return $instance; + } +} + + [Container%s/ProjectServiceContainer.php] => buildParameters = $buildParameters; + $this->containerDir = $containerDir; + $this->targetDir = \dirname($containerDir); + $this->services = $this->privates = []; + $this->methodMap = [ + 'foo' => 'getFooService', + ]; + $this->fileMap = [ + 'closure' => 'getClosureService', + ]; + + $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 require $this->containerDir.\DIRECTORY_SEPARATOR.'removed-ids.php'; + } + + protected function load($file, $lazyLoad = true) + { + if (class_exists($class = __NAMESPACE__.'\\'.$file, false)) { + return $class::do($this, $lazyLoad); + } + + if ('.' === $file[-4]) { + $class = substr($class, 0, -4); + } else { + $file .= '.php'; + } + + $service = require $this->containerDir.\DIRECTORY_SEPARATOR.$file; + + return class_exists($class, false) ? $class::do($this, $lazyLoad) : $service; + } + + /** + * Gets the public 'foo' shared service. + * + * @return \FooClass + */ + protected function getFooService() + { + return $this->services['foo'] = new \FooClass(new \stdClass()); + } +} + + [ProjectServiceContainer.preload.php] => = 7.4 when preloading is desired + +use Symfony\Component\DependencyInjection\Dumper\Preloader; + +if (in_array(PHP_SAPI, ['cli', 'phpdbg'], true)) { + return; +} + +require dirname(__DIR__, %d).'%svendor/autoload.php'; +require __DIR__.'/Container%s/ProjectServiceContainer.php'; +require __DIR__.'/Container%s/getClosureService.php'; + +$classes = []; +$classes[] = 'FooClass'; +$classes[] = 'Symfony\Component\DependencyInjection\ContainerInterface'; + +Preloader::preload($classes); + + [ProjectServiceContainer.php] => '%s', + 'container.build_id' => '%s', + 'container.build_time' => %d, +], __DIR__.\DIRECTORY_SEPARATOR.'Container%s'); + +)