vendor/symfony/form/FormRegistry.php line 64

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