From 206b49a22f1e9c0564bdc2dd74de81d563eac1b8 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 24 Jan 2011 11:27:07 +0100 Subject: [PATCH] [FrameworkBundle] added a cache warmer to pre-compute template paths To enable this cache warmer, you must add a "cache-warner" option to app:templating: --- .../FrameworkExtension.php | 12 ++- .../Resources/config/schema/symfony-1.0.xsd | 1 + .../Resources/config/templating.xml | 11 +++ .../CacheWarmer/TemplatePathsCacheWarmer.php | 94 +++++++++++++++++++ .../Loader/CachedTemplateLocator.php | 42 +++++++++ 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Templating/CacheWarmer/TemplatePathsCacheWarmer.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Templating/Loader/CachedTemplateLocator.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 5c909ddc7ead..112c16f02e9f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -263,6 +263,15 @@ protected function registerTemplatingConfiguration(array $config, ContainerBuild $container->setParameter('templating.loader.cache.path', $config['cache']); } + if (isset($config['cache-warmer'])) { + $config['cache_warmer'] = $config['cache-warmer']; + } + + if (isset($config['cache_warmer']) && $config['cache_warmer']) { + $container->getDefinition('templating.cache_warmer.template_paths')->addTag('kernel.cache_warmer'); + $container->setAlias('templating.locator', 'templating.locator.cached'); + } + // engines if (!$engines = $this->normalizeConfig($config, 'engine')) { throw new \LogicException('You must register at least one templating engine.'); @@ -281,10 +290,11 @@ protected function registerTemplatingConfiguration(array $config, ContainerBuild $container->setAlias('templating', 'templating.engine.delegating'); } - // compilation $this->addClassesToCompile(array( 'Symfony\\Bundle\\FrameworkBundle\\Templating\\EngineInterface', 'Symfony\\Component\\Templating\\EngineInterface', + 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Loader\\TemplateLocatorInterface', + $container->findDefinition('templating.locator')->getClass(), )); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 109a4a16f819..d4c168cfd87c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -80,6 +80,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml index 278258214e17..ba3161b85cfd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml @@ -7,7 +7,9 @@ Symfony\Bundle\FrameworkBundle\Templating\DelegatingEngine Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateNameParser + Symfony\Bundle\FrameworkBundle\Templating\CacheWarmer\TemplatePathsCacheWarmer Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateLocator + Symfony\Bundle\FrameworkBundle\Templating\Loader\CachedTemplateLocator Symfony\Bundle\FrameworkBundle\Templating\Loader\FilesystemLoader Symfony\Component\Templating\Loader\CacheLoader Symfony\Component\Templating\Loader\ChainLoader @@ -32,6 +34,15 @@ %kernel.root_dir% + + %kernel.cache_dir% + + + + + %kernel.root_dir%/views + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/CacheWarmer/TemplatePathsCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/Templating/CacheWarmer/TemplatePathsCacheWarmer.php new file mode 100644 index 000000000000..296b04187944 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/CacheWarmer/TemplatePathsCacheWarmer.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Templating\CacheWarmer; + +use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmer; +use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\Finder\Finder; + +/** + * Computes the association between template names and their paths on the disk. + * + * @author Fabien Potencier + */ +class TemplatePathsCacheWarmer extends CacheWarmer +{ + protected $kernel; + protected $rootDir; + + /** + * Constructor. + * + * @param Kernel $kernel A Kernel instance + * @param string $rootDir The directory where global templates can be stored + */ + public function __construct(Kernel $kernel, $rootDir) + { + $this->kernel = $kernel; + $this->rootDir = $rootDir; + } + + /** + * Warms up the cache. + * + * @param string $cacheDir The cache directory + */ + public function warmUp($cacheDir) + { + $templates = $this->computeTemplatePaths(); + + $this->writeCacheFile($cacheDir.'/templates.php', sprintf('kernel->getBundles() as $name => $bundle) { + if (!is_dir($dir = $bundle->getPath().$prefix)) { + continue; + } + + $finder = new Finder(); + foreach ($finder->files()->followLinks()->name('*.twig')->in($dir) as $file) { + list($category, $template) = $this->parseTemplateName($file, $prefix.'/'); + $name = sprintf('%s:%s:%s', $bundle->getName(), $category, $template); + $resource = '@'.$bundle->getName().$prefix.'/'.$category.'/'.$template; + + $templates[$name] = $this->kernel->locateResource($resource, $this->rootDir); + } + } + + return $templates; + } + + protected function parseTemplateName($file, $prefix) + { + $path = $file->getPathname(); + + list(, $tmp) = explode($prefix, $path, 2); + $parts = explode('/', strtr($tmp, '\\', '/')); + $template = array_pop($parts); + + return array(implode('/', $parts), $template); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Loader/CachedTemplateLocator.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Loader/CachedTemplateLocator.php new file mode 100644 index 000000000000..e21413cbc103 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Loader/CachedTemplateLocator.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\FrameworkBundle\Templating\Loader; + +/** + * + * @author Fabien Potencier + */ +class CachedTemplateLocator implements TemplateLocatorInterface +{ + protected $templates; + + /** + * Constructor. + */ + public function __construct($cacheDir) + { + if (!file_exists($cache = $cacheDir.'/templates.php')) { + throw new \RuntimeException(sprintf('The template locator cache is not warmed up (%s).', $cache)); + } + + $this->templates = require $cache; + } + + public function locate($name) + { + if (!isset($this->templates[$name])) { + throw new \InvalidArgumentException(sprintf('Unable to find template "%s".', $name)); + } + + return $this->templates[$name]; + } +}