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\Extension\Core\Type
;
14 use Symfony\Component\Form\FormBuilderInterface
;
15 use Symfony\Component\Form\FormInterface
;
16 use Symfony\Component\Form\FormView
;
17 use Symfony\Component\Form\Extension\Core\EventListener\TrimListener
;
18 use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper
;
19 use Symfony\Component\Form\Exception\LogicException
;
20 use Symfony\Component\OptionsResolver\Options
;
21 use Symfony\Component\OptionsResolver\OptionsResolverInterface
;
22 use Symfony\Component\PropertyAccess\PropertyAccess
;
23 use Symfony\Component\PropertyAccess\PropertyAccessorInterface
;
25 class FormType
extends BaseType
28 * @var PropertyAccessorInterface
30 private $propertyAccessor;
32 public function __construct(PropertyAccessorInterface
$propertyAccessor = null)
34 $this->propertyAccessor
= $propertyAccessor ?: PropertyAccess
::getPropertyAccessor();
40 public function buildForm(FormBuilderInterface
$builder, array $options)
42 parent
::buildForm($builder, $options);
45 ->setRequired($options['required'])
46 ->setErrorBubbling($options['error_bubbling'])
47 ->setEmptyData($options['empty_data'])
48 ->setPropertyPath($options['property_path'])
49 ->setMapped($options['mapped'])
50 ->setByReference($options['by_reference'])
51 ->setInheritData($options['inherit_data'])
52 ->setCompound($options['compound'])
53 ->setData(isset($options['data']) ? $options['data'] : null)
54 ->setDataLocked(isset($options['data']))
55 ->setDataMapper($options['compound'] ? new PropertyPathMapper($this->propertyAccessor
) : null)
56 ->setMethod($options['method'])
57 ->setAction($options['action'])
58 ->setAutoInitialize($options['auto_initialize'])
61 if ($options['trim']) {
62 $builder->addEventSubscriber(new TrimListener());
69 public function buildView(FormView
$view, FormInterface
$form, array $options)
71 parent
::buildView($view, $form, $options);
73 $name = $form->getName();
74 $readOnly = $options['read_only'];
78 throw new LogicException('Form node with empty name can be used only as root form node.');
81 // Complex fields are read-only if they themselves or their parents are.
83 $readOnly = $view->parent
->vars
['read_only'];
87 $view->vars
= array_replace($view->vars
, array(
88 'read_only' => $readOnly,
89 'errors' => $form->getErrors(),
90 'valid' => $form->isSubmitted() ? $form->isValid() : true,
91 'value' => $form->getViewData(),
92 'data' => $form->getNormData(),
93 'required' => $form->isRequired(),
94 'max_length' => $options['max_length'],
95 'pattern' => $options['pattern'],
97 'label_attr' => $options['label_attr'],
98 'compound' => $form->getConfig()->getCompound(),
99 'method' => $form->getConfig()->getMethod(),
100 'action' => $form->getConfig()->getAction(),
107 public function finishView(FormView
$view, FormInterface
$form, array $options)
111 foreach ($view->children
as $child) {
112 if ($child->vars
['multipart']) {
118 $view->vars
['multipart'] = $multipart;
124 public function setDefaultOptions(OptionsResolverInterface
$resolver)
126 parent
::setDefaultOptions($resolver);
128 // Derive "data_class" option from passed "data" object
129 $dataClass = function (Options
$options) {
130 return isset($options['data']) && is_object($options['data']) ? get_class($options['data']) : null;
133 // Derive "empty_data" closure from "data_class" option
134 $emptyData = function (Options
$options) {
135 $class = $options['data_class'];
137 if (null !== $class) {
138 return function (FormInterface
$form) use ($class) {
139 return $form->isEmpty() && !$form->isRequired() ? null : new $class();
143 return function (FormInterface
$form) {
144 return $form->getConfig()->getCompound() ? array() : '';
148 // For any form that is not represented by a single HTML control,
149 // errors should bubble up by default
150 $errorBubbling = function (Options
$options) {
151 return $options['compound'];
154 // BC with old "virtual" option
155 $inheritData = function (Options
$options) {
156 if (null !== $options['virtual']) {
157 // Uncomment this as soon as the deprecation note should be shown
158 // trigger_error('The form option "virtual" is deprecated since version 2.3 and will be removed in 3.0. Use "inherit_data" instead.', E_USER_DEPRECATED);
159 return $options['virtual'];
165 // If data is given, the form is locked to that data
166 // (independent of its value)
167 $resolver->setOptional(array(
171 $resolver->setDefaults(array(
172 'data_class' => $dataClass,
173 'empty_data' => $emptyData,
176 'read_only' => false,
177 'max_length' => null,
179 'property_path' => null,
181 'by_reference' => true,
182 'error_bubbling' => $errorBubbling,
183 'label_attr' => array(),
185 'inherit_data' => $inheritData,
188 // According to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt)
189 // section 4.2., empty URIs are considered same-document references
191 'auto_initialize' => true,
194 $resolver->setAllowedTypes(array(
195 'label_attr' => 'array',
202 public function getParent()
210 public function getName()