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

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 $lists = [];
  31.     /**
  32.      * @var ChoiceListView[]
  33.      */
  34.     private $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.      * @param mixed $value The value to hash
  42.      *
  43.      * @return string The SHA-256 hash
  44.      *
  45.      * @internal
  46.      */
  47.     public static function generateHash($valuestring $namespace ''): string
  48.     {
  49.         if (\is_object($value)) {
  50.             $value spl_object_hash($value);
  51.         } elseif (\is_array($value)) {
  52.             array_walk_recursive($value, function (&$v) {
  53.                 if (\is_object($v)) {
  54.                     $v spl_object_hash($v);
  55.                 }
  56.             });
  57.         }
  58.         return hash('sha256'$namespace.':'.serialize($value));
  59.     }
  60.     public function __construct(ChoiceListFactoryInterface $decoratedFactory)
  61.     {
  62.         $this->decoratedFactory $decoratedFactory;
  63.     }
  64.     /**
  65.      * Returns the decorated factory.
  66.      *
  67.      * @return ChoiceListFactoryInterface The decorated factory
  68.      */
  69.     public function getDecoratedFactory()
  70.     {
  71.         return $this->decoratedFactory;
  72.     }
  73.     /**
  74.      * {@inheritdoc}
  75.      *
  76.      * @param callable|Cache\ChoiceValue|null  $value  The callable or static option for
  77.      *                                                 generating the choice values
  78.      * @param callable|Cache\ChoiceFilter|null $filter The callable or static option for
  79.      *                                                 filtering the choices
  80.      */
  81.     public function createListFromChoices(iterable $choices$value null/*, $filter = null*/)
  82.     {
  83.         $filter \func_num_args() > func_get_arg(2) : null;
  84.         if ($choices instanceof \Traversable) {
  85.             $choices iterator_to_array($choices);
  86.         }
  87.         $cache true;
  88.         // Only cache per value and filter when needed. The value is not validated on purpose.
  89.         // The decorated factory may decide which values to accept and which not.
  90.         if ($value instanceof Cache\ChoiceValue) {
  91.             $value $value->getOption();
  92.         } elseif ($value) {
  93.             $cache false;
  94.         }
  95.         if ($filter instanceof Cache\ChoiceFilter) {
  96.             $filter $filter->getOption();
  97.         } elseif ($filter) {
  98.             $cache false;
  99.         }
  100.         if (!$cache) {
  101.             return $this->decoratedFactory->createListFromChoices($choices$value$filter);
  102.         }
  103.         $hash self::generateHash([$choices$value$filter], 'fromChoices');
  104.         if (!isset($this->lists[$hash])) {
  105.             $this->lists[$hash] = $this->decoratedFactory->createListFromChoices($choices$value$filter);
  106.         }
  107.         return $this->lists[$hash];
  108.     }
  109.     /**
  110.      * {@inheritdoc}
  111.      *
  112.      * @param ChoiceLoaderInterface|Cache\ChoiceLoader $loader The loader or static loader to load
  113.      *                                                         the choices lazily
  114.      * @param callable|Cache\ChoiceValue|null          $value  The callable or static option for
  115.      *                                                         generating the choice values
  116.      * @param callable|Cache\ChoiceFilter|null         $filter The callable or static option for
  117.      *                                                         filtering the choices
  118.      */
  119.     public function createListFromLoader(ChoiceLoaderInterface $loader$value null/*, $filter = null*/)
  120.     {
  121.         $filter \func_num_args() > func_get_arg(2) : null;
  122.         $cache true;
  123.         if ($loader instanceof Cache\ChoiceLoader) {
  124.             $loader $loader->getOption();
  125.         } else {
  126.             $cache false;
  127.         }
  128.         if ($value instanceof Cache\ChoiceValue) {
  129.             $value $value->getOption();
  130.         } elseif ($value) {
  131.             $cache false;
  132.         }
  133.         if ($filter instanceof Cache\ChoiceFilter) {
  134.             $filter $filter->getOption();
  135.         } elseif ($filter) {
  136.             $cache false;
  137.         }
  138.         if (!$cache) {
  139.             return $this->decoratedFactory->createListFromLoader($loader$value$filter);
  140.         }
  141.         $hash self::generateHash([$loader$value$filter], 'fromLoader');
  142.         if (!isset($this->lists[$hash])) {
  143.             $this->lists[$hash] = $this->decoratedFactory->createListFromLoader($loader$value$filter);
  144.         }
  145.         return $this->lists[$hash];
  146.     }
  147.     /**
  148.      * {@inheritdoc}
  149.      *
  150.      * @param array|callable|Cache\PreferredChoice|null $preferredChoices The preferred choices
  151.      * @param callable|false|Cache\ChoiceLabel|null     $label            The option or static option generating the choice labels
  152.      * @param callable|Cache\ChoiceFieldName|null       $index            The option or static option generating the view indices
  153.      * @param callable|Cache\GroupBy|null               $groupBy          The option or static option generating the group names
  154.      * @param array|callable|Cache\ChoiceAttr|null      $attr             The option or static option generating the HTML attributes
  155.      */
  156.     public function createView(ChoiceListInterface $list$preferredChoices null$label null$index null$groupBy null$attr null)
  157.     {
  158.         $cache true;
  159.         if ($preferredChoices instanceof Cache\PreferredChoice) {
  160.             $preferredChoices $preferredChoices->getOption();
  161.         } elseif ($preferredChoices) {
  162.             $cache false;
  163.         }
  164.         if ($label instanceof Cache\ChoiceLabel) {
  165.             $label $label->getOption();
  166.         } elseif (null !== $label) {
  167.             $cache false;
  168.         }
  169.         if ($index instanceof Cache\ChoiceFieldName) {
  170.             $index $index->getOption();
  171.         } elseif ($index) {
  172.             $cache false;
  173.         }
  174.         if ($groupBy instanceof Cache\GroupBy) {
  175.             $groupBy $groupBy->getOption();
  176.         } elseif ($groupBy) {
  177.             $cache false;
  178.         }
  179.         if ($attr instanceof Cache\ChoiceAttr) {
  180.             $attr $attr->getOption();
  181.         } elseif ($attr) {
  182.             $cache false;
  183.         }
  184.         if (!$cache) {
  185.             return $this->decoratedFactory->createView($list$preferredChoices$label$index$groupBy$attr);
  186.         }
  187.         $hash self::generateHash([$list$preferredChoices$label$index$groupBy$attr]);
  188.         if (!isset($this->views[$hash])) {
  189.             $this->views[$hash] = $this->decoratedFactory->createView(
  190.                 $list,
  191.                 $preferredChoices,
  192.                 $label,
  193.                 $index,
  194.                 $groupBy,
  195.                 $attr
  196.             );
  197.         }
  198.         return $this->views[$hash];
  199.     }
  200.     public function reset()
  201.     {
  202.         $this->lists = [];
  203.         $this->views = [];
  204.         Cache\AbstractStaticOption::reset();
  205.     }
  206. }