FormRegistry.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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\UnexpectedTypeException;
  14. /**
  15. * The central registry of the Form component.
  16. *
  17. * @author Bernhard Schussek <bschussek@gmail.com>
  18. */
  19. class FormRegistry implements FormRegistryInterface
  20. {
  21. /**
  22. * Extensions.
  23. *
  24. * @var FormExtensionInterface[] An array of FormExtensionInterface
  25. */
  26. private $extensions = array();
  27. /**
  28. * @var ResolvedFormTypeInterface[]
  29. */
  30. private $types = array();
  31. /**
  32. * @var string[]
  33. */
  34. private $legacyNames = array();
  35. /**
  36. * @var FormTypeGuesserInterface|false|null
  37. */
  38. private $guesser = false;
  39. /**
  40. * @var ResolvedFormTypeFactoryInterface
  41. */
  42. private $resolvedTypeFactory;
  43. /**
  44. * @param FormExtensionInterface[] $extensions An array of FormExtensionInterface
  45. * @param ResolvedFormTypeFactoryInterface $resolvedTypeFactory The factory for resolved form types
  46. *
  47. * @throws UnexpectedTypeException if any extension does not implement FormExtensionInterface
  48. */
  49. public function __construct(array $extensions, ResolvedFormTypeFactoryInterface $resolvedTypeFactory)
  50. {
  51. foreach ($extensions as $extension) {
  52. if (!$extension instanceof FormExtensionInterface) {
  53. throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormExtensionInterface');
  54. }
  55. }
  56. $this->extensions = $extensions;
  57. $this->resolvedTypeFactory = $resolvedTypeFactory;
  58. }
  59. /**
  60. * {@inheritdoc}
  61. */
  62. public function getType($name)
  63. {
  64. if (!isset($this->types[$name])) {
  65. $type = null;
  66. foreach ($this->extensions as $extension) {
  67. if ($extension->hasType($name)) {
  68. $type = $extension->getType($name);
  69. break;
  70. }
  71. }
  72. if (!$type) {
  73. // Support fully-qualified class names
  74. if (!class_exists($name)) {
  75. throw new InvalidArgumentException(sprintf('Could not load type "%s": class does not exist.', $name));
  76. }
  77. if (!is_subclass_of($name, 'Symfony\Component\Form\FormTypeInterface')) {
  78. throw new InvalidArgumentException(sprintf('Could not load type "%s": class does not implement "Symfony\Component\Form\FormTypeInterface".', $name));
  79. }
  80. $type = new $name();
  81. }
  82. $this->resolveAndAddType($type);
  83. }
  84. if (isset($this->legacyNames[$name])) {
  85. @trigger_error(sprintf('Accessing type "%s" by its string name is deprecated since Symfony 2.8 and will be removed in 3.0. Use the fully-qualified type class name "%s" instead.', $name, \get_class($this->types[$name]->getInnerType())), E_USER_DEPRECATED);
  86. }
  87. return $this->types[$name];
  88. }
  89. /**
  90. * Wraps a type into a ResolvedFormTypeInterface implementation and connects
  91. * it with its parent type.
  92. *
  93. * @param FormTypeInterface $type The type to resolve
  94. *
  95. * @return ResolvedFormTypeInterface The resolved type
  96. */
  97. private function resolveAndAddType(FormTypeInterface $type)
  98. {
  99. $typeExtensions = array();
  100. $parentType = $type->getParent();
  101. $fqcn = \get_class($type);
  102. $name = $type->getName();
  103. $hasCustomName = $name !== $fqcn;
  104. if ($parentType instanceof FormTypeInterface) {
  105. @trigger_error(sprintf('Returning a FormTypeInterface from %s::getParent() is deprecated since Symfony 2.8 and will be removed in 3.0. Return the fully-qualified type class name instead.', $fqcn), E_USER_DEPRECATED);
  106. $this->resolveAndAddType($parentType);
  107. $parentType = $parentType->getName();
  108. }
  109. if ($hasCustomName) {
  110. foreach ($this->extensions as $extension) {
  111. if ($x = $extension->getTypeExtensions($name)) {
  112. @trigger_error(sprintf('Returning a type name from %s::getExtendedType() is deprecated since Symfony 2.8 and will be removed in 3.0. Return the fully-qualified type class name instead.', \get_class($x[0])), E_USER_DEPRECATED);
  113. $typeExtensions = array_merge($typeExtensions, $x);
  114. }
  115. }
  116. }
  117. foreach ($this->extensions as $extension) {
  118. $typeExtensions = array_merge(
  119. $typeExtensions,
  120. $extension->getTypeExtensions($fqcn)
  121. );
  122. }
  123. $resolvedType = $this->resolvedTypeFactory->createResolvedType(
  124. $type,
  125. $typeExtensions,
  126. $parentType ? $this->getType($parentType) : null
  127. );
  128. $this->types[$fqcn] = $resolvedType;
  129. if ($hasCustomName) {
  130. // Enable access by the explicit type name until Symfony 3.0
  131. $this->types[$name] = $resolvedType;
  132. $this->legacyNames[$name] = true;
  133. }
  134. }
  135. /**
  136. * {@inheritdoc}
  137. */
  138. public function hasType($name)
  139. {
  140. if (isset($this->legacyNames[$name])) {
  141. @trigger_error(sprintf('Accessing type "%s" by its string name is deprecated since Symfony 2.8 and will be removed in 3.0. Use the fully-qualified type class name "%s" instead.', $name, \get_class($this->types[$name]->getInnerType())), E_USER_DEPRECATED);
  142. }
  143. if (isset($this->types[$name])) {
  144. return true;
  145. }
  146. try {
  147. $this->getType($name);
  148. } catch (ExceptionInterface $e) {
  149. return false;
  150. }
  151. return true;
  152. }
  153. /**
  154. * {@inheritdoc}
  155. */
  156. public function getTypeGuesser()
  157. {
  158. if (false === $this->guesser) {
  159. $guessers = array();
  160. foreach ($this->extensions as $extension) {
  161. $guesser = $extension->getTypeGuesser();
  162. if ($guesser) {
  163. $guessers[] = $guesser;
  164. }
  165. }
  166. $this->guesser = !empty($guessers) ? new FormTypeGuesserChain($guessers) : null;
  167. }
  168. return $this->guesser;
  169. }
  170. /**
  171. * {@inheritdoc}
  172. */
  173. public function getExtensions()
  174. {
  175. return $this->extensions;
  176. }
  177. }