Prechádzať zdrojové kódy

[Templating] refactored helpers, added helper slots, made some speed optimizations

Fabien Potencier 15 rokov pred
rodič
commit
da364173cb

+ 57 - 121
src/Symfony/Components/Templating/Engine.php

@@ -3,7 +3,6 @@
 namespace Symfony\Components\Templating;
 
 use Symfony\Components\Templating\Loader\LoaderInterface;
-use Symfony\Components\Templating\Helper\HelperSet;
 use Symfony\Components\Templating\Renderer\PhpRenderer;
 use Symfony\Components\Templating\Renderer\RendererInterface;
 
@@ -28,11 +27,9 @@ class Engine
   protected $loader;
   protected $renderers;
   protected $current;
-  protected $helperSet;
+  protected $helpers;
   protected $parents;
   protected $stack;
-  protected $slots;
-  protected $openSlots;
   protected $charset;
 
   /**
@@ -40,19 +37,19 @@ class Engine
    *
    * @param LoaderInterface $loader    A loader instance
    * @param array           $renderers An array of renderer instances
-   * @param HelperSet       $helperSet A helper set instance
+   * @param array           $helpers   A array of helper instances
    */
-  public function __construct(LoaderInterface $loader, array $renderers = array(), HelperSet $helperSet = null)
+  public function __construct(LoaderInterface $loader, array $renderers = array(), array $helpers = array())
   {
     $this->loader    = $loader;
     $this->renderers = $renderers;
+    $this->helpers   = array();
     $this->parents   = array();
     $this->stack     = array();
-    $this->slots     = array();
-    $this->openSlots = array();
     $this->charset   = 'UTF-8';
+    $this->cache     = array();
 
-    $this->setHelperSet(null === $helperSet ? new HelperSet() : $helperSet);
+    $this->addHelpers($helpers);
 
     if (!isset($this->renderers['php']))
     {
@@ -84,14 +81,23 @@ class Engine
    */
   public function render($name, array $parameters = array())
   {
-    list($name, $options) = $this->splitTemplateName($name);
+    if (isset($this->cache[$name]))
+    {
+      list($name, $options, $template) = $this->cache[$name];
+    }
+    else
+    {
+      list($name, $options) = $this->splitTemplateName($old = $name);
 
-    // load
-    $template = $this->loader->load($name, $options);
+      // load
+      $template = $this->loader->load($name, $options);
 
-    if (false === $template)
-    {
-      throw new \InvalidArgumentException(sprintf('The template "%s" does not exist (renderer: %s).', $name, $options['renderer']));
+      if (false === $template)
+      {
+        throw new \InvalidArgumentException(sprintf('The template "%s" does not exist (renderer: %s).', $name, $options['renderer']));
+      }
+
+      $this->cache[$old] = array($name, $options, $template);
     }
 
     $this->current = $name;
@@ -114,40 +120,18 @@ class Engine
     // decorator
     if ($this->parents[$name])
     {
-      $this->stack[] = $this->get('content');
-      $this->set('content', $content);
+      $slots = $this->get('slots');
+      $this->stack[] = $slots->get('content');
+      $slots->set('content', $content);
 
       $content = $this->render($this->parents[$name], $parameters);
 
-      $this->set('content', array_pop($this->stack));
+      $slots->set('content', array_pop($this->stack));
     }
 
     return $content;
   }
 
-  /**
-   * Sets a helper value.
-   *
-   * @param string          $name  The helper name
-   * @param HelperInterface $value The helper value
-   */
-  public function setHelperSet(HelperSet $helperSet)
-  {
-    $this->helperSet = $helperSet;
-
-    $helperSet->setEngine($this);
-  }
-
-  /**
-   * Gets all helper values.
-   *
-   * @return array An array of all helper values
-   */
-  public function getHelperSet()
-  {
-    return $this->helperSet;
-  }
-
   /**
    * Gets a helper value.
    *
@@ -159,121 +143,73 @@ class Engine
    */
   public function __get($name)
   {
-    return $this->$name = $this->helperSet->get($name);
+    return $this->$name = $this->get($name);
   }
 
-  /**
-   * Decorates the current template with another one.
-   *
-   * @param string $template  The decorator logical name
-   */
-  public function extend($template)
+  public function addHelpers(array $helpers = array())
   {
-    $this->parents[$this->current] = $template;
-  }
-
-  /**
-   * Starts a new slot.
-   *
-   * This method starts an output buffer that will be
-   * closed when the stop() method is called.
-   *
-   * @param string $name  The slot name
-   *
-   * @throws \InvalidArgumentException if a slot with the same name is already started
-   */
-  public function start($name)
-  {
-    if (in_array($name, $this->openSlots))
+    foreach ($helpers as $alias => $helper)
     {
-      throw new \InvalidArgumentException(sprintf('A slot named "%s" is already started.', $name));
+      $this->set($helper, is_int($alias) ? null : $alias);
     }
-
-    $this->openSlots[] = $name;
-    $this->slots[$name] = '';
-
-    ob_start();
-    ob_implicit_flush(0);
   }
 
   /**
-   * Stops a slot.
+   * Sets a helper.
    *
-   * @throws \LogicException if no slot has been started
+   * @param HelperInterface $value The helper instance
+   * @param string                    $alias An alias
    */
-  public function stop()
+  public function set(HelperInterface $helper, $alias = null)
   {
-    $content = ob_get_clean();
-
-    if (!$this->openSlots)
+    $this->helpers[$helper->getName()] = $helper;
+    if (null !== $alias)
     {
-      throw new \LogicException('No slot started.');
+      $this->helpers[$alias] = $helper;
     }
 
-    $name = array_pop($this->openSlots);
-
-    $this->slots[$name] = $content;
+    $helper->setEngine($this);
   }
 
   /**
-   * Returns true if the slot exists.
+   * Returns true if the helper if defined.
+   *
+   * @param string  $name The helper name
    *
-   * @param string $name The slot name
+   * @return Boolean true if the helper is defined, false otherwise
    */
   public function has($name)
   {
-    return isset($this->slots[$name]);
+    return isset($this->helpers[$name]);
   }
 
   /**
-   * Gets the slot value.
+   * Gets a helper value.
    *
-   * @param string $name    The slot name
-   * @param string $default The default slot content
+   * @param string $name The helper name
    *
-   * @return string The slot content
-   */
-  public function get($name, $default = false)
-  {
-    return isset($this->slots[$name]) ? $this->slots[$name] : $default;
-  }
-
-  /**
-   * Sets a slot value.
+   * @return HelperInterface The helper instance
    *
-   * @param string $name    The slot name
-   * @param string $content The slot content
+   * @throws \InvalidArgumentException if the helper is not defined
    */
-  public function set($name, $content)
+  public function get($name)
   {
-    $this->slots[$name] = $content;
+    if (!isset($this->helpers[$name]))
+    {
+      throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
+    }
+
+    return $this->helpers[$name];
   }
 
   /**
-   * Outputs a slot.
-   *
-   * @param string $name    The slot name
-   * @param string $default The default slot content
+   * Decorates the current template with another one.
    *
-   * @return Boolean true if the slot is defined or if a default content has been provided, false otherwise
+   * @param string $template  The decorator logical name
    */
-  public function output($name, $default = false)
+  public function extend($template)
   {
-    if (!isset($this->slots[$name]))
-    {
-      if (false !== $default)
-      {
-        echo $default;
-
-        return true;
-      }
-
-      return false;
-    }
-
-    echo $this->slots[$name];
-
-    return true;
+    $this->parents[$this->current] = $template;
   }
 
   /**

+ 11 - 9
src/Symfony/Components/Templating/Helper/Helper.php

@@ -2,6 +2,8 @@
 
 namespace Symfony\Components\Templating\Helper;
 
+use Symfony\Components\Templating\Engine;
+
 /*
  * This file is part of the symfony package.
  *
@@ -20,25 +22,25 @@ namespace Symfony\Components\Templating\Helper;
  */
 abstract class Helper implements HelperInterface
 {
-  protected $helperSet;
+  protected $engine;
 
   /**
-   * Sets the helper set associated with this helper.
+   * Sets the engine associated with this helper.
    *
-   * @param HelperSet $helperSet A HelperSet instance
+   * @param Engine $engine A Engine instance
    */
-  public function setHelperSet(HelperSet $helperSet = null)
+  public function setEngine(Engine $engine = null)
   {
-    $this->helperSet = $helperSet;
+    $this->engine = $engine;
   }
 
   /**
-   * Gets the helper set associated with this helper.
+   * Gets the engine associated with this helper.
    *
-   * @return HelperSet A HelperSet instance
+   * @return Engine A Engine instance
    */
-  public function getHelperSet()
+  public function getEngine()
   {
-    return $this->helperSet;
+    return $this->engine;
   }
 }

+ 8 - 6
src/Symfony/Components/Templating/Helper/HelperInterface.php

@@ -2,6 +2,8 @@
 
 namespace Symfony\Components\Templating\Helper;
 
+use Symfony\Components\Templating\Engine;
+
 /*
  * This file is part of the symfony package.
  *
@@ -28,16 +30,16 @@ interface HelperInterface
   function getName();
 
   /**
-   * Sets the helper set associated with this helper.
+   * Sets the engine associated with this helper.
    *
-   * @param HelperSet $helperSet A HelperSet instance
+   * @param Engine $engine A Engine instance
    */
-  function setHelperSet(HelperSet $helperSet = null);
+  function setEngine(Engine $engine = null);
 
   /**
-   * Gets the helper set associated with this helper.
+   * Gets the engine associated with this helper.
    *
-   * @return HelperSet A HelperSet instance
+   * @return Engine A Engine instance
    */
-  function getHelperSet();
+  function getEngine();
 }

+ 0 - 104
src/Symfony/Components/Templating/Helper/HelperSet.php

@@ -1,104 +0,0 @@
-<?php
-
-namespace Symfony\Components\Templating\Helper;
-
-use Symfony\Components\Templating\Engine;
-
-/*
- * 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.
- */
-
-/**
- * HelperSet represents a set of helpers to be used with a templating engine.
- *
- * @package    symfony
- * @subpackage templating
- * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
- */
-class HelperSet
-{
-  protected $helpers;
-  protected $engine;
-
-  public function __construct(array $helpers = array())
-  {
-    $this->helpers = array();
-    foreach ($helpers as $alias => $helper)
-    {
-      $this->set($helper, is_int($alias) ? null : $alias);
-    }
-  }
-
-  /**
-   * Sets a helper.
-   *
-   * @param HelperInterface $value The helper instance
-   * @param string                    $alias An alias
-   */
-  public function set(HelperInterface $helper, $alias = null)
-  {
-    $this->helpers[$helper->getName()] = $helper;
-    if (null !== $alias)
-    {
-      $this->helpers[$alias] = $helper;
-    }
-
-    $helper->setHelperSet($this);
-  }
-
-  /**
-   * Returns true if the helper if defined.
-   *
-   * @param string  $name The helper name
-   *
-   * @return Boolean true if the helper is defined, false otherwise
-   */
-  public function has($name)
-  {
-    return isset($this->helpers[$name]);
-  }
-
-  /**
-   * Gets a helper value.
-   *
-   * @param string $name The helper name
-   *
-   * @return HelperInterface The helper instance
-   *
-   * @throws \InvalidArgumentException if the helper is not defined
-   */
-  public function get($name)
-  {
-    if (!$this->has($name))
-    {
-      throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
-    }
-
-    return $this->helpers[$name];
-  }
-
-  /**
-   * Sets the template engine associated with this helper set.
-   *
-   * @param Engine $engine A Engine instance
-   */
-  public function setEngine(Engine $engine = null)
-  {
-    $this->engine = $engine;
-  }
-
-  /**
-   * Gets the template engine associated with this helper set.
-   *
-   * @return Engine A Engine instance
-   */
-  public function getEngine()
-  {
-    return $this->engine;
-  }
-}

+ 2 - 2
src/Symfony/Components/Templating/Helper/JavascriptsHelper.php

@@ -37,7 +37,7 @@ class JavascriptsHelper extends Helper
    */
   public function add($javascript, $attributes = array())
   {
-    $this->javascripts[$this->helperSet->get('assets')->getUrl($javascript)] = $attributes;
+    $this->javascripts[$this->engine->get('assets')->getUrl($javascript)] = $attributes;
   }
 
   /**
@@ -63,7 +63,7 @@ class JavascriptsHelper extends Helper
       $atts = array();
       foreach ($attributes as $key => $value)
       {
-        $atts[] = sprintf('%s="%s"', $key, $this->helperSet->getEngine()->escape($value));
+        $atts[] = sprintf('%s="%s"', $key, $this->engine->escape($value));
       }
 
       $html[] = sprintf('<script type="text/javascript" src="%s" %s></script>', $path, implode(' ', $atts));

+ 139 - 0
src/Symfony/Components/Templating/Helper/SlotsHelper.php

@@ -0,0 +1,139 @@
+<?php
+
+namespace Symfony\Components\Templating\Helper;
+
+/*
+ * 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.
+ */
+
+/**
+ * SlotsHelper manages template slots.
+ *
+ * @package    symfony
+ * @subpackage templating
+ * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class SlotsHelper extends Helper
+{
+  protected $slots = array();
+  protected $openSlots = array();
+
+  /**
+   * Starts a new slot.
+   *
+   * This method starts an output buffer that will be
+   * closed when the stop() method is called.
+   *
+   * @param string $name  The slot name
+   *
+   * @throws \InvalidArgumentException if a slot with the same name is already started
+   */
+  public function start($name)
+  {
+    if (in_array($name, $this->openSlots))
+    {
+      throw new \InvalidArgumentException(sprintf('A slot named "%s" is already started.', $name));
+    }
+
+    $this->openSlots[] = $name;
+    $this->slots[$name] = '';
+
+    ob_start();
+    ob_implicit_flush(0);
+  }
+
+  /**
+   * Stops a slot.
+   *
+   * @throws \LogicException if no slot has been started
+   */
+  public function stop()
+  {
+    $content = ob_get_clean();
+
+    if (!$this->openSlots)
+    {
+      throw new \LogicException('No slot started.');
+    }
+
+    $name = array_pop($this->openSlots);
+
+    $this->slots[$name] = $content;
+  }
+
+  /**
+   * Returns true if the slot exists.
+   *
+   * @param string $name The slot name
+   */
+  public function has($name)
+  {
+    return isset($this->slots[$name]);
+  }
+
+  /**
+   * Gets the slot value.
+   *
+   * @param string $name    The slot name
+   * @param string $default The default slot content
+   *
+   * @return string The slot content
+   */
+  public function get($name, $default = false)
+  {
+    return isset($this->slots[$name]) ? $this->slots[$name] : $default;
+  }
+
+  /**
+   * Sets a slot value.
+   *
+   * @param string $name    The slot name
+   * @param string $content The slot content
+   */
+  public function set($name, $content)
+  {
+    $this->slots[$name] = $content;
+  }
+
+  /**
+   * Outputs a slot.
+   *
+   * @param string $name    The slot name
+   * @param string $default The default slot content
+   *
+   * @return Boolean true if the slot is defined or if a default content has been provided, false otherwise
+   */
+  public function output($name, $default = false)
+  {
+    if (!isset($this->slots[$name]))
+    {
+      if (false !== $default)
+      {
+        echo $default;
+
+        return true;
+      }
+
+      return false;
+    }
+
+    echo $this->slots[$name];
+
+    return true;
+  }
+
+  /**
+   * Returns the canonical name of this helper.
+   *
+   * @return string The canonical name
+   */
+  public function getName()
+  {
+    return 'slots';
+  }
+}

+ 2 - 2
src/Symfony/Components/Templating/Helper/StylesheetsHelper.php

@@ -37,7 +37,7 @@ class StylesheetsHelper extends Helper
    */
   public function add($stylesheet, $attributes = array())
   {
-    $this->stylesheets[$this->helperSet->get('assets')->getUrl($stylesheet)] = $attributes;
+    $this->stylesheets[$this->engine->get('assets')->getUrl($stylesheet)] = $attributes;
   }
 
   /**
@@ -63,7 +63,7 @@ class StylesheetsHelper extends Helper
       $atts = array();
       foreach ($attributes as $key => $value)
       {
-        $atts[] = sprintf('%s="%s"', $key, $this->helperSet->getEngine()->escape($value));
+        $atts[] = sprintf('%s="%s"', $key, $this->engine->escape($value));
       }
 
       $html[] = sprintf('<link href="%s" rel="stylesheet" type="text/css" %s />', $path, implode(' ', $atts));

+ 1 - 1
src/Symfony/Components/Templating/Renderer/PhpRenderer.php

@@ -28,7 +28,7 @@ class PhpRenderer extends Renderer
    * Evaluates a template.
    *
    * @param Storage $template   The template to render
-   * @param array             $parameters An array of parameters to pass to the template
+   * @param array   $parameters An array of parameters to pass to the template
    *
    * @return string|false The evaluated template, or false if the renderer is unable to render the template
    */