FormFactory.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien.potencier@symfony-project.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\Guess\Guess;
  12. use Symfony\Component\Form\Exception\FormException;
  13. class FormFactory implements FormFactoryInterface
  14. {
  15. private $extensions = array();
  16. private $types = array();
  17. private $guesser;
  18. public function __construct(array $extensions = array())
  19. {
  20. foreach ($extensions as $extension) {
  21. $this->addExtension($extension);
  22. }
  23. }
  24. public function addExtension(FormExtensionInterface $extension)
  25. {
  26. $this->extensions[] = $extension;
  27. }
  28. private function loadGuesser()
  29. {
  30. $guessers = array();
  31. foreach ($this->extensions as $extension) {
  32. $guesser = $extension->getTypeGuesser();
  33. if ($guesser) {
  34. $guessers[] = $guesser;
  35. }
  36. }
  37. $this->guesser = new FormTypeGuesserChain($guessers);
  38. }
  39. public function getType($name)
  40. {
  41. $type = null;
  42. if ($name instanceof FormTypeInterface) {
  43. $type = $name;
  44. $name = $type->getName();
  45. }
  46. if (!isset($this->types[$name])) {
  47. if (!$type) {
  48. foreach ($this->extensions as $extension) {
  49. if ($extension->hasType($name)) {
  50. $type = $extension->getType($name);
  51. break;
  52. }
  53. }
  54. if (!$type) {
  55. throw new FormException(sprintf('Could not load type "%s"', $name));
  56. }
  57. }
  58. $typeExtensions = array();
  59. foreach ($this->extensions as $extension) {
  60. $typeExtensions = array_merge(
  61. $typeExtensions,
  62. $extension->getTypeExtensions($name)
  63. );
  64. }
  65. $type->setExtensions($typeExtensions);
  66. $this->types[$name] = $type;
  67. }
  68. return $this->types[$name];
  69. }
  70. public function create($type, $data = null, array $options = array())
  71. {
  72. return $this->createBuilder($type, $data, $options)->getForm();
  73. }
  74. public function createNamed($type, $name, $data = null, array $options = array())
  75. {
  76. return $this->createNamedBuilder($type, $name, $data, $options)->getForm();
  77. }
  78. /**
  79. * @inheritDoc
  80. */
  81. public function createForProperty($class, $property, $data = null, array $options = array())
  82. {
  83. return $this->createBuilderForProperty($class, $property, $data, $options)->getForm();
  84. }
  85. public function createBuilder($type, $data = null, array $options = array())
  86. {
  87. $name = is_object($type) ? $type->getName() : $type;
  88. return $this->createNamedBuilder($type, $name, $data, $options);
  89. }
  90. public function createNamedBuilder($type, $name, $data = null, array $options = array())
  91. {
  92. $builder = null;
  93. $types = array();
  94. $knownOptions = array();
  95. $passedOptions = array_keys($options);
  96. while (null !== $type) {
  97. $type = $this->getType($type);
  98. $defaultOptions = $type->getDefaultOptions($options);
  99. foreach ($type->getExtensions() as $typeExtension) {
  100. $defaultOptions = array_merge($defaultOptions, $typeExtension->getDefaultOptions($options));
  101. }
  102. $options = array_merge($defaultOptions, $options);
  103. $knownOptions = array_merge($knownOptions, array_keys($defaultOptions));
  104. array_unshift($types, $type);
  105. $type = $type->getParent($options);
  106. }
  107. $diff = array_diff($passedOptions, $knownOptions);
  108. if (count($diff) > 0) {
  109. throw new FormException(sprintf('The options "%s" do not exist', implode('", "', $diff)));
  110. }
  111. for ($i = 0, $l = count($types); $i < $l && !$builder; ++$i) {
  112. $builder = $types[$i]->createBuilder($name, $this, $options);
  113. }
  114. // TODO check if instance exists
  115. $builder->setTypes($types);
  116. foreach ($types as $type) {
  117. $type->buildForm($builder, $options);
  118. foreach ($type->getExtensions() as $typeExtension) {
  119. $typeExtension->buildForm($builder, $options);
  120. }
  121. }
  122. if (null !== $data) {
  123. $builder->setData($data);
  124. }
  125. return $builder;
  126. }
  127. public function createBuilderForProperty($class, $property, $data = null, array $options = array())
  128. {
  129. if (!$this->guesser) {
  130. $this->loadGuesser();
  131. }
  132. $typeGuess = $this->guesser->guessType($class, $property);
  133. $maxLengthGuess = $this->guesser->guessMaxLength($class, $property);
  134. $requiredGuess = $this->guesser->guessRequired($class, $property);
  135. $type = $typeGuess ? $typeGuess->getType() : 'text';
  136. if ($maxLengthGuess) {
  137. $options = array_merge(array('max_length' => $maxLengthGuess->getValue()), $options);
  138. }
  139. if ($requiredGuess) {
  140. $options = array_merge(array('required' => $requiredGuess->getValue()), $options);
  141. }
  142. // user options may override guessed options
  143. if ($typeGuess) {
  144. $options = array_merge($typeGuess->getOptions(), $options);
  145. }
  146. return $this->createNamedBuilder($type, $property, $data, $options);
  147. }
  148. }