FormFactory.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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\UnexpectedTypeException;
  12. use Symfony\Component\Form\Util\StringUtil;
  13. class FormFactory implements FormFactoryInterface
  14. {
  15. private $registry;
  16. private $resolvedTypeFactory;
  17. public function __construct(FormRegistryInterface $registry, ResolvedFormTypeFactoryInterface $resolvedTypeFactory)
  18. {
  19. $this->registry = $registry;
  20. $this->resolvedTypeFactory = $resolvedTypeFactory;
  21. }
  22. /**
  23. * {@inheritdoc}
  24. */
  25. public function create($type = 'Symfony\Component\Form\Extension\Core\Type\FormType', $data = null, array $options = array())
  26. {
  27. return $this->createBuilder($type, $data, $options)->getForm();
  28. }
  29. /**
  30. * {@inheritdoc}
  31. */
  32. public function createNamed($name, $type = 'Symfony\Component\Form\Extension\Core\Type\FormType', $data = null, array $options = array())
  33. {
  34. return $this->createNamedBuilder($name, $type, $data, $options)->getForm();
  35. }
  36. /**
  37. * {@inheritdoc}
  38. */
  39. public function createForProperty($class, $property, $data = null, array $options = array())
  40. {
  41. return $this->createBuilderForProperty($class, $property, $data, $options)->getForm();
  42. }
  43. /**
  44. * {@inheritdoc}
  45. */
  46. public function createBuilder($type = 'Symfony\Component\Form\Extension\Core\Type\FormType', $data = null, array $options = array())
  47. {
  48. $name = null;
  49. if ($type instanceof ResolvedFormTypeInterface) {
  50. $typeObject = $type;
  51. } elseif ($type instanceof FormTypeInterface) {
  52. $typeObject = $type;
  53. } elseif (\is_string($type)) {
  54. $typeObject = $this->registry->getType($type);
  55. $name = $type;
  56. } else {
  57. throw new UnexpectedTypeException($type, 'string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface');
  58. }
  59. if (method_exists($typeObject, 'getBlockPrefix')) {
  60. // As of Symfony 3.0, the block prefix of the type is used as default name
  61. $name = $typeObject->getBlockPrefix();
  62. } else {
  63. // BC when there is no block prefix
  64. if (null === $name) {
  65. $name = $typeObject->getName();
  66. }
  67. if (false !== strpos($name, '\\')) {
  68. // FQCN
  69. $name = StringUtil::fqcnToBlockPrefix($name);
  70. }
  71. }
  72. return $this->createNamedBuilder($name, $type, $data, $options);
  73. }
  74. /**
  75. * {@inheritdoc}
  76. */
  77. public function createNamedBuilder($name, $type = 'Symfony\Component\Form\Extension\Core\Type\FormType', $data = null, array $options = array())
  78. {
  79. if (null !== $data && !array_key_exists('data', $options)) {
  80. $options['data'] = $data;
  81. }
  82. if ($type instanceof FormTypeInterface) {
  83. @trigger_error(sprintf('Passing type instances to FormBuilder::add(), Form::add() or the FormFactory is deprecated since Symfony 2.8 and will not be supported in 3.0. Use the fully-qualified type class name instead (%s).', \get_class($type)), E_USER_DEPRECATED);
  84. $type = $this->resolveType($type);
  85. } elseif (\is_string($type)) {
  86. $type = $this->registry->getType($type);
  87. } elseif ($type instanceof ResolvedFormTypeInterface) {
  88. @trigger_error(sprintf('Passing type instances to FormBuilder::add(), Form::add() or the FormFactory is deprecated since Symfony 2.8 and will not be supported in 3.0. Use the fully-qualified type class name instead (%s).', \get_class($type->getInnerType())), E_USER_DEPRECATED);
  89. } else {
  90. throw new UnexpectedTypeException($type, 'string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface');
  91. }
  92. $builder = $type->createBuilder($this, $name, $options);
  93. // Explicitly call buildForm() in order to be able to override either
  94. // createBuilder() or buildForm() in the resolved form type
  95. $type->buildForm($builder, $builder->getOptions());
  96. return $builder;
  97. }
  98. /**
  99. * {@inheritdoc}
  100. */
  101. public function createBuilderForProperty($class, $property, $data = null, array $options = array())
  102. {
  103. if (null === $guesser = $this->registry->getTypeGuesser()) {
  104. return $this->createNamedBuilder($property, 'Symfony\Component\Form\Extension\Core\Type\TextType', $data, $options);
  105. }
  106. $typeGuess = $guesser->guessType($class, $property);
  107. $maxLengthGuess = $guesser->guessMaxLength($class, $property);
  108. $requiredGuess = $guesser->guessRequired($class, $property);
  109. $patternGuess = $guesser->guessPattern($class, $property);
  110. $type = $typeGuess ? $typeGuess->getType() : 'Symfony\Component\Form\Extension\Core\Type\TextType';
  111. $maxLength = $maxLengthGuess ? $maxLengthGuess->getValue() : null;
  112. $pattern = $patternGuess ? $patternGuess->getValue() : null;
  113. if (null !== $pattern) {
  114. $options = array_replace_recursive(array('attr' => array('pattern' => $pattern)), $options);
  115. }
  116. if (null !== $maxLength) {
  117. $options = array_replace_recursive(array('attr' => array('maxlength' => $maxLength)), $options);
  118. }
  119. if ($requiredGuess) {
  120. $options = array_merge(array('required' => $requiredGuess->getValue()), $options);
  121. }
  122. // user options may override guessed options
  123. if ($typeGuess) {
  124. $attrs = array();
  125. $typeGuessOptions = $typeGuess->getOptions();
  126. if (isset($typeGuessOptions['attr']) && isset($options['attr'])) {
  127. $attrs = array('attr' => array_merge($typeGuessOptions['attr'], $options['attr']));
  128. }
  129. $options = array_merge($typeGuessOptions, $options, $attrs);
  130. }
  131. return $this->createNamedBuilder($property, $type, $data, $options);
  132. }
  133. /**
  134. * Wraps a type into a ResolvedFormTypeInterface implementation and connects
  135. * it with its parent type.
  136. *
  137. * @return ResolvedFormTypeInterface The resolved type
  138. */
  139. private function resolveType(FormTypeInterface $type)
  140. {
  141. $parentType = $type->getParent();
  142. if ($parentType instanceof FormTypeInterface) {
  143. $parentType = $this->resolveType($parentType);
  144. } elseif (null !== $parentType) {
  145. $parentType = $this->registry->getType($parentType);
  146. }
  147. return $this->resolvedTypeFactory->createResolvedType(
  148. $type,
  149. // Type extensions are not supported for unregistered type instances,
  150. // i.e. type instances that are passed to the FormFactory directly,
  151. // nor for their parents, if getParent() also returns a type instance.
  152. array(),
  153. $parentType
  154. );
  155. }
  156. }