diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php index 724187b1dbfe7..1b8b64cac357f 100644 --- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php +++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php @@ -30,8 +30,7 @@ class EnvVarProcessor implements EnvVarProcessorInterface public function __construct(ContainerInterface $container, \Traversable $loaders = null) { $this->container = $container; - $this->loaders = new \IteratorIterator($loaders ?? new \ArrayIterator()); - $this->loaders = $this->loaders->getInnerIterator(); + $this->loaders = $loaders ?? new \ArrayIterator(); } /** @@ -141,20 +140,32 @@ public function getEnv($prefix, $name, \Closure $getEnv) } } - $loaders = $this->loaders; - $this->loaders = new \ArrayIterator(); - - try { - while ((false === $env || null === $env) && $loaders->valid()) { - $loader = $loaders->current(); - $loaders->next(); - $this->loadedVars[] = $vars = $loader->loadEnvVars(); - $env = $vars[$name] ?? false; + if (false === $env || null === $env) { + $loaders = $this->loaders; + $this->loaders = new \ArrayIterator(); + + try { + $i = 0; + $ended = true; + $count = $loaders instanceof \Countable ? $loaders->count() : 0; + foreach ($loaders as $loader) { + if (\count($this->loadedVars) > $i++) { + continue; + } + $this->loadedVars[] = $vars = $loader->loadEnvVars(); + if (false !== $env = $vars[$name] ?? false) { + $ended = false; + break; + } + } + if ($ended || $count === $i) { + $loaders = $this->loaders; + } + } catch (ParameterCircularReferenceException $e) { + // skip loaders that need an env var that is not defined + } finally { + $this->loaders = $loaders; } - } catch (ParameterCircularReferenceException $e) { - // skip loaders that need an env var that is not defined - } finally { - $this->loaders = $loaders; } if (false === $env || null === $env) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php index 9970eb474f6be..df329b4f7e316 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php @@ -3,10 +3,12 @@ namespace Symfony\Component\DependencyInjection\Tests; use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\EnvVarLoaderInterface; use Symfony\Component\DependencyInjection\EnvVarProcessor; +use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException; class EnvVarProcessorTest extends TestCase { @@ -553,4 +555,44 @@ public function loadEnvVars(): array $result = $processor->getEnv('string', 'FOO_ENV_LOADER', function () {}); $this->assertSame('123', $result); // check twice } + + public function testCircularEnvLoader() + { + $container = new ContainerBuilder(); + $container->setParameter('env(FOO_CONTAINER)', 'foo'); + $container->compile(); + + $index = 0; + $loaders = function () use (&$index) { + if (0 === $index++) { + throw new ParameterCircularReferenceException(['FOO_CONTAINER']); + } + + yield new class() implements EnvVarLoaderInterface { + public function loadEnvVars(): array + { + return [ + 'FOO_ENV_LOADER' => '123', + ]; + } + }; + }; + + $processor = new EnvVarProcessor($container, new RewindableGenerator($loaders, 1)); + + $result = $processor->getEnv('string', 'FOO_CONTAINER', function () {}); + $this->assertSame('foo', $result); + + $result = $processor->getEnv('string', 'FOO_ENV_LOADER', function () {}); + $this->assertSame('123', $result); + + $result = $processor->getEnv('default', ':BAR_CONTAINER', function ($name) use ($processor) { + $this->assertSame('BAR_CONTAINER', $name); + + return $processor->getEnv('string', $name, function () {}); + }); + $this->assertNull($result); + + $this->assertSame(2, $index); + } }