vendor/symfony/form/AbstractRendererEngine.php line 83

  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\Component\Form;
  11. use Symfony\Contracts\Service\ResetInterface;
  12. /**
  13.  * Default implementation of {@link FormRendererEngineInterface}.
  14.  *
  15.  * @author Bernhard Schussek <bschussek@gmail.com>
  16.  */
  17. abstract class AbstractRendererEngine implements FormRendererEngineInterfaceResetInterface
  18. {
  19.     /**
  20.      * The variable in {@link FormView} used as cache key.
  21.      */
  22.     public const CACHE_KEY_VAR 'cache_key';
  23.     /**
  24.      * @var array
  25.      */
  26.     protected $defaultThemes;
  27.     /**
  28.      * @var array[]
  29.      */
  30.     protected $themes = [];
  31.     /**
  32.      * @var bool[]
  33.      */
  34.     protected $useDefaultThemes = [];
  35.     /**
  36.      * @var array[]
  37.      */
  38.     protected $resources = [];
  39.     /**
  40.      * @var array<array<int|false>>
  41.      */
  42.     private array $resourceHierarchyLevels = [];
  43.     /**
  44.      * Creates a new renderer engine.
  45.      *
  46.      * @param array $defaultThemes The default themes. The type of these
  47.      *                             themes is open to the implementation.
  48.      */
  49.     public function __construct(array $defaultThemes = [])
  50.     {
  51.         $this->defaultThemes $defaultThemes;
  52.     }
  53.     public function setTheme(FormView $viewmixed $themesbool $useDefaultThemes true)
  54.     {
  55.         $cacheKey $view->vars[self::CACHE_KEY_VAR];
  56.         // Do not cast, as casting turns objects into arrays of properties
  57.         $this->themes[$cacheKey] = \is_array($themes) ? $themes : [$themes];
  58.         $this->useDefaultThemes[$cacheKey] = $useDefaultThemes;
  59.         // Unset instead of resetting to an empty array, in order to allow
  60.         // implementations (like TwigRendererEngine) to check whether $cacheKey
  61.         // is set at all.
  62.         unset($this->resources[$cacheKey], $this->resourceHierarchyLevels[$cacheKey]);
  63.     }
  64.     public function getResourceForBlockName(FormView $viewstring $blockName): mixed
  65.     {
  66.         $cacheKey $view->vars[self::CACHE_KEY_VAR];
  67.         if (!isset($this->resources[$cacheKey][$blockName])) {
  68.             $this->loadResourceForBlockName($cacheKey$view$blockName);
  69.         }
  70.         return $this->resources[$cacheKey][$blockName];
  71.     }
  72.     public function getResourceForBlockNameHierarchy(FormView $view, array $blockNameHierarchyint $hierarchyLevel): mixed
  73.     {
  74.         $cacheKey $view->vars[self::CACHE_KEY_VAR];
  75.         $blockName $blockNameHierarchy[$hierarchyLevel];
  76.         if (!isset($this->resources[$cacheKey][$blockName])) {
  77.             $this->loadResourceForBlockNameHierarchy($cacheKey$view$blockNameHierarchy$hierarchyLevel);
  78.         }
  79.         return $this->resources[$cacheKey][$blockName];
  80.     }
  81.     public function getResourceHierarchyLevel(FormView $view, array $blockNameHierarchyint $hierarchyLevel): int|false
  82.     {
  83.         $cacheKey $view->vars[self::CACHE_KEY_VAR];
  84.         $blockName $blockNameHierarchy[$hierarchyLevel];
  85.         if (!isset($this->resources[$cacheKey][$blockName])) {
  86.             $this->loadResourceForBlockNameHierarchy($cacheKey$view$blockNameHierarchy$hierarchyLevel);
  87.         }
  88.         // If $block was previously rendered loaded with loadTemplateForBlock(), the template
  89.         // is cached but the hierarchy level is not. In this case, we know that the  block
  90.         // exists at this very hierarchy level, so we can just set it.
  91.         if (!isset($this->resourceHierarchyLevels[$cacheKey][$blockName])) {
  92.             $this->resourceHierarchyLevels[$cacheKey][$blockName] = $hierarchyLevel;
  93.         }
  94.         return $this->resourceHierarchyLevels[$cacheKey][$blockName];
  95.     }
  96.     /**
  97.      * Loads the cache with the resource for a given block name.
  98.      *
  99.      * @see getResourceForBlock()
  100.      *
  101.      * @return bool
  102.      */
  103.     abstract protected function loadResourceForBlockName(string $cacheKeyFormView $viewstring $blockName);
  104.     /**
  105.      * Loads the cache with the resource for a specific level of a block hierarchy.
  106.      *
  107.      * @see getResourceForBlockHierarchy()
  108.      */
  109.     private function loadResourceForBlockNameHierarchy(string $cacheKeyFormView $view, array $blockNameHierarchyint $hierarchyLevel): bool
  110.     {
  111.         $blockName $blockNameHierarchy[$hierarchyLevel];
  112.         // Try to find a template for that block
  113.         if ($this->loadResourceForBlockName($cacheKey$view$blockName)) {
  114.             // If loadTemplateForBlock() returns true, it was able to populate the
  115.             // cache. The only missing thing is to set the hierarchy level at which
  116.             // the template was found.
  117.             $this->resourceHierarchyLevels[$cacheKey][$blockName] = $hierarchyLevel;
  118.             return true;
  119.         }
  120.         if ($hierarchyLevel 0) {
  121.             $parentLevel $hierarchyLevel 1;
  122.             $parentBlockName $blockNameHierarchy[$parentLevel];
  123.             // The next two if statements contain slightly duplicated code. This is by intention
  124.             // and tries to avoid execution of unnecessary checks in order to increase performance.
  125.             if (isset($this->resources[$cacheKey][$parentBlockName])) {
  126.                 // It may happen that the parent block is already loaded, but its level is not.
  127.                 // In this case, the parent block must have been loaded by loadResourceForBlock(),
  128.                 // which does not check the hierarchy of the block. Subsequently the block must have
  129.                 // been found directly on the parent level.
  130.                 if (!isset($this->resourceHierarchyLevels[$cacheKey][$parentBlockName])) {
  131.                     $this->resourceHierarchyLevels[$cacheKey][$parentBlockName] = $parentLevel;
  132.                 }
  133.                 // Cache the shortcuts for further accesses
  134.                 $this->resources[$cacheKey][$blockName] = $this->resources[$cacheKey][$parentBlockName];
  135.                 $this->resourceHierarchyLevels[$cacheKey][$blockName] = $this->resourceHierarchyLevels[$cacheKey][$parentBlockName];
  136.                 return true;
  137.             }
  138.             if ($this->loadResourceForBlockNameHierarchy($cacheKey$view$blockNameHierarchy$parentLevel)) {
  139.                 // Cache the shortcuts for further accesses
  140.                 $this->resources[$cacheKey][$blockName] = $this->resources[$cacheKey][$parentBlockName];
  141.                 $this->resourceHierarchyLevels[$cacheKey][$blockName] = $this->resourceHierarchyLevels[$cacheKey][$parentBlockName];
  142.                 return true;
  143.             }
  144.         }
  145.         // Cache the result for further accesses
  146.         $this->resources[$cacheKey][$blockName] = false;
  147.         $this->resourceHierarchyLevels[$cacheKey][$blockName] = false;
  148.         return false;
  149.     }
  150.     public function reset(): void
  151.     {
  152.         $this->themes = [];
  153.         $this->useDefaultThemes = [];
  154.         $this->resources = [];
  155.         $this->resourceHierarchyLevels = [];
  156.     }
  157. }