vendor/symfony/form/ChoiceList/Factory/CachingFactoryDecorator.php line 157

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\Component\Form\ChoiceList\Factory;
  11. use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
  12. use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
  13. use Symfony\Component\Form\ChoiceList\View\ChoiceListView;
  14. use Symfony\Contracts\Service\ResetInterface;
  15. /**
  16.  * Caches the choice lists created by the decorated factory.
  17.  *
  18.  * To cache a list based on its options, arguments must be decorated
  19.  * by a {@see Cache\AbstractStaticOption} implementation.
  20.  *
  21.  * @author Bernhard Schussek <bschussek@gmail.com>
  22.  * @author Jules Pietri <jules@heahprod.com>
  23.  */
  24. class CachingFactoryDecorator implements ChoiceListFactoryInterfaceResetInterface
  25. {
  26.     private $decoratedFactory;
  27.     /**
  28.      * @var ChoiceListInterface[]
  29.      */
  30.     private array $lists = [];
  31.     /**
  32.      * @var ChoiceListView[]
  33.      */
  34.     private array $views = [];
  35.     /**
  36.      * Generates a SHA-256 hash for the given value.
  37.      *
  38.      * Optionally, a namespace string can be passed. Calling this method will
  39.      * the same values, but different namespaces, will return different hashes.
  40.      *
  41.      * @return string The SHA-256 hash
  42.      *
  43.      * @internal
  44.      */
  45.     public static function generateHash(mixed $valuestring $namespace ''): string
  46.     {
  47.         if (\is_object($value)) {
  48.             $value spl_object_hash($value);
  49.         } elseif (\is_array($value)) {
  50.             array_walk_recursive($value, function (&$v) {
  51.                 if (\is_object($v)) {
  52.                     $v spl_object_hash($v);
  53.                 }
  54.             });
  55.         }
  56.         return hash('sha256'$namespace.':'.serialize($value));
  57.     }
  58.     public function __construct(ChoiceListFactoryInterface $decoratedFactory)
  59.     {
  60.         $this->decoratedFactory $decoratedFactory;
  61.     }
  62.     /**
  63.      * Returns the decorated factory.
  64.      */
  65.     public function getDecoratedFactory(): ChoiceListFactoryInterface
  66.     {
  67.         return $this->decoratedFactory;
  68.     }
  69.     /**
  70.      * {@inheritdoc}
  71.      */
  72.     public function createListFromChoices(iterable $choicesmixed $value nullmixed $filter null): ChoiceListInterface
  73.     {
  74.         if ($choices instanceof \Traversable) {
  75.             $choices iterator_to_array($choices);
  76.         }
  77.         $cache true;
  78.         // Only cache per value and filter when needed. The value is not validated on purpose.
  79.         // The decorated factory may decide which values to accept and which not.
  80.         if ($value instanceof Cache\ChoiceValue) {
  81.             $value $value->getOption();
  82.         } elseif ($value) {
  83.             $cache false;
  84.         }
  85.         if ($filter instanceof Cache\ChoiceFilter) {
  86.             $filter $filter->getOption();
  87.         } elseif ($filter) {
  88.             $cache false;
  89.         }
  90.         if (!$cache) {
  91.             return $this->decoratedFactory->createListFromChoices($choices$value$filter);
  92.         }
  93.         $hash self::generateHash([$choices$value$filter], 'fromChoices');
  94.         if (!isset($this->lists[$hash])) {
  95.             $this->lists[$hash] = $this->decoratedFactory->createListFromChoices($choices$value$filter);
  96.         }
  97.         return $this->lists[$hash];
  98.     }
  99.     /**
  100.      * {@inheritdoc}
  101.      */
  102.     public function createListFromLoader(ChoiceLoaderInterface $loadermixed $value nullmixed $filter null): ChoiceListInterface
  103.     {
  104.         $cache true;
  105.         if ($loader instanceof Cache\ChoiceLoader) {
  106.             $loader $loader->getOption();
  107.         } else {
  108.             $cache false;
  109.         }
  110.         if ($value instanceof Cache\ChoiceValue) {
  111.             $value $value->getOption();
  112.         } elseif ($value) {
  113.             $cache false;
  114.         }
  115.         if ($filter instanceof Cache\ChoiceFilter) {
  116.             $filter $filter->getOption();
  117.         } elseif ($filter) {
  118.             $cache false;
  119.         }
  120.         if (!$cache) {
  121.             return $this->decoratedFactory->createListFromLoader($loader$value$filter);
  122.         }
  123.         $hash self::generateHash([$loader$value$filter], 'fromLoader');
  124.         if (!isset($this->lists[$hash])) {
  125.             $this->lists[$hash] = $this->decoratedFactory->createListFromLoader($loader$value$filter);
  126.         }
  127.         return $this->lists[$hash];
  128.     }
  129.     /**
  130.      * {@inheritdoc}
  131.      */
  132.     public function createView(ChoiceListInterface $listmixed $preferredChoices nullmixed $label nullmixed $index nullmixed $groupBy nullmixed $attr nullmixed $labelTranslationParameters = []): ChoiceListView
  133.     {
  134.         $cache true;
  135.         if ($preferredChoices instanceof Cache\PreferredChoice) {
  136.             $preferredChoices $preferredChoices->getOption();
  137.         } elseif ($preferredChoices) {
  138.             $cache false;
  139.         }
  140.         if ($label instanceof Cache\ChoiceLabel) {
  141.             $label $label->getOption();
  142.         } elseif (null !== $label) {
  143.             $cache false;
  144.         }
  145.         if ($index instanceof Cache\ChoiceFieldName) {
  146.             $index $index->getOption();
  147.         } elseif ($index) {
  148.             $cache false;
  149.         }
  150.         if ($groupBy instanceof Cache\GroupBy) {
  151.             $groupBy $groupBy->getOption();
  152.         } elseif ($groupBy) {
  153.             $cache false;
  154.         }
  155.         if ($attr instanceof Cache\ChoiceAttr) {
  156.             $attr $attr->getOption();
  157.         } elseif ($attr) {
  158.             $cache false;
  159.         }
  160.         if ($labelTranslationParameters instanceof Cache\ChoiceTranslationParameters) {
  161.             $labelTranslationParameters $labelTranslationParameters->getOption();
  162.         } elseif ([] !== $labelTranslationParameters) {
  163.             $cache false;
  164.         }
  165.         if (!$cache) {
  166.             return $this->decoratedFactory->createView(
  167.                 $list,
  168.                 $preferredChoices,
  169.                 $label,
  170.                 $index,
  171.                 $groupBy,
  172.                 $attr,
  173.                 $labelTranslationParameters
  174.             );
  175.         }
  176.         $hash self::generateHash([$list$preferredChoices$label$index$groupBy$attr$labelTranslationParameters]);
  177.         if (!isset($this->views[$hash])) {
  178.             $this->views[$hash] = $this->decoratedFactory->createView(
  179.                 $list,
  180.                 $preferredChoices,
  181.                 $label,
  182.                 $index,
  183.                 $groupBy,
  184.                 $attr,
  185.                 $labelTranslationParameters
  186.             );
  187.         }
  188.         return $this->views[$hash];
  189.     }
  190.     public function reset()
  191.     {
  192.         $this->lists = [];
  193.         $this->views = [];
  194.         Cache\AbstractStaticOption::reset();
  195.     }
  196. }