Skip to content

Commit

Permalink
[FrameworkBundle] added a cache warmer to pre-compute template paths
Browse files Browse the repository at this point in the history
To enable this cache warmer, you must add a "cache-warner" option
to app:templating:

        <app:templating cache-warmer="true">
  • Loading branch information
fabpot committed Jan 24, 2011
1 parent d0b4bfc commit 206b49a
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 1 deletion.
Expand Up @@ -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.');
Expand All @@ -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(),
));
}

Expand Down
Expand Up @@ -80,6 +80,7 @@
<xsd:attribute name="assets-version" type="xsd:string" />
<xsd:attribute name="assets-base-urls" type="xsd:string" />
<xsd:attribute name="cache" type="xsd:string" />
<xsd:attribute name="cache-warmer" type="cache_warmer" />
</xsd:complexType>

<xsd:complexType name="translator">
Expand Down
11 changes: 11 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml
Expand Up @@ -7,7 +7,9 @@
<parameters>
<parameter key="templating.engine.delegating.class">Symfony\Bundle\FrameworkBundle\Templating\DelegatingEngine</parameter>
<parameter key="templating.name_parser.class">Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateNameParser</parameter>
<parameter key="templating.cache_warmer.template_paths.class">Symfony\Bundle\FrameworkBundle\Templating\CacheWarmer\TemplatePathsCacheWarmer</parameter>
<parameter key="templating.locator.class">Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateLocator</parameter>
<parameter key="templating.locator.cached.class">Symfony\Bundle\FrameworkBundle\Templating\Loader\CachedTemplateLocator</parameter>
<parameter key="templating.loader.filesystem.class">Symfony\Bundle\FrameworkBundle\Templating\Loader\FilesystemLoader</parameter>
<parameter key="templating.loader.cache.class">Symfony\Component\Templating\Loader\CacheLoader</parameter>
<parameter key="templating.loader.chain.class">Symfony\Component\Templating\Loader\ChainLoader</parameter>
Expand All @@ -32,6 +34,15 @@
<argument>%kernel.root_dir%</argument>
</service>

<service id="templating.locator.cached" class="%templating.locator.cached.class%" public="false">
<argument>%kernel.cache_dir%</argument>
</service>

<service id="templating.cache_warmer.template_paths" class="%templating.cache_warmer.template_paths.class%" public="false">
<argument type="service" id="kernel" />
<argument>%kernel.root_dir%/views</argument>
</service>

<service id="templating.loader.filesystem" class="%templating.loader.filesystem.class%" public="false">
<argument type="service" id="templating.locator" />
</service>
Expand Down
@@ -0,0 +1,94 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* 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 <fabien.potencier@symfony-project.com>
*/
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('<?php return %s;', var_export($templates, true)));
}

/**
* Checks whether this warmer is optional or not.
*
* @return Boolean always false
*/
public function isOptional()
{
return false;
}

protected function computeTemplatePaths()
{
$prefix = '/Resources/views';
$templates = array();
foreach ($this->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);
}
}
@@ -0,0 +1,42 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* 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 <fabien.potencier@symfony-project.com>
*/
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];
}
}

0 comments on commit 206b49a

Please sign in to comment.