FormBuilder.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  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\DataMapper\DataMapperInterface;
  12. use Symfony\Component\Form\DataTransformer\DataTransformerInterface;
  13. use Symfony\Component\Form\Renderer\ThemeRenderer;
  14. use Symfony\Component\Form\Renderer\FormRendererInterface;
  15. use Symfony\Component\Form\Renderer\Plugin\FormRendererPluginInterface;
  16. use Symfony\Component\Form\Validator\FormValidatorInterface;
  17. use Symfony\Component\Form\Exception\FormException;
  18. use Symfony\Component\Form\Exception\UnexpectedTypeException;
  19. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  20. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  21. class FormBuilder
  22. {
  23. private $name;
  24. private $data;
  25. private $dispatcher;
  26. private $factory;
  27. private $readOnly;
  28. private $required;
  29. private $renderer;
  30. private $rendererVars = array();
  31. private $clientTransformer;
  32. private $normalizationTransformer;
  33. private $validators = array();
  34. private $attributes = array();
  35. private $types = array();
  36. private $parent;
  37. private $dataClass;
  38. private $fields = array();
  39. private $dataMapper;
  40. private $errorBubbling = false;
  41. public function __construct(EventDispatcherInterface $dispatcher)
  42. {
  43. $this->dispatcher = $dispatcher;
  44. }
  45. public function setFormFactory(FormFactoryInterface $factory)
  46. {
  47. $this->factory = $factory;
  48. return $this;
  49. }
  50. public function getFormFactory()
  51. {
  52. return $this->factory;
  53. }
  54. public function setName($name)
  55. {
  56. $this->name = $name;
  57. return $this;
  58. }
  59. public function getName()
  60. {
  61. return $this->name;
  62. }
  63. public function setParent(FormBuilder $builder)
  64. {
  65. $this->parent = $builder;
  66. return $this;
  67. }
  68. public function getParent()
  69. {
  70. return $this->parent;
  71. }
  72. public function end()
  73. {
  74. return $this->parent;
  75. }
  76. public function setData($data)
  77. {
  78. $this->data = $data;
  79. return $this;
  80. }
  81. public function getData()
  82. {
  83. return $this->data;
  84. }
  85. public function setReadOnly($readOnly)
  86. {
  87. $this->readOnly = $readOnly;
  88. return $this;
  89. }
  90. public function getReadOnly()
  91. {
  92. return $this->readOnly;
  93. }
  94. /**
  95. * Sets whether this field is required to be filled out when bound.
  96. *
  97. * @param Boolean $required
  98. */
  99. public function setRequired($required)
  100. {
  101. $this->required = $required;
  102. return $this;
  103. }
  104. public function getRequired()
  105. {
  106. return $this->required;
  107. }
  108. public function setErrorBubbling($errorBubbling)
  109. {
  110. $this->errorBubbling = $errorBubbling;
  111. return $this;
  112. }
  113. public function getErrorBubbling()
  114. {
  115. return $this->errorBubbling;
  116. }
  117. public function addValidator(FormValidatorInterface $validator)
  118. {
  119. $this->validators[] = $validator;
  120. return $this;
  121. }
  122. public function getValidators()
  123. {
  124. return $this->validators;
  125. }
  126. /**
  127. * Adds an event listener for events on this field
  128. *
  129. * @see Symfony\Component\EventDispatcher\EventDispatcherInterface::addEventListener
  130. */
  131. public function addEventListener($eventNames, $listener, $priority = 0)
  132. {
  133. $this->dispatcher->addListener($eventNames, $listener, $priority);
  134. return $this;
  135. }
  136. /**
  137. * Adds an event subscriber for events on this field
  138. *
  139. * @see Symfony\Component\EventDispatcher\EventDispatcherInterface::addEventSubscriber
  140. */
  141. public function addEventSubscriber(EventSubscriberInterface $subscriber, $priority = 0)
  142. {
  143. $this->dispatcher->addSubscriber($subscriber, $priority);
  144. return $this;
  145. }
  146. protected function buildDispatcher()
  147. {
  148. return $this->dispatcher;
  149. }
  150. /**
  151. * Sets the DataTransformer.
  152. *
  153. * @param DataTransformerInterface $clientTransformer
  154. */
  155. public function setNormTransformer(DataTransformerInterface $normalizationTransformer = null)
  156. {
  157. $this->normalizationTransformer = $normalizationTransformer;
  158. return $this;
  159. }
  160. public function getNormTransformer()
  161. {
  162. return $this->normalizationTransformer;
  163. }
  164. /**
  165. * Sets the DataTransformer.
  166. *
  167. * @param DataTransformerInterface $clientTransformer
  168. */
  169. public function setClientTransformer(DataTransformerInterface $clientTransformer = null)
  170. {
  171. $this->clientTransformer = $clientTransformer;
  172. return $this;
  173. }
  174. public function getClientTransformer()
  175. {
  176. return $this->clientTransformer;
  177. }
  178. /**
  179. * Sets the renderer
  180. *
  181. * @param FormRendererInterface $renderer
  182. */
  183. public function setRenderer(FormRendererInterface $renderer)
  184. {
  185. $this->renderer = $renderer;
  186. return $this;
  187. }
  188. public function addRendererPlugin(FormRendererPluginInterface $plugin)
  189. {
  190. $this->rendererVars[] = $plugin;
  191. return $this;
  192. }
  193. public function setRendererVar($name, $value)
  194. {
  195. $this->rendererVars[$name] = $value;
  196. return $this;
  197. }
  198. protected function buildRenderer()
  199. {
  200. foreach ($this->rendererVars as $name => $value) {
  201. if (!$this->renderer) {
  202. throw new FormException('A renderer must be set in order to add renderer variables or plugins');
  203. }
  204. if ($value instanceof FormRendererPluginInterface) {
  205. $this->renderer->addPlugin($value);
  206. continue;
  207. }
  208. $this->renderer->setVar($name, $value);
  209. }
  210. return $this->renderer;
  211. }
  212. public function setAttribute($name, $value)
  213. {
  214. $this->attributes[$name] = $value;
  215. return $this;
  216. }
  217. public function getAttribute($name)
  218. {
  219. return $this->attributes[$name];
  220. }
  221. public function hasAttribute($name)
  222. {
  223. return isset($this->attributes[$name]);
  224. }
  225. public function getAttributes()
  226. {
  227. return $this->attributes;
  228. }
  229. public function setDataMapper(DataMapperInterface $dataMapper)
  230. {
  231. $this->dataMapper = $dataMapper;
  232. }
  233. public function getDataMapper()
  234. {
  235. return $this->dataMapper;
  236. }
  237. public function setTypes(array $types)
  238. {
  239. $this->types = $types;
  240. return $this;
  241. }
  242. public function getTypes()
  243. {
  244. return $this->types;
  245. }
  246. /**
  247. * Adds a new field to this group. A field must have a unique name within
  248. * the group. Otherwise the existing field is overwritten.
  249. *
  250. * If you add a nested group, this group should also be represented in the
  251. * object hierarchy. If you want to add a group that operates on the same
  252. * hierarchy level, use merge().
  253. *
  254. * <code>
  255. * class Entity
  256. * {
  257. * public $location;
  258. * }
  259. *
  260. * class Location
  261. * {
  262. * public $longitude;
  263. * public $latitude;
  264. * }
  265. *
  266. * $entity = new Entity();
  267. * $entity->location = new Location();
  268. *
  269. * $form = new Form('entity', $entity, $validator);
  270. *
  271. * $locationGroup = new Form('location');
  272. * $locationGroup->add(new TextField('longitude'));
  273. * $locationGroup->add(new TextField('latitude'));
  274. *
  275. * $form->add($locationGroup);
  276. * </code>
  277. *
  278. * @param FormInterface|string $field
  279. * @return FormInterface
  280. */
  281. public function add($name, $type = null, array $options = array())
  282. {
  283. if (!is_string($name)) {
  284. throw new UnexpectedTypeException($name, 'string');
  285. }
  286. if (null !== $type && !is_string($type)) {
  287. throw new UnexpectedTypeException($type, 'string');
  288. }
  289. $this->fields[$name] = array(
  290. 'type' => $type,
  291. 'options' => $options,
  292. );
  293. return $this;
  294. }
  295. public function build($name, $type = null, array $options = array())
  296. {
  297. if (null !== $type) {
  298. $builder = $this->getFormFactory()->createBuilder(
  299. $type,
  300. $name,
  301. $options
  302. );
  303. } else {
  304. if (!$this->dataClass) {
  305. throw new FormException('The data class must be set to automatically create fields');
  306. }
  307. $builder = $this->getFormFactory()->createBuilderForProperty(
  308. $this->dataClass,
  309. $name,
  310. $options
  311. );
  312. }
  313. $this->fields[$name] = $builder;
  314. $builder->setParent($this);
  315. return $builder;
  316. }
  317. public function get($name)
  318. {
  319. if (!isset($this->fields[$name])) {
  320. throw new FormException(sprintf('The field "%s" does not exist', $name));
  321. }
  322. $field = $this->fields[$name];
  323. if ($field instanceof FormBuilder) {
  324. return $field;
  325. }
  326. return $this->build($name, $field['type'], $field['options']);
  327. }
  328. /**
  329. * Removes the field with the given name.
  330. *
  331. * @param string $name
  332. */
  333. public function remove($name)
  334. {
  335. if (isset($this->fields[$name])) {
  336. // field might still be lazy
  337. if ($this->fields[$name] instanceof FormInterface) {
  338. $this->fields[$name]->setParent(null);
  339. }
  340. unset($this->fields[$name]);
  341. }
  342. }
  343. /**
  344. * Returns whether a field with the given name exists.
  345. *
  346. * @param string $name
  347. * @return Boolean
  348. */
  349. public function has($name)
  350. {
  351. return isset($this->fields[$name]);
  352. }
  353. protected function buildChildren()
  354. {
  355. $fields = array();
  356. foreach ($this->fields as $name => $builder) {
  357. if (!$builder instanceof FormBuilder) {
  358. $builder = $this->build($name, $builder['type'], $builder['options']);
  359. }
  360. $fields[$builder->getName()] = $builder->getForm();
  361. }
  362. return $fields;
  363. }
  364. public function setDataClass($class)
  365. {
  366. $this->dataClass = $class;
  367. return $this;
  368. }
  369. public function getDataClass()
  370. {
  371. return $this->dataClass;
  372. }
  373. public function getForm()
  374. {
  375. $instance = new Form(
  376. $this->getName(),
  377. $this->getTypes(),
  378. $this->buildDispatcher(),
  379. $this->buildRenderer(),
  380. $this->getClientTransformer(),
  381. $this->getNormTransformer(),
  382. $this->getDataMapper(),
  383. $this->getValidators(),
  384. $this->getRequired(),
  385. $this->getReadOnly(),
  386. $this->getErrorBubbling(),
  387. $this->getAttributes()
  388. );
  389. foreach ($this->buildChildren() as $field) {
  390. $instance->add($field);
  391. }
  392. if ($this->getData()) {
  393. $instance->setData($this->getData());
  394. }
  395. return $instance;
  396. }
  397. }