4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Form
;
14 use Symfony\Component\Form\Exception\BadMethodCallException
;
15 use Symfony\Component\Form\Exception\InvalidArgumentException
;
16 use Symfony\Component\Form\Exception\UnexpectedTypeException
;
17 use Symfony\Component\EventDispatcher\EventDispatcherInterface
;
20 * A builder for creating {@link Form} instances.
22 * @author Bernhard Schussek <bschussek@gmail.com>
24 class FormBuilder
extends FormConfigBuilder
implements \IteratorAggregate
, FormBuilderInterface
27 * The children of the form builder.
29 * @var FormBuilderInterface[]
31 private $children = array();
34 * The data of children who haven't been converted to form builders yet.
38 private $unresolvedChildren = array();
41 * Creates a new form builder.
44 * @param string $dataClass
45 * @param EventDispatcherInterface $dispatcher
46 * @param FormFactoryInterface $factory
47 * @param array $options
49 public function __construct($name, $dataClass, EventDispatcherInterface
$dispatcher, FormFactoryInterface
$factory, array $options = array())
51 parent
::__construct($name, $dataClass, $dispatcher, $options);
53 $this->setFormFactory($factory);
59 public function add($child, $type = null, array $options = array())
62 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
65 if ($child instanceof self
) {
66 $this->children
[$child->getName()] = $child;
68 // In case an unresolved child with the same name exists
69 unset($this->unresolvedChildren
[$child->getName()]);
74 if (!is_string($child) && !is_int($child)) {
75 throw new UnexpectedTypeException($child, 'string, integer or Symfony\Component\Form\FormBuilder');
78 if (null !== $type && !is_string($type) && !$type instanceof FormTypeInterface
) {
79 throw new UnexpectedTypeException($type, 'string or Symfony\Component\Form\FormTypeInterface');
82 // Add to "children" to maintain order
83 $this->children
[$child] = null;
84 $this->unresolvedChildren
[$child] = array(
86 'options' => $options,
95 public function create($name, $type = null, array $options = array())
98 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
101 if (null === $type && null === $this->getDataClass()) {
105 if (null !== $type) {
106 return $this->getFormFactory()->createNamedBuilder($name, $type, null, $options);
109 return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, null, $options);
115 public function get($name)
118 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
121 if (isset($this->unresolvedChildren
[$name])) {
122 return $this->resolveChild($name);
125 if (isset($this->children
[$name])) {
126 return $this->children
[$name];
129 throw new InvalidArgumentException(sprintf('The child with the name "%s" does not exist.', $name));
135 public function remove($name)
138 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
141 unset($this->unresolvedChildren
[$name]);
143 if (array_key_exists($name, $this->children
)) {
144 unset($this->children
[$name]);
153 public function has($name)
156 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
159 if (isset($this->unresolvedChildren
[$name])) {
163 if (isset($this->children
[$name])) {
173 public function all()
176 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
179 $this->resolveChildren();
181 return $this->children
;
187 public function count()
190 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
193 return count($this->children
);
199 public function getFormConfig()
201 $config = parent
::getFormConfig();
203 $config->children
= array();
204 $config->unresolvedChildren
= array();
212 public function getForm()
215 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
218 $this->resolveChildren();
220 $form = new Form($this->getFormConfig());
222 foreach ($this->children
as $child) {
223 // Automatic initialization is only supported on root forms
224 $form->add($child->setAutoInitialize(false)->getForm());
227 if ($this->getAutoInitialize()) {
228 // Automatically initialize the form if it is configured so
238 public function getIterator()
241 throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
244 return new \
ArrayIterator($this->children
);
248 * Converts an unresolved child into a {@link FormBuilder} instance.
250 * @param string $name The name of the unresolved child.
252 * @return FormBuilder The created instance.
254 private function resolveChild($name)
256 $info = $this->unresolvedChildren
[$name];
257 $child = $this->create($name, $info['type'], $info['options']);
258 $this->children
[$name] = $child;
259 unset($this->unresolvedChildren
[$name]);
265 * Converts all unresolved children into {@link FormBuilder} instances.
267 private function resolveChildren()
269 foreach ($this->unresolvedChildren
as $name => $info) {
270 $this->children
[$name] = $this->create($name, $info['type'], $info['options']);
273 $this->unresolvedChildren
= array();