Prechádzať zdrojové kódy

[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:

        <app:templating cache-warmer="true">
Fabien Potencier 14 rokov pred
rodič
commit
206b49a22f

+ 11 - 1
src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

@@ -263,6 +263,15 @@ class FrameworkExtension extends Extension
             $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 @@ class FrameworkExtension extends Extension
             $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(),
         ));
     }
 

+ 1 - 0
src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

@@ -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">

+ 11 - 0
src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml

@@ -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>
@@ -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>

+ 94 - 0
src/Symfony/Bundle/FrameworkBundle/Templating/CacheWarmer/TemplatePathsCacheWarmer.php

@@ -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);
+    }
+}

+ 42 - 0
src/Symfony/Bundle/FrameworkBundle/Templating/Loader/CachedTemplateLocator.php

@@ -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];
+    }
+}