From a60dfcf07685c0efea159043e71b0da23fc57e33 Mon Sep 17 00:00:00 2001 From: Marcin Sikon Date: Sun, 7 May 2023 23:00:30 +0200 Subject: [PATCH] [DependencyInjection] Fix dumping non-shared factories with TaggedIteratorArgument --- .../DependencyInjection/Dumper/PhpDumper.php | 3 +- .../Tests/Dumper/PhpDumperTest.php | 30 ++++ .../Tests/Fixtures/includes/foo.php | 6 + ...nlined_factories_with_tagged_iterrator.txt | 130 ++++++++++++++++++ 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_inlined_factories_with_tagged_iterrator.txt diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index c7b3e72bce7ae..a2964dd618d3f 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -945,8 +945,9 @@ protected static function {$methodName}(\$container$lazyInitialization) if (!$isProxyCandidate && !$definition->isShared()) { $c = implode("\n", array_map(fn ($line) => $line ? ' '.$line : $line, explode("\n", $c))); $lazyloadInitialization = $definition->isLazy() ? ', $lazyLoad = true' : ''; + $useContainerRef = $this->addContainerRef ? ' use ($containerRef)' : ''; - $c = sprintf(" %s = function (\$container%s) {\n%s };\n\n return %1\$s(\$container);\n", $factory, $lazyloadInitialization, $c); + $c = sprintf(" %s = function (\$container%s)%s {\n%s };\n\n return %1\$s(\$container);\n", $factory, $lazyloadInitialization, $useContainerRef, $c); } $code .= $c; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index c16c902b2016f..6d4ad0884441c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -21,6 +21,7 @@ use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Argument\ServiceLocator as ArgumentServiceLocator; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; +use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\DependencyInjection\Attribute\AutowireCallable; use Symfony\Component\DependencyInjection\Attribute\AutowireServiceClosure; @@ -285,6 +286,35 @@ public function testDumpAsFilesWithFactoriesInlined() $this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services9_inlined_factories.txt', $dump); } + public function testDumpAsFilesWithFactoriesInlinedWithTaggedIterator() + { + $container = new ContainerBuilder(); + $container + ->register('foo', FooClass::class) + ->addMethodCall('setOtherInstances', [new TaggedIteratorArgument('foo')]) + ->setShared(false) + ->setPublic(true); + + $container + ->register('Bar', 'Bar') + ->addTag('foo'); + + $container + ->register('stdClass', '\stdClass') + ->addTag('foo'); + + $container->compile(); + + $dumper = new PhpDumper($container); + $dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'hot_path_tag' => 'hot', 'build_time' => 1563381341, 'inline_factories' => true, 'inline_class_loader' => true]), true); + + if ('\\' === \DIRECTORY_SEPARATOR) { + $dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump); + } + + $this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services9_inlined_factories_with_tagged_iterrator.txt', $dump); + } + public function testDumpAsFilesWithLazyFactoriesInlined() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/foo.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/foo.php index c8a6b347a0029..be59d01fcf787 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/foo.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/foo.php @@ -7,6 +7,7 @@ class FooClass public $qux; public $foo; public $moo; + public $otherInstances; public $bar = null; public $initialized = false; @@ -41,4 +42,9 @@ public function setBar($value = null) { $this->bar = $value; } + + public function setOtherInstances($otherInstances) + { + $this->otherInstances = $otherInstances; + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_inlined_factories_with_tagged_iterrator.txt b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_inlined_factories_with_tagged_iterrator.txt new file mode 100644 index 0000000000000..cd0358301c712 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_inlined_factories_with_tagged_iterrator.txt @@ -0,0 +1,130 @@ +Array +( + [Container%s/removed-ids.php] => true, + 'stdClass' => true, +]; + + [Container%s/ProjectServiceContainer.php] => ref = \WeakReference::create($this); + $this->targetDir = \dirname($containerDir); + $this->services = $this->privates = []; + $this->methodMap = [ + 'foo' => 'getFooService', + ]; + + $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'; + } + + /** + * Gets the public 'foo' service. + * + * @return \Symfony\Component\DependencyInjection\Tests\Dumper\FooClass + */ + protected static function getFooService($container) + { + $containerRef = $container->ref; + + $container->factories['foo'] = function ($container) use ($containerRef) { + $instance = new \Symfony\Component\DependencyInjection\Tests\Dumper\FooClass(); + + $instance->setOtherInstances(new RewindableGenerator(function () use ($containerRef) { + $container = $containerRef->get(); + + yield 0 => ($container->privates['Bar'] ??= new \Bar()); + yield 1 => ($container->privates['stdClass'] ??= new \stdClass()); + }, 2)); + + return $instance; + }; + + return $container->factories['foo']($container); + } +} + + [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).'/vendor/autoload.php'; +(require __DIR__.'/ProjectServiceContainer.php')->set(\Container%s\ProjectServiceContainer::class, null); + +$classes = []; +$classes[] = 'Bar'; +$classes[] = 'Symfony\Component\DependencyInjection\Tests\Dumper\FooClass'; +$classes[] = 'Symfony\Component\DependencyInjection\ContainerInterface'; + +$preloaded = Preloader::preload($classes); + + [ProjectServiceContainer.php] => '%s', + 'container.build_id' => '3f6e2bc2', + 'container.build_time' => 1563381341, +], __DIR__.\DIRECTORY_SEPARATOR.'Container%s'); + +)