Viewing file: TwigRendererEngine.php (7.13 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
/* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */
namespace Symfony\Bridge\Twig\Form;
use Symfony\Component\Form\AbstractRendererEngine; use Symfony\Component\Form\FormView;
/** * @author Bernhard Schussek <bschussek@gmail.com> */ class TwigRendererEngine extends AbstractRendererEngine implements TwigRendererEngineInterface { /** * @var \Twig_Environment */ private $environment;
/** * @var \Twig_Template */ private $template;
/** * {@inheritdoc} */ public function setEnvironment(\Twig_Environment $environment) { $this->environment = $environment; }
/** * {@inheritdoc} */ public function renderBlock(FormView $view, $resource, $blockName, array $variables = array()) { $cacheKey = $view->vars[self::CACHE_KEY_VAR];
$context = $this->environment->mergeGlobals($variables);
ob_start();
// By contract,This method can only be called after getting the resource // (which is passed to the method). Getting a resource for the first time // (with an empty cache) is guaranteed to invoke loadResourcesFromTheme(), // where the property $template is initialized.
// We do not call renderBlock here to avoid too many nested level calls // (XDebug limits the level to 100 by default) $this->template->displayBlock($blockName, $context, $this->resources[$cacheKey]);
return ob_get_clean(); }
/** * Loads the cache with the resource for a given block name. * * This implementation eagerly loads all blocks of the themes assigned to the given view * and all of its ancestors views. This is necessary, because Twig receives the * list of blocks later. At that point, all blocks must already be loaded, for the * case that the function "block()" is used in the Twig template. * * @see getResourceForBlock() * * @param string $cacheKey The cache key of the form view. * @param FormView $view The form view for finding the applying themes. * @param string $blockName The name of the block to load. * * @return Boolean True if the resource could be loaded, false otherwise. */ protected function loadResourceForBlockName($cacheKey, FormView $view, $blockName) { // The caller guarantees that $this->resources[$cacheKey][$block] is // not set, but it doesn't have to check whether $this->resources[$cacheKey] // is set. If $this->resources[$cacheKey] is set, all themes for this // $cacheKey are already loaded (due to the eager population, see doc comment). if (isset($this->resources[$cacheKey])) { // As said in the previous, the caller guarantees that // $this->resources[$cacheKey][$block] is not set. Since the themes are // already loaded, it can only be a non-existing block. $this->resources[$cacheKey][$blockName] = false;
return false; }
// Recursively try to find the block in the themes assigned to $view, // then of its parent view, then of the parent view of the parent and so on. // When the root view is reached in this recursion, also the default // themes are taken into account.
// Check each theme whether it contains the searched block if (isset($this->themes[$cacheKey])) { for ($i = count($this->themes[$cacheKey]) - 1; $i >= 0; --$i) { $this->loadResourcesFromTheme($cacheKey, $this->themes[$cacheKey][$i]); // CONTINUE LOADING (see doc comment) } }
// Check the default themes once we reach the root view without success if (!$view->parent) { for ($i = count($this->defaultThemes) - 1; $i >= 0; --$i) { $this->loadResourcesFromTheme($cacheKey, $this->defaultThemes[$i]); // CONTINUE LOADING (see doc comment) } }
// Proceed with the themes of the parent view if ($view->parent) { $parentCacheKey = $view->parent->vars[self::CACHE_KEY_VAR];
if (!isset($this->resources[$parentCacheKey])) { $this->loadResourceForBlockName($parentCacheKey, $view->parent, $blockName); }
// EAGER CACHE POPULATION (see doc comment) foreach ($this->resources[$parentCacheKey] as $nestedBlockName => $resource) { if (!isset($this->resources[$cacheKey][$nestedBlockName])) { $this->resources[$cacheKey][$nestedBlockName] = $resource; } } }
// Even though we loaded the themes, it can happen that none of them // contains the searched block if (!isset($this->resources[$cacheKey][$blockName])) { // Cache that we didn't find anything to speed up further accesses $this->resources[$cacheKey][$blockName] = false; }
return false !== $this->resources[$cacheKey][$blockName]; }
/** * Loads the resources for all blocks in a theme. * * @param string $cacheKey The cache key for storing the resource. * @param mixed $theme The theme to load the block from. This parameter * is passed by reference, because it might be necessary * to initialize the theme first. Any changes made to * this variable will be kept and be available upon * further calls to this method using the same theme. */ protected function loadResourcesFromTheme($cacheKey, &$theme) { if (!$theme instanceof \Twig_Template) { /* @var \Twig_Template $theme */ $theme = $this->environment->loadTemplate($theme); }
if (null === $this->template) { // Store the first \Twig_Template instance that we find so that // we can call displayBlock() later on. It doesn't matter *which* // template we use for that, since we pass the used blocks manually // anyway. $this->template = $theme; }
// Use a separate variable for the inheritance traversal, because // theme is a reference and we don't want to change it. $currentTheme = $theme;
$context = $this->environment->mergeGlobals(array());
// The do loop takes care of template inheritance. // Add blocks from all templates in the inheritance tree, but avoid // overriding blocks already set. do { foreach ($currentTheme->getBlocks() as $block => $blockData) { if (!isset($this->resources[$cacheKey][$block])) { // The resource given back is the key to the bucket that // contains this block. $this->resources[$cacheKey][$block] = $blockData; } } } while (false !== $currentTheme = $currentTheme->getParent($context)); } }
|