diff --git a/src/Loader/ChainLoader.php b/src/Loader/ChainLoader.php index 163c029f8..8393711fc 100644 --- a/src/Loader/ChainLoader.php +++ b/src/Loader/ChainLoader.php @@ -21,22 +21,33 @@ use Twig\Source; */ final class ChainLoader implements LoaderInterface { - private $hasSourceCache = []; - private $loaders = []; + /** + * @var \Traversable|LoaderInterface[] + */ + private $loaders; /** - * @param LoaderInterface[] $loaders + * @var array */ - public function __construct(array $loaders = []) + private $hasSourceCache = []; + + /** + * @param iterable $loaders + */ + public function __construct(iterable $loaders = []) { - foreach ($loaders as $loader) { - $this->addLoader($loader); - } + $this->loaders = $loaders; } public function addLoader(LoaderInterface $loader): void { - $this->loaders[] = $loader; + $current = $this->loaders; + + $this->loaders = (static function () use ($current, $loader): \Generator { + yield from $current; + yield $loader; + })(); + $this->hasSourceCache = []; } @@ -45,13 +56,18 @@ final class ChainLoader implements LoaderInterface */ public function getLoaders(): array { + if (!\is_array($this->loaders)) { + $this->loaders = \iterator_to_array($this->loaders, false); + } + return $this->loaders; } public function getSourceContext(string $name): Source { $exceptions = []; - foreach ($this->loaders as $loader) { + + foreach ($this->getLoaders() as $loader) { if (!$loader->exists($name)) { continue; } @@ -72,7 +88,7 @@ final class ChainLoader implements LoaderInterface return $this->hasSourceCache[$name]; } - foreach ($this->loaders as $loader) { + foreach ($this->getLoaders() as $loader) { if ($loader->exists($name)) { return $this->hasSourceCache[$name] = true; } @@ -84,7 +100,8 @@ final class ChainLoader implements LoaderInterface public function getCacheKey(string $name): string { $exceptions = []; - foreach ($this->loaders as $loader) { + + foreach ($this->getLoaders() as $loader) { if (!$loader->exists($name)) { continue; } @@ -102,7 +119,8 @@ final class ChainLoader implements LoaderInterface public function isFresh(string $name, int $time): bool { $exceptions = []; - foreach ($this->loaders as $loader) { + + foreach ($this->getLoaders() as $loader) { if (!$loader->exists($name)) { continue; } diff --git a/tests/Loader/ChainTest.php b/tests/Loader/ChainTest.php index faaaebe33..52d6d4c72 100644 --- a/tests/Loader/ChainTest.php +++ b/tests/Loader/ChainTest.php @@ -72,10 +72,30 @@ class ChainTest extends TestCase public function testAddLoader() { - $loader = new ChainLoader(); - $loader->addLoader(new ArrayLoader(['foo' => 'bar'])); + $fooLoader = new ArrayLoader(['foo' => 'foo:code']); + $barLoader = new ArrayLoader(['bar' => 'bar:code']); + $bazLoader = new ArrayLoader(['baz' => 'baz:code']); + $quxLoader = new ArrayLoader(['qux' => 'qux:code']); - $this->assertEquals('bar', $loader->getSourceContext('foo')->getCode()); + $loader = new ChainLoader((static function () use ($fooLoader, $barLoader): \Generator { + yield $fooLoader; + yield $barLoader; + })()); + + $loader->addLoader($bazLoader); + $loader->addLoader($quxLoader); + + $this->assertEquals('foo:code', $loader->getSourceContext('foo')->getCode()); + $this->assertEquals('bar:code', $loader->getSourceContext('bar')->getCode()); + $this->assertEquals('baz:code', $loader->getSourceContext('baz')->getCode()); + $this->assertEquals('qux:code', $loader->getSourceContext('qux')->getCode()); + + $this->assertEquals([ + $fooLoader, + $barLoader, + $bazLoader, + $quxLoader, + ], $loader->getLoaders()); } public function testExists()