vendor/symfony/form/FormRegistry.php line 68

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;
  11. use Symfony\Component\Form\Exception\ExceptionInterface;
  12. use Symfony\Component\Form\Exception\InvalidArgumentException;
  13. use Symfony\Component\Form\Exception\LogicException;
  14. use Symfony\Component\Form\Exception\UnexpectedTypeException;
  15. /**
  16.  * The central registry of the Form component.
  17.  *
  18.  * @author Bernhard Schussek <bschussek@gmail.com>
  19.  */
  20. class FormRegistry implements FormRegistryInterface
  21. {
  22.     /**
  23.      * @var FormExtensionInterface[]
  24.      */
  25.     private $extensions = [];
  26.     /**
  27.      * @var ResolvedFormTypeInterface[]
  28.      */
  29.     private $types = [];
  30.     /**
  31.      * @var FormTypeGuesserInterface|false|null
  32.      */
  33.     private $guesser false;
  34.     /**
  35.      * @var ResolvedFormTypeFactoryInterface
  36.      */
  37.     private $resolvedTypeFactory;
  38.     private $checkedTypes = [];
  39.     /**
  40.      * @param FormExtensionInterface[] $extensions
  41.      *
  42.      * @throws UnexpectedTypeException if any extension does not implement FormExtensionInterface
  43.      */
  44.     public function __construct(array $extensionsResolvedFormTypeFactoryInterface $resolvedTypeFactory)
  45.     {
  46.         foreach ($extensions as $extension) {
  47.             if (!$extension instanceof FormExtensionInterface) {
  48.                 throw new UnexpectedTypeException($extensionFormExtensionInterface::class);
  49.             }
  50.         }
  51.         $this->extensions $extensions;
  52.         $this->resolvedTypeFactory $resolvedTypeFactory;
  53.     }
  54.     /**
  55.      * {@inheritdoc}
  56.      */
  57.     public function getType(string $name)
  58.     {
  59.         if (!isset($this->types[$name])) {
  60.             $type null;
  61.             foreach ($this->extensions as $extension) {
  62.                 if ($extension->hasType($name)) {
  63.                     $type $extension->getType($name);
  64.                     break;
  65.                 }
  66.             }
  67.             if (!$type) {
  68.                 // Support fully-qualified class names
  69.                 if (!class_exists($name)) {
  70.                     throw new InvalidArgumentException(sprintf('Could not load type "%s": class does not exist.'$name));
  71.                 }
  72.                 if (!is_subclass_of($nameFormTypeInterface::class)) {
  73.                     throw new InvalidArgumentException(sprintf('Could not load type "%s": class does not implement "Symfony\Component\Form\FormTypeInterface".'$name));
  74.                 }
  75.                 $type = new $name();
  76.             }
  77.             $this->types[$name] = $this->resolveType($type);
  78.         }
  79.         return $this->types[$name];
  80.     }
  81.     /**
  82.      * Wraps a type into a ResolvedFormTypeInterface implementation and connects it with its parent type.
  83.      */
  84.     private function resolveType(FormTypeInterface $type): ResolvedFormTypeInterface
  85.     {
  86.         $parentType $type->getParent();
  87.         $fqcn \get_class($type);
  88.         if (isset($this->checkedTypes[$fqcn])) {
  89.             $types implode(' > 'array_merge(array_keys($this->checkedTypes), [$fqcn]));
  90.             throw new LogicException(sprintf('Circular reference detected for form type "%s" (%s).'$fqcn$types));
  91.         }
  92.         $this->checkedTypes[$fqcn] = true;
  93.         $typeExtensions = [];
  94.         try {
  95.             foreach ($this->extensions as $extension) {
  96.                 $typeExtensions[] = $extension->getTypeExtensions($fqcn);
  97.             }
  98.             return $this->resolvedTypeFactory->createResolvedType(
  99.                 $type,
  100.                 array_merge([], ...$typeExtensions),
  101.                 $parentType $this->getType($parentType) : null
  102.             );
  103.         } finally {
  104.             unset($this->checkedTypes[$fqcn]);
  105.         }
  106.     }
  107.     /**
  108.      * {@inheritdoc}
  109.      */
  110.     public function hasType(string $name)
  111.     {
  112.         if (isset($this->types[$name])) {
  113.             return true;
  114.         }
  115.         try {
  116.             $this->getType($name);
  117.         } catch (ExceptionInterface $e) {
  118.             return false;
  119.         }
  120.         return true;
  121.     }
  122.     /**
  123.      * {@inheritdoc}
  124.      */
  125.     public function getTypeGuesser()
  126.     {
  127.         if (false === $this->guesser) {
  128.             $guessers = [];
  129.             foreach ($this->extensions as $extension) {
  130.                 $guesser $extension->getTypeGuesser();
  131.                 if ($guesser) {
  132.                     $guessers[] = $guesser;
  133.                 }
  134.             }
  135.             $this->guesser = !empty($guessers) ? new FormTypeGuesserChain($guessers) : null;
  136.         }
  137.         return $this->guesser;
  138.     }
  139.     /**
  140.      * {@inheritdoc}
  141.      */
  142.     public function getExtensions()
  143.     {
  144.         return $this->extensions;
  145.     }
  146. }