diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplateFinder.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplateFinder.php index 2b756a2997abc..1e229849824ac 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplateFinder.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplateFinder.php @@ -45,7 +45,7 @@ public function __construct(KernelInterface $kernel, TemplateNameParserInterface /** * Find all the templates in the bundle and in the kernel Resources folder. * - * @return array An array of templates of type TemplateReferenceInterface + * @return TemplateReferenceInterface[] */ public function findAllTemplates() { @@ -69,7 +69,7 @@ public function findAllTemplates() * * @param string $dir The folder where to look for templates * - * @return array An array of templates of type TemplateReferenceInterface + * @return TemplateReferenceInterface[] */ private function findTemplatesInFolder($dir) { @@ -93,7 +93,7 @@ private function findTemplatesInFolder($dir) * * @param BundleInterface $bundle The bundle where to look for templates * - * @return array An array of templates of type TemplateReferenceInterface + * @return TemplateReferenceInterface[] */ private function findTemplatesInBundle(BundleInterface $bundle) { diff --git a/src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php b/src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php new file mode 100644 index 0000000000000..aefb5c7296b97 --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\TwigBundle\CacheWarmer; + +use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; + +/** + * Generates the Twig cache for all templates. + * + * @author Fabien Potencier + */ +class TemplateCacheWarmer implements CacheWarmerInterface +{ + private $twig; + private $iterator; + + public function __construct(\Twig_Environment $twig, \Traversable $iterator) + { + $this->twig = $twig; + $this->iterator = $iterator; + } + + /** + * {@inheritdoc} + */ + public function warmUp($cacheDir) + { + foreach ($this->iterator as $template) { + try { + $this->twig->loadTemplate($template); + } catch (\Twig_Error $e) { + // problem during compilation, give up + // might be a syntax error or a non-Twig template + } + } + } + + /** + * {@inheritdoc} + */ + public function isOptional() + { + return true; + } +} diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php index c0171219d0487..5296ac542ca87 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php @@ -78,6 +78,7 @@ public function load(array $configs, ContainerBuilder $container) } $container->getDefinition('twig.cache_warmer')->replaceArgument(2, $config['paths']); + $container->getDefinition('twig.template_iterator')->replaceArgument(2, $config['paths']); // register bundles as Twig namespaces foreach ($container->getParameter('kernel.bundles') as $bundle => $class) { diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index 183db3f23676e..d98f2b3611c59 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -52,6 +52,18 @@ + + + %kernel.root_dir% + + + + + + + + + diff --git a/src/Symfony/Bundle/TwigBundle/TemplateIterator.php b/src/Symfony/Bundle/TwigBundle/TemplateIterator.php new file mode 100644 index 0000000000000..63f8da549fdd4 --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/TemplateIterator.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\TwigBundle; + +use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\Finder\Finder; + +/** + * Iterator for all templates in bundles and in the application Resources directory. + * + * @author Fabien Potencier + */ +class TemplateIterator implements \IteratorAggregate +{ + private $kernel; + private $rootDir; + private $templates; + private $paths; + + /** + * @param KernelInterface $kernel A KernelInterface instance + * @param string $rootDir The directory where global templates can be stored + * @param array $paths Additional Twig paths to warm + */ + public function __construct(KernelInterface $kernel, $rootDir, array $paths = array()) + { + $this->kernel = $kernel; + $this->rootDir = $rootDir; + $this->paths = $paths; + } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + if (null !== $this->templates) { + return $this->templates; + } + + $this->templates = $this->findTemplatesInDirectory($this->rootDir.'/Resources/views'); + foreach ($this->kernel->getBundles() as $bundle) { + $name = $bundle->getName(); + if ('Bundle' === substr($name, -6)) { + $name = substr($name, 0, -6); + } + + $this->templates = array_merge( + $this->templates, + $this->findTemplatesInDirectory($bundle->getPath().'/Resources/views', $name), + $this->findTemplatesInDirectory($this->rootDir.'/'.$bundle->getName().'/views', $name) + ); + } + + foreach ($this->paths as $dir => $namespace) { + $this->templates = array_merge($this->templates, $this->findTemplatesInDirectory($dir, $namespace)); + } + + return $this->templates = new \ArrayIterator(array_unique($this->templates)); + } + + /** + * Find templates in the given directory. + * + * @param string $dir The directory where to look for templates + * @param string|null $namespace The template namespace + * + * @return array + */ + private function findTemplatesInDirectory($dir, $namespace = null) + { + if (!is_dir($dir)) { + return array(); + } + + $templates = array(); + foreach (Finder::create()->files()->followLinks()->in($dir) as $file) { + $templates[] = (null !== $namespace ? '@'.$namespace.'/' : '').str_replace('\\', '/', $file->getRelativePathname()); + } + + return $templates; + } +} diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Fixtures/templates/BarBundle/Resources/views/index.html.twig b/src/Symfony/Bundle/TwigBundle/Tests/Fixtures/templates/BarBundle/Resources/views/index.html.twig new file mode 100644 index 0000000000000..1975b0e15986a --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/Tests/Fixtures/templates/BarBundle/Resources/views/index.html.twig @@ -0,0 +1 @@ +{# Twig template #} diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Fixtures/templates/Foo/index.html.twig b/src/Symfony/Bundle/TwigBundle/Tests/Fixtures/templates/Foo/index.html.twig new file mode 100644 index 0000000000000..1975b0e15986a --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/Tests/Fixtures/templates/Foo/index.html.twig @@ -0,0 +1 @@ +{# Twig template #} diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Fixtures/templates/Resources/views/layout.html.twig b/src/Symfony/Bundle/TwigBundle/Tests/Fixtures/templates/Resources/views/layout.html.twig new file mode 100644 index 0000000000000..1975b0e15986a --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/Tests/Fixtures/templates/Resources/views/layout.html.twig @@ -0,0 +1 @@ +{# Twig template #} diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Fixtures/templates/Resources/views/sub/sub.html.twig b/src/Symfony/Bundle/TwigBundle/Tests/Fixtures/templates/Resources/views/sub/sub.html.twig new file mode 100644 index 0000000000000..1975b0e15986a --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/Tests/Fixtures/templates/Resources/views/sub/sub.html.twig @@ -0,0 +1 @@ +{# Twig template #} diff --git a/src/Symfony/Bundle/TwigBundle/Tests/TemplateIteratorTest.php b/src/Symfony/Bundle/TwigBundle/Tests/TemplateIteratorTest.php new file mode 100644 index 0000000000000..13bb9ef909180 --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/Tests/TemplateIteratorTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\TwigBundle\Tests; + +use Symfony\Bundle\TwigBundle\TemplateIterator; + +class TemplateIteratorTest extends TestCase +{ + public function testGetIterator() + { + $bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface'); + $bundle->expects($this->any())->method('getName')->will($this->returnValue('BarBundle')); + $bundle->expects($this->any())->method('getPath')->will($this->returnValue(__DIR__.'/Fixtures/templates/BarBundle')); + + $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\Kernel')->disableOriginalConstructor()->getMock(); + $kernel->expects($this->any())->method('getBundles')->will($this->returnValue(array( + $bundle, + ))); + $iterator = new TemplateIterator($kernel, __DIR__.'/Fixtures/templates', array(__DIR__.'/Fixtures/templates/Foo' => 'Foo')); + + $sorted = iterator_to_array($iterator); + sort($sorted); + $this->assertEquals( + array( + '@Bar/index.html.twig', + '@Foo/index.html.twig', + 'layout.html.twig', + 'sub/sub.html.twig', + ), + $sorted + ); + } +}