vendor/symfony/twig-bridge/Form/TwigRendererEngine.php line 102

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Bridge\Twig\Form;
  11. use Symfony\Component\Form\AbstractRendererEngine;
  12. use Symfony\Component\Form\FormView;
  13. use Twig\Environment;
  14. use Twig\Template;
  15. /**
  16.  * @author Bernhard Schussek <bschussek@gmail.com>
  17.  */
  18. class TwigRendererEngine extends AbstractRendererEngine
  19. {
  20.     /**
  21.      * @var Environment
  22.      */
  23.     private $environment;
  24.     /**
  25.      * @var Template
  26.      */
  27.     private $template;
  28.     public function __construct(array $defaultThemesEnvironment $environment)
  29.     {
  30.         parent::__construct($defaultThemes);
  31.         $this->environment $environment;
  32.     }
  33.     /**
  34.      * {@inheritdoc}
  35.      */
  36.     public function renderBlock(FormView $view$resource$blockName, array $variables = [])
  37.     {
  38.         $cacheKey $view->vars[self::CACHE_KEY_VAR];
  39.         $context $this->environment->mergeGlobals($variables);
  40.         ob_start();
  41.         // By contract,This method can only be called after getting the resource
  42.         // (which is passed to the method). Getting a resource for the first time
  43.         // (with an empty cache) is guaranteed to invoke loadResourcesFromTheme(),
  44.         // where the property $template is initialized.
  45.         // We do not call renderBlock here to avoid too many nested level calls
  46.         // (XDebug limits the level to 100 by default)
  47.         $this->template->displayBlock($blockName$context$this->resources[$cacheKey]);
  48.         return ob_get_clean();
  49.     }
  50.     /**
  51.      * Loads the cache with the resource for a given block name.
  52.      *
  53.      * This implementation eagerly loads all blocks of the themes assigned to the given view
  54.      * and all of its ancestors views. This is necessary, because Twig receives the
  55.      * list of blocks later. At that point, all blocks must already be loaded, for the
  56.      * case that the function "block()" is used in the Twig template.
  57.      *
  58.      * @see getResourceForBlock()
  59.      *
  60.      * @param string   $cacheKey  The cache key of the form view
  61.      * @param FormView $view      The form view for finding the applying themes
  62.      * @param string   $blockName The name of the block to load
  63.      *
  64.      * @return bool True if the resource could be loaded, false otherwise
  65.      */
  66.     protected function loadResourceForBlockName($cacheKeyFormView $view$blockName)
  67.     {
  68.         // The caller guarantees that $this->resources[$cacheKey][$block] is
  69.         // not set, but it doesn't have to check whether $this->resources[$cacheKey]
  70.         // is set. If $this->resources[$cacheKey] is set, all themes for this
  71.         // $cacheKey are already loaded (due to the eager population, see doc comment).
  72.         if (isset($this->resources[$cacheKey])) {
  73.             // As said in the previous, the caller guarantees that
  74.             // $this->resources[$cacheKey][$block] is not set. Since the themes are
  75.             // already loaded, it can only be a non-existing block.
  76.             $this->resources[$cacheKey][$blockName] = false;
  77.             return false;
  78.         }
  79.         // Recursively try to find the block in the themes assigned to $view,
  80.         // then of its parent view, then of the parent view of the parent and so on.
  81.         // When the root view is reached in this recursion, also the default
  82.         // themes are taken into account.
  83.         // Check each theme whether it contains the searched block
  84.         if (isset($this->themes[$cacheKey])) {
  85.             for ($i = \count($this->themes[$cacheKey]) - 1$i >= 0; --$i) {
  86.                 $this->loadResourcesFromTheme($cacheKey$this->themes[$cacheKey][$i]);
  87.                 // CONTINUE LOADING (see doc comment)
  88.             }
  89.         }
  90.         // Check the default themes once we reach the root view without success
  91.         if (!$view->parent) {
  92.             if (!isset($this->useDefaultThemes[$cacheKey]) || $this->useDefaultThemes[$cacheKey]) {
  93.                 for ($i = \count($this->defaultThemes) - 1$i >= 0; --$i) {
  94.                     $this->loadResourcesFromTheme($cacheKey$this->defaultThemes[$i]);
  95.                     // CONTINUE LOADING (see doc comment)
  96.                 }
  97.             }
  98.         }
  99.         // Proceed with the themes of the parent view
  100.         if ($view->parent) {
  101.             $parentCacheKey $view->parent->vars[self::CACHE_KEY_VAR];
  102.             if (!isset($this->resources[$parentCacheKey])) {
  103.                 $this->loadResourceForBlockName($parentCacheKey$view->parent$blockName);
  104.             }
  105.             // EAGER CACHE POPULATION (see doc comment)
  106.             foreach ($this->resources[$parentCacheKey] as $nestedBlockName => $resource) {
  107.                 if (!isset($this->resources[$cacheKey][$nestedBlockName])) {
  108.                     $this->resources[$cacheKey][$nestedBlockName] = $resource;
  109.                 }
  110.             }
  111.         }
  112.         // Even though we loaded the themes, it can happen that none of them
  113.         // contains the searched block
  114.         if (!isset($this->resources[$cacheKey][$blockName])) {
  115.             // Cache that we didn't find anything to speed up further accesses
  116.             $this->resources[$cacheKey][$blockName] = false;
  117.         }
  118.         return false !== $this->resources[$cacheKey][$blockName];
  119.     }
  120.     /**
  121.      * Loads the resources for all blocks in a theme.
  122.      *
  123.      * @param string $cacheKey The cache key for storing the resource
  124.      * @param mixed  $theme    The theme to load the block from. This parameter
  125.      *                         is passed by reference, because it might be necessary
  126.      *                         to initialize the theme first. Any changes made to
  127.      *                         this variable will be kept and be available upon
  128.      *                         further calls to this method using the same theme.
  129.      */
  130.     protected function loadResourcesFromTheme($cacheKey, &$theme)
  131.     {
  132.         if (!$theme instanceof Template) {
  133.             /* @var Template $theme */
  134.             $theme $this->environment->load($theme)->unwrap();
  135.         }
  136.         if (null === $this->template) {
  137.             // Store the first Template instance that we find so that
  138.             // we can call displayBlock() later on. It doesn't matter *which*
  139.             // template we use for that, since we pass the used blocks manually
  140.             // anyway.
  141.             $this->template $theme;
  142.         }
  143.         // Use a separate variable for the inheritance traversal, because
  144.         // theme is a reference and we don't want to change it.
  145.         $currentTheme $theme;
  146.         $context $this->environment->mergeGlobals([]);
  147.         // The do loop takes care of template inheritance.
  148.         // Add blocks from all templates in the inheritance tree, but avoid
  149.         // overriding blocks already set.
  150.         do {
  151.             foreach ($currentTheme->getBlocks() as $block => $blockData) {
  152.                 if (!isset($this->resources[$cacheKey][$block])) {
  153.                     // The resource given back is the key to the bucket that
  154.                     // contains this block.
  155.                     $this->resources[$cacheKey][$block] = $blockData;
  156.                 }
  157.             }
  158.         } while (false !== $currentTheme $currentTheme->getParent($context));
  159.     }
  160. }