diff --git a/src/Symfony/Bundle/TwigBundle/CHANGELOG.md b/src/Symfony/Bundle/TwigBundle/CHANGELOG.md index 3ddc5d809a80..01834ca16c5f 100644 --- a/src/Symfony/Bundle/TwigBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/TwigBundle/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 2.2.0 ----- + * added support for multiple loaders via the "twig.loader" tag. * added automatic registration of namespaced paths for registered bundles * added support for namespaced paths diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/TwigLoaderPass.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/TwigLoaderPass.php new file mode 100644 index 000000000000..3d0775990f52 --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/TwigLoaderPass.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\TwigBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\Exception\LogicException; + +/** + * If there are any tagged loaders replace + * default filesystem loader with chain loader + * + * Add tagged loaders to chain loader + * + * @author Daniel Leech + */ +class TwigLoaderPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container) + { + if (false === $container->hasDefinition('twig')) { + return; + } + + // register additional template loaders + $loaderIds = $container->findTaggedServiceIds('twig.loader'); + + if (count($loaderIds) === 0) { + throw new LogicException('No twig loaders found. You need to tag at least one loader with "twig.loader"'); + } + + if (count($loaderIds) === 1) { + $container->setAlias('twig.loader', key($loaderIds)); + } else { + $chainLoader = $container->getDefinition('twig.loader.chain'); + foreach (array_keys($loaderIds) as $id) { + $chainLoader->addMethodCall('addLoader', array(new Reference($id))); + }; + $container->setAlias('twig.loader', 'twig.loader.chain'); + } + } +} + diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index 35016810ff6f..1f310af1346e 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -7,6 +7,7 @@ Twig_Environment Symfony\Bundle\TwigBundle\Loader\FilesystemLoader + Twig_Loader_Chain Symfony\Bundle\TwigBundle\TwigEngine Symfony\Bundle\TwigBundle\CacheWarmer\TemplateCacheCacheWarmer Symfony\Bridge\Twig\Extension\TranslationExtension @@ -41,8 +42,11 @@ + + + diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Compiler/TwigLoaderPassTest.php b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Compiler/TwigLoaderPassTest.php new file mode 100644 index 000000000000..1f7d90e98159 --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Compiler/TwigLoaderPassTest.php @@ -0,0 +1,87 @@ +builder = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); + $this->chainLoader = new Definition('loader'); + $this->pass = new TwigLoaderPass(); + } + + public function testMapperPassWithOneTaggedLoaders() + { + $serviceIds = array( + 'test_loader_1' => array( + ), + ); + + $this->builder->expects($this->once()) + ->method('hasDefinition') + ->with('twig') + ->will($this->returnValue(true)); + $this->builder->expects($this->once()) + ->method('findTaggedServiceIds') + ->with('twig.loader') + ->will($this->returnValue($serviceIds)); + $this->builder->expects($this->once()) + ->method('setAlias') + ->with('twig.loader', 'test_loader_1'); + + $this->pass->process($this->builder); + } + + public function testMapperPassWithTwoTaggedLoaders() + { + $serviceIds = array( + 'test_loader_1' => array( + ), + 'test_loader_2' => array( + ), + ); + + $this->builder->expects($this->once()) + ->method('hasDefinition') + ->with('twig') + ->will($this->returnValue(true)); + $this->builder->expects($this->once()) + ->method('findTaggedServiceIds') + ->with('twig.loader') + ->will($this->returnValue($serviceIds)); + $this->builder->expects($this->once()) + ->method('getDefinition') + ->with('twig.loader.chain') + ->will($this->returnValue($this->chainLoader)); + $this->builder->expects($this->once()) + ->method('setAlias') + ->with('twig.loader', 'twig.loader.chain'); + + $this->pass->process($this->builder); + $calls = $this->chainLoader->getMethodCalls(); + $this->assertEquals(2, count($calls)); + $this->assertEquals('addLoader', $calls[0][0]); + } + + /** + * @expectedException Symfony\Component\DependencyInjection\Exception\LogicException + */ + public function testMapperPassWithZeroTaggedLoaders() + { + $this->builder->expects($this->once()) + ->method('hasDefinition') + ->with('twig') + ->will($this->returnValue(true)); + $this->builder->expects($this->once()) + ->method('findTaggedServiceIds') + ->with('twig.loader') + ->will($this->returnValue(array())); + + $this->pass->process($this->builder); + } +} diff --git a/src/Symfony/Bundle/TwigBundle/TwigBundle.php b/src/Symfony/Bundle/TwigBundle/TwigBundle.php index a67756c0b133..88a172caab0b 100644 --- a/src/Symfony/Bundle/TwigBundle/TwigBundle.php +++ b/src/Symfony/Bundle/TwigBundle/TwigBundle.php @@ -14,6 +14,7 @@ use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\TwigEnvironmentPass; +use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\TwigLoaderPass; use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\ExceptionListenerPass; /** @@ -28,6 +29,7 @@ public function build(ContainerBuilder $container) parent::build($container); $container->addCompilerPass(new TwigEnvironmentPass()); + $container->addCompilerPass(new TwigLoaderPass()); $container->addCompilerPass(new ExceptionListenerPass()); } }