[Form] Options are now passed to buildView() and buildViewBottomUp()

This commit is contained in:
Bernhard Schussek 2012-05-23 18:47:14 +02:00
parent 027259eba4
commit 0ef4066983
35 changed files with 379 additions and 355 deletions

View File

@ -488,6 +488,8 @@
* `getErrorBubbling` * `getErrorBubbling`
* `getNormTransformers` * `getNormTransformers`
* `getClientTransformers` * `getClientTransformers`
* `getAttribute`
* `hasAttribute`
You can access these methods on the `FormConfigInterface` object instead. You can access these methods on the `FormConfigInterface` object instead.
@ -609,6 +611,24 @@
The second argument `$value` contains the current default value and The second argument `$value` contains the current default value and
does not have to be specified if not needed. does not have to be specified if not needed.
* A third argument $options was added to the methods `buildView()` and
`buildViewBottomUp()` in `FormTypeInterface` and `FormTypeExtensionInterface`.
You should adapt your implementing classes.
Before:
```
public function buildView(FormView $view, FormInterface $form)
public function buildViewBottomUp(FormView $view, FormInterface $form)
```
After:
```
public function buildView(FormView $view, FormInterface $form, array $options)
public function buildViewBottomUp(FormView $view, FormInterface $form, array $options)
```
### Validator ### Validator
* The methods `setMessage()`, `getMessageTemplate()` and * The methods `setMessage()`, `getMessageTemplate()` and

View File

@ -35,14 +35,14 @@ abstract class AbstractType implements FormTypeInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildView(FormView $view, FormInterface $form) public function buildView(FormView $view, FormInterface $form, array $options)
{ {
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildViewBottomUp(FormView $view, FormInterface $form) public function buildViewBottomUp(FormView $view, FormInterface $form, array $options)
{ {
} }

View File

@ -28,14 +28,14 @@ abstract class AbstractTypeExtension implements FormTypeExtensionInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildView(FormView $view, FormInterface $form) public function buildView(FormView $view, FormInterface $form, array $options)
{ {
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildViewBottomUp(FormView $view, FormInterface $form) public function buildViewBottomUp(FormView $view, FormInterface $form, array $options)
{ {
} }

View File

@ -81,6 +81,8 @@ CHANGELOG
* `getErrorBubbling` * `getErrorBubbling`
* `getNormTransformers` * `getNormTransformers`
* `getClientTransformers` * `getClientTransformers`
* `getAttribute`
* `hasAttribute`
* deprecated the option "validation_constraint" in favor of the new * deprecated the option "validation_constraint" in favor of the new
option "constraints" option "constraints"
* removed superfluous methods from DataMapperInterface * removed superfluous methods from DataMapperInterface
@ -92,3 +94,9 @@ CHANGELOG
which accepts an OptionsResolver instance which accepts an OptionsResolver instance
* deprecated the methods `getDefaultOptions` and `getAllowedOptionValues` * deprecated the methods `getDefaultOptions` and `getAllowedOptionValues`
in FormTypeInterface and FormTypeExtensionInterface in FormTypeInterface and FormTypeExtensionInterface
* options passed during construction can now be accessed from FormConfigInterface
* [BC BREAK] the options array is now passed as last argument of the
methods
* `buildView`
* `buildViewBottomUp`
in FormTypeInterface and FormTypeExtensionInterface

View File

@ -27,17 +27,16 @@ class CheckboxType extends AbstractType
{ {
$builder $builder
->appendClientTransformer(new BooleanToStringTransformer($options['value'])) ->appendClientTransformer(new BooleanToStringTransformer($options['value']))
->setAttribute('value', $options['value'])
; ;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildView(FormView $view, FormInterface $form) public function buildView(FormView $view, FormInterface $form, array $options)
{ {
$view $view
->set('value', $form->getAttribute('value')) ->set('value', $options['value'])
->set('checked', null !== $form->getClientData()) ->set('checked', null !== $form->getClientData())
; ;
} }

View File

@ -36,10 +36,6 @@ class ChoiceType extends AbstractType
*/ */
public function buildForm(FormBuilder $builder, array $options) public function buildForm(FormBuilder $builder, array $options)
{ {
if ($options['choice_list'] && !$options['choice_list'] instanceof ChoiceListInterface) {
throw new FormException('The "choice_list" must be an instance of "Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface".');
}
if (!$options['choice_list'] && !is_array($options['choices']) && !$options['choices'] instanceof \Traversable) { if (!$options['choice_list'] && !is_array($options['choices']) && !$options['choices'] instanceof \Traversable) {
throw new FormException('Either the option "choices" or "choice_list" must be set.'); throw new FormException('Either the option "choices" or "choice_list" must be set.');
} }
@ -47,30 +43,7 @@ class ChoiceType extends AbstractType
if ($options['expanded']) { if ($options['expanded']) {
$this->addSubForms($builder, $options['choice_list']->getPreferredViews(), $options); $this->addSubForms($builder, $options['choice_list']->getPreferredViews(), $options);
$this->addSubForms($builder, $options['choice_list']->getRemainingViews(), $options); $this->addSubForms($builder, $options['choice_list']->getRemainingViews(), $options);
}
// empty value
if ($options['multiple'] || $options['expanded']) {
// never use and empty value for these cases
$emptyValue = null;
} elseif (false === $options['empty_value']) {
// an empty value should be added but the user decided otherwise
$emptyValue = null;
} else {
// empty value has been set explicitly
$emptyValue = $options['empty_value'];
}
$builder
->setAttribute('choice_list', $options['choice_list'])
->setAttribute('preferred_choices', $options['preferred_choices'])
->setAttribute('multiple', $options['multiple'])
->setAttribute('expanded', $options['expanded'])
->setAttribute('required', $options['required'])
->setAttribute('empty_value', $emptyValue)
;
if ($options['expanded']) {
if ($options['multiple']) { if ($options['multiple']) {
$builder $builder
->appendClientTransformer(new ChoicesToBooleanArrayTransformer($options['choice_list'])) ->appendClientTransformer(new ChoicesToBooleanArrayTransformer($options['choice_list']))
@ -100,20 +73,18 @@ class ChoiceType extends AbstractType
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildView(FormView $view, FormInterface $form) public function buildView(FormView $view, FormInterface $form, array $options)
{ {
$choiceList = $form->getAttribute('choice_list');
$view $view
->set('multiple', $form->getAttribute('multiple')) ->set('multiple', $options['multiple'])
->set('expanded', $form->getAttribute('expanded')) ->set('expanded', $options['expanded'])
->set('preferred_choices', $choiceList->getPreferredViews()) ->set('preferred_choices', $options['choice_list']->getPreferredViews())
->set('choices', $choiceList->getRemainingViews()) ->set('choices', $options['choice_list']->getRemainingViews())
->set('separator', '-------------------') ->set('separator', '-------------------')
->set('empty_value', $form->getAttribute('empty_value')) ->set('empty_value', $options['empty_value'])
; ;
if ($view->get('multiple') && !$view->get('expanded')) { if ($options['multiple'] && !$options['expanded']) {
// Add "[]" to the name in case a select tag with multiple options is // Add "[]" to the name in case a select tag with multiple options is
// displayed. Otherwise only one of the selected options is sent in the // displayed. Otherwise only one of the selected options is sent in the
// POST request. // POST request.
@ -124,14 +95,14 @@ class ChoiceType extends AbstractType
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildViewBottomUp(FormView $view, FormInterface $form) public function buildViewBottomUp(FormView $view, FormInterface $form, array $options)
{ {
if ($view->get('expanded')) { if ($options['expanded']) {
// Radio buttons should have the same name as the parent // Radio buttons should have the same name as the parent
$childName = $view->get('full_name'); $childName = $view->get('full_name');
// Checkboxes should append "[]" to allow multiple selection // Checkboxes should append "[]" to allow multiple selection
if ($view->get('multiple')) { if ($options['multiple']) {
$childName .= '[]'; $childName .= '[]';
} }
@ -166,6 +137,19 @@ class ChoiceType extends AbstractType
return $options['required'] ? null : ''; return $options['required'] ? null : '';
}; };
$emptyValueFilter = function (Options $options, $emptyValue) {
if ($options['multiple'] || $options['expanded']) {
// never use an empty value for these cases
return null;
} elseif (false === $emptyValue) {
// an empty value should be added but the user decided otherwise
return null;
}
// empty value has been set explicitly
return $emptyValue;
};
$singleControl = function (Options $options) { $singleControl = function (Options $options) {
return !$options['expanded']; return !$options['expanded'];
}; };
@ -181,6 +165,14 @@ class ChoiceType extends AbstractType
'error_bubbling' => false, 'error_bubbling' => false,
'single_control' => $singleControl, 'single_control' => $singleControl,
)); ));
$resolver->setFilters(array(
'empty_value' => $emptyValueFilter,
));
$resolver->setAllowedTypes(array(
'choice_list' => array('null', 'Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface'),
));
} }
/** /**

View File

@ -40,34 +40,30 @@ class CollectionType extends AbstractType
$options['allow_delete'] $options['allow_delete']
); );
$builder $builder->addEventSubscriber($resizeListener);
->addEventSubscriber($resizeListener)
->setAttribute('allow_add', $options['allow_add'])
->setAttribute('allow_delete', $options['allow_delete'])
;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildView(FormView $view, FormInterface $form) public function buildView(FormView $view, FormInterface $form, array $options)
{ {
$view $view
->set('allow_add', $form->getAttribute('allow_add')) ->set('allow_add', $options['allow_add'])
->set('allow_delete', $form->getAttribute('allow_delete')) ->set('allow_delete', $options['allow_delete'])
; ;
if ($form->hasAttribute('prototype')) { if ($form->getConfig()->hasAttribute('prototype')) {
$view->set('prototype', $form->getAttribute('prototype')->createView($view)); $view->set('prototype', $form->getConfig()->getAttribute('prototype')->createView($view));
} }
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildViewBottomUp(FormView $view, FormInterface $form) public function buildViewBottomUp(FormView $view, FormInterface $form, array $options)
{ {
if ($form->hasAttribute('prototype') && $view->get('prototype')->get('multipart')) { if ($form->getConfig()->hasAttribute('prototype') && $view->get('prototype')->get('multipart')) {
$view->set('multipart', true); $view->set('multipart', true);
} }
} }

View File

@ -111,18 +111,16 @@ class DateTimeType extends AbstractType
new DateTimeToArrayTransformer($options['data_timezone'], $options['data_timezone'], $parts) new DateTimeToArrayTransformer($options['data_timezone'], $options['data_timezone'], $parts)
)); ));
} }
$builder->setAttribute('widget', $options['widget']);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildView(FormView $view, FormInterface $form) public function buildView(FormView $view, FormInterface $form, array $options)
{ {
$view->set('widget', $form->getAttribute('widget')); $view->set('widget', $options['widget']);
if ('single_text' === $form->getAttribute('widget')) { if ('single_text' === $options['widget']) {
$view->set('type', 'datetime'); $view->set('type', 'datetime');
} }
} }

View File

@ -130,24 +130,22 @@ class DateType extends AbstractType
)); ));
} }
$builder $builder->setAttribute('formatter', $formatter);
->setAttribute('formatter', $formatter)
->setAttribute('widget', $options['widget']);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildViewBottomUp(FormView $view, FormInterface $form) public function buildViewBottomUp(FormView $view, FormInterface $form, array $options)
{ {
$view->set('widget', $form->getAttribute('widget')); $view->set('widget', $options['widget']);
if ('single_text' === $form->getAttribute('widget')) { if ('single_text' === $options['widget']) {
$view->set('type', 'date'); $view->set('type', 'date');
} }
if ($view->hasChildren()) { if ($view->hasChildren()) {
$pattern = $form->getAttribute('formatter')->getPattern(); $pattern = $form->getConfig()->getAttribute('formatter')->getPattern();
// set right order with respect to locale (e.g.: de_DE=dd.MM.yy; en_US=M/d/yy) // set right order with respect to locale (e.g.: de_DE=dd.MM.yy; en_US=M/d/yy)
// lookup various formats at http://userguide.icu-project.org/formatparse/datetime // lookup various formats at http://userguide.icu-project.org/formatparse/datetime

View File

@ -21,7 +21,7 @@ class FileType extends AbstractType
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildView(FormView $view, FormInterface $form) public function buildView(FormView $view, FormInterface $form, array $options)
{ {
$view $view
->set('type', 'file') ->set('type', 'file')
@ -32,7 +32,7 @@ class FileType extends AbstractType
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildViewBottomUp(FormView $view, FormInterface $form) public function buildViewBottomUp(FormView $view, FormInterface $form, array $options)
{ {
$view $view
->set('multipart', true) ->set('multipart', true)

View File

@ -31,14 +31,6 @@ class FormType extends AbstractType
*/ */
public function buildForm(FormBuilder $builder, array $options) public function buildForm(FormBuilder $builder, array $options)
{ {
if (!is_array($options['attr'])) {
throw new FormException('The "attr" option must be an "array".');
}
if (!is_array($options['label_attr'])) {
throw new FormException('The "label_attr" option must be an "array".');
}
$builder $builder
->setRequired($options['required']) ->setRequired($options['required'])
->setDisabled($options['disabled']) ->setDisabled($options['disabled'])
@ -49,14 +41,6 @@ class FormType extends AbstractType
->setMapped($options['mapped']) ->setMapped($options['mapped'])
->setByReference($options['by_reference']) ->setByReference($options['by_reference'])
->setVirtual($options['virtual']) ->setVirtual($options['virtual'])
->setAttribute('read_only', $options['read_only'])
->setAttribute('max_length', $options['max_length'])
->setAttribute('pattern', $options['pattern'])
->setAttribute('label', $options['label'] ?: $this->humanize($builder->getName()))
->setAttribute('attr', $options['attr'])
->setAttribute('label_attr', $options['label_attr'])
->setAttribute('translation_domain', $options['translation_domain'])
->setAttribute('single_control', $options['single_control'])
->setData($options['data']) ->setData($options['data'])
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new PropertyPathMapper())
; ;
@ -69,10 +53,10 @@ class FormType extends AbstractType
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildView(FormView $view, FormInterface $form) public function buildView(FormView $view, FormInterface $form, array $options)
{ {
$name = $form->getName(); $name = $form->getName();
$readOnly = $form->getAttribute('read_only'); $readOnly = $options['read_only'];
if ($view->hasParent()) { if ($view->hasParent()) {
if ('' === $name) { if ('' === $name) {
@ -115,23 +99,23 @@ class FormType extends AbstractType
->set('value', $form->getClientData()) ->set('value', $form->getClientData())
->set('disabled', $form->isDisabled()) ->set('disabled', $form->isDisabled())
->set('required', $form->isRequired()) ->set('required', $form->isRequired())
->set('max_length', $form->getAttribute('max_length')) ->set('max_length', $options['max_length'])
->set('pattern', $form->getAttribute('pattern')) ->set('pattern', $options['pattern'])
->set('size', null) ->set('size', null)
->set('label', $form->getAttribute('label')) ->set('label', $options['label'] ?: $this->humanize($form->getName()))
->set('multipart', false) ->set('multipart', false)
->set('attr', $form->getAttribute('attr')) ->set('attr', $options['attr'])
->set('label_attr', $form->getAttribute('label_attr')) ->set('label_attr', $options['label_attr'])
->set('single_control', $form->getAttribute('single_control')) ->set('single_control', $options['single_control'])
->set('types', $types) ->set('types', $types)
->set('translation_domain', $form->getAttribute('translation_domain')) ->set('translation_domain', $options['translation_domain'])
; ;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildViewBottomUp(FormView $view, FormInterface $form) public function buildViewBottomUp(FormView $view, FormInterface $form, array $options)
{ {
$multipart = false; $multipart = false;
@ -214,6 +198,11 @@ class FormType extends AbstractType
'single_control' => false, 'single_control' => false,
'translation_domain' => 'messages', 'translation_domain' => 'messages',
)); ));
$resolver->setAllowedTypes(array(
'attr' => 'array',
'label_attr' => 'array',
));
} }
/** /**
@ -221,7 +210,7 @@ class FormType extends AbstractType
*/ */
public function createBuilder($name, FormFactoryInterface $factory, array $options) public function createBuilder($name, FormFactoryInterface $factory, array $options)
{ {
return new FormBuilder($name, $options['data_class'], new EventDispatcher(), $factory); return new FormBuilder($name, $options['data_class'], new EventDispatcher(), $factory, $options);
} }
/** /**

View File

@ -34,16 +34,15 @@ class MoneyType extends AbstractType
null, null,
$options['divisor'] $options['divisor']
)) ))
->setAttribute('currency', $options['currency'])
; ;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildView(FormView $view, FormInterface $form) public function buildView(FormView $view, FormInterface $form, array $options)
{ {
$view->set('money_pattern', self::getPattern($form->getAttribute('currency'))); $view->set('money_pattern', self::getPattern($options['currency']));
} }
/** /**

View File

@ -22,17 +22,9 @@ class PasswordType extends AbstractType
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildForm(FormBuilder $builder, array $options) public function buildView(FormView $view, FormInterface $form, array $options)
{ {
$builder->setAttribute('always_empty', $options['always_empty']); if ($options['always_empty'] || !$form->isBound()) {
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form)
{
if ($form->getAttribute('always_empty') || !$form->isBound()) {
$view->set('value', ''); $view->set('value', '');
} }
} }

View File

@ -20,7 +20,7 @@ class TextareaType extends AbstractType
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildView(FormView $view, FormInterface $form) public function buildView(FormView $view, FormInterface $form, array $options)
{ {
$view->set('pattern', null); $view->set('pattern', null);
} }

View File

@ -42,12 +42,6 @@ class TimeType extends AbstractType
$hourOptions = $minuteOptions = $secondOptions = array(); $hourOptions = $minuteOptions = $secondOptions = array();
if ('choice' === $options['widget']) { if ('choice' === $options['widget']) {
if (is_array($options['empty_value'])) {
$options['empty_value'] = array_merge(array('hour' => null, 'minute' => null, 'second' => null), $options['empty_value']);
} else {
$options['empty_value'] = array('hour' => $options['empty_value'], 'minute' => $options['empty_value'], 'second' => $options['empty_value']);
}
$hours = $minutes = array(); $hours = $minutes = array();
foreach ($options['hours'] as $hour) { foreach ($options['hours'] as $hour) {
@ -114,24 +108,19 @@ class TimeType extends AbstractType
new DateTimeToArrayTransformer($options['data_timezone'], $options['data_timezone'], $parts) new DateTimeToArrayTransformer($options['data_timezone'], $options['data_timezone'], $parts)
)); ));
} }
$builder
->setAttribute('widget', $options['widget'])
->setAttribute('with_seconds', $options['with_seconds'])
;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildView(FormView $view, FormInterface $form) public function buildView(FormView $view, FormInterface $form, array $options)
{ {
$view $view
->set('widget', $form->getAttribute('widget')) ->set('widget', $options['widget'])
->set('with_seconds', $form->getAttribute('with_seconds')) ->set('with_seconds', $options['with_seconds'])
; ;
if ('single_text' === $form->getAttribute('widget')) { if ('single_text' === $options['widget']) {
$view->set('type', 'time'); $view->set('type', 'time');
} }
} }
@ -145,6 +134,21 @@ class TimeType extends AbstractType
return $options['widget'] === 'single_text'; return $options['widget'] === 'single_text';
}; };
$emptyValueFilter = function (Options $options, $emptyValue) {
if (is_array($emptyValue)) {
return array_merge(
array('hour' => null, 'minute' => null, 'second' => null),
$emptyValue
);
}
return array(
'hour' => $emptyValue,
'minute' => $emptyValue,
'second' => $emptyValue
);
};
$resolver->setDefaults(array( $resolver->setDefaults(array(
'hours' => range(0, 23), 'hours' => range(0, 23),
'minutes' => range(0, 59), 'minutes' => range(0, 59),
@ -167,6 +171,10 @@ class TimeType extends AbstractType
'single_control' => $singleControl, 'single_control' => $singleControl,
)); ));
$resolver->setFilters(array(
'empty_value' => $emptyValueFilter,
));
$resolver->setAllowedValues(array( $resolver->setAllowedValues(array(
'input' => array( 'input' => array(
'datetime', 'datetime',

View File

@ -63,7 +63,7 @@ class CsrfValidationListener implements EventSubscriberInterface
$form = $event->getForm(); $form = $event->getForm();
$data = $event->getData(); $data = $event->getData();
if ($form->isRoot() && !$form->getAttribute('single_control')) { if ($form->isRoot() && !$form->getConfig()->getOption('single_control')) {
if (!isset($data[$this->fieldName]) || !$this->csrfProvider->isCsrfTokenValid($this->intention, $data[$this->fieldName])) { if (!isset($data[$this->fieldName]) || !$this->csrfProvider->isCsrfTokenValid($this->intention, $data[$this->fieldName])) {
$form->addError(new FormError('The CSRF token is invalid. Please try to resubmit the form')); $form->addError(new FormError('The CSRF token is invalid. Please try to resubmit the form'));
} }

View File

@ -47,11 +47,7 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
return; return;
} }
// use a low priority so higher priority listeners don't remove the field
$builder $builder
->setAttribute('csrf_field_name', $options['csrf_field_name'])
->setAttribute('csrf_provider', $options['csrf_provider'])
->setAttribute('csrf_intention', $options['intention'])
->setAttribute('csrf_factory', $builder->getFormFactory()) ->setAttribute('csrf_factory', $builder->getFormFactory())
->addEventSubscriber(new CsrfValidationListener($options['csrf_field_name'], $options['csrf_provider'], $options['intention'])) ->addEventSubscriber(new CsrfValidationListener($options['csrf_field_name'], $options['csrf_provider'], $options['intention']))
; ;
@ -63,15 +59,13 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
* @param FormView $view The form view * @param FormView $view The form view
* @param FormInterface $form The form * @param FormInterface $form The form
*/ */
public function buildViewBottomUp(FormView $view, FormInterface $form) public function buildViewBottomUp(FormView $view, FormInterface $form, array $options)
{ {
if (!$view->hasParent() && !$form->getAttribute('single_control') && $form->hasAttribute('csrf_field_name')) { if ($options['csrf_protection'] && !$view->hasParent() && !$options['single_control']) {
$name = $form->getAttribute('csrf_field_name'); $factory = $form->getConfig()->getAttribute('csrf_factory');
$csrfProvider = $form->getAttribute('csrf_provider'); $data = $options['csrf_provider']->generateCsrfToken($options['intention']);
$intention = $form->getAttribute('csrf_intention');
$factory = $form->getAttribute('csrf_factory'); $csrfForm = $factory->createNamed('hidden', $options['csrf_field_name'], $data, array(
$data = $csrfProvider->generateCsrfToken($intention);
$csrfForm = $factory->createNamed('hidden', $name, $data, array(
'property_path' => false, 'property_path' => false,
)); ));

View File

@ -55,6 +55,7 @@ class FormValidator extends ConstraintValidator
$path = $this->context->getPropertyPath(); $path = $this->context->getPropertyPath();
$graphWalker = $this->context->getGraphWalker(); $graphWalker = $this->context->getGraphWalker();
$groups = $this->getValidationGroups($form); $groups = $this->getValidationGroups($form);
$config = $form->getConfig();
if (!empty($path)) { if (!empty($path)) {
$path .= '.'; $path .= '.';
@ -72,7 +73,7 @@ class FormValidator extends ConstraintValidator
// Validate the data against the constraints defined // Validate the data against the constraints defined
// in the form // in the form
$constraints = $form->getAttribute('constraints'); $constraints = $config->getOption('constraints');
foreach ($constraints as $constraint) { foreach ($constraints as $constraint) {
foreach ($groups as $group) { foreach ($groups as $group) {
$graphWalker->walkConstraint($constraint, $form->getData(), $group, $path . 'data'); $graphWalker->walkConstraint($constraint, $form->getData(), $group, $path . 'data');
@ -85,7 +86,7 @@ class FormValidator extends ConstraintValidator
// Mark the form with an error if it is not synchronized // Mark the form with an error if it is not synchronized
$this->context->addViolation( $this->context->addViolation(
$form->getAttribute('invalid_message'), $config->getOption('invalid_message'),
array('{{ value }}' => $clientDataAsString), array('{{ value }}' => $clientDataAsString),
$form->getClientData(), $form->getClientData(),
null, null,
@ -96,7 +97,7 @@ class FormValidator extends ConstraintValidator
// Mark the form with an error if it contains extra fields // Mark the form with an error if it contains extra fields
if (count($form->getExtraData()) > 0) { if (count($form->getExtraData()) > 0) {
$this->context->addViolation( $this->context->addViolation(
$form->getAttribute('extra_fields_message'), $config->getOption('extra_fields_message'),
array('{{ extra_fields }}' => implode('", "', array_keys($form->getExtraData()))), array('{{ extra_fields }}' => implode('", "', array_keys($form->getExtraData()))),
$form->getExtraData() $form->getExtraData()
); );
@ -126,7 +127,7 @@ class FormValidator extends ConstraintValidator
if ($length > $maxLength) { if ($length > $maxLength) {
$this->context->addViolation( $this->context->addViolation(
$form->getAttribute('post_max_size_message'), $config->getOption('post_max_size_message'),
array('{{ max }}' => $max), array('{{ max }}' => $max),
$length $length
); );
@ -161,7 +162,7 @@ class FormValidator extends ConstraintValidator
$parent = $form->getParent(); $parent = $form->getParent();
while (null !== $parent) { while (null !== $parent) {
if (!$parent->getAttribute('cascade_validation')) { if (!$parent->getConfig()->getOption('cascade_validation')) {
return false; return false;
} }
@ -182,29 +183,18 @@ class FormValidator extends ConstraintValidator
{ {
$groups = null; $groups = null;
if ($form->hasAttribute('validation_groups')) { while (null !== $form && null === $groups) {
$groups = $form->getAttribute('validation_groups'); $groups = $form->getConfig()->getOption('validation_groups');
if (is_callable($groups)) { if (is_callable($groups)) {
$groups = (array) call_user_func($groups, $form); $groups = (array) call_user_func($groups, $form);
} }
}
$currentForm = $form; $form = $form->getParent();
while (!$groups && $currentForm->hasParent()) {
$currentForm = $currentForm->getParent();
if ($currentForm->hasAttribute('validation_groups')) {
$groups = $currentForm->getAttribute('validation_groups');
if (is_callable($groups)) {
$groups = (array) call_user_func($groups, $currentForm);
}
}
} }
if (null === $groups) { if (null === $groups) {
$groups = array('Default'); $groups = array(Constraint::DEFAULT_GROUP);
} }
return (array) $groups; return (array) $groups;

View File

@ -45,29 +45,7 @@ class FormTypeValidatorExtension extends AbstractTypeExtension
*/ */
public function buildForm(FormBuilder $builder, array $options) public function buildForm(FormBuilder $builder, array $options)
{ {
if (empty($options['validation_groups'])) { $builder->addEventSubscriber(new ValidationListener($this->validator, $this->violationMapper));
$options['validation_groups'] = null;
} else {
$options['validation_groups'] = is_callable($options['validation_groups'])
? $options['validation_groups']
: (array) $options['validation_groups'];
}
// Objects, when casted to an array, are split into their properties
$constraints = is_object($options['constraints'])
? array($options['constraints'])
: (array) $options['constraints'];
$builder
->setAttribute('error_mapping', $options['error_mapping'])
->setAttribute('validation_groups', $options['validation_groups'])
->setAttribute('constraints', $constraints)
->setAttribute('cascade_validation', $options['cascade_validation'])
->setAttribute('invalid_message', $options['invalid_message'])
->setAttribute('extra_fields_message', $options['extra_fields_message'])
->setAttribute('post_max_size_message', $options['post_max_size_message'])
->addEventSubscriber(new ValidationListener($this->validator, $this->violationMapper))
;
} }
/** /**
@ -80,6 +58,22 @@ class FormTypeValidatorExtension extends AbstractTypeExtension
return $options['validation_constraint']; return $options['validation_constraint'];
}; };
// Make sure that validation groups end up as null, closure or array
$validationGroupsFilter = function (Options $options, $groups) {
if (empty($groups)) {
return null;
} elseif (is_callable($groups)) {
return $groups;
}
return (array) $groups;
};
// Constraint should always be converted to an array
$constraintsFilter = function (Options $options, $constraints) {
return is_object($constraints) ? array($constraints) : (array) $constraints;
};
$resolver->setDefaults(array( $resolver->setDefaults(array(
'error_mapping' => array(), 'error_mapping' => array(),
'validation_groups' => null, 'validation_groups' => null,
@ -91,6 +85,11 @@ class FormTypeValidatorExtension extends AbstractTypeExtension
'extra_fields_message' => 'This form should not contain extra fields.', 'extra_fields_message' => 'This form should not contain extra fields.',
'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.', 'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
)); ));
$resolver->setFilters(array(
'validation_groups' => $validationGroupsFilter,
'constraints' => $constraintsFilter,
));
} }
/** /**

View File

@ -109,12 +109,12 @@ class ViolationMapper implements ViolationMapperInterface
} }
// Follow dot rules until we have the final target // Follow dot rules until we have the final target
$mapping = $this->scope->getAttribute('error_mapping'); $mapping = $this->scope->getConfig()->getAttribute('error_mapping');
while ($this->isValidScope() && isset($mapping['.'])) { while ($this->isValidScope() && isset($mapping['.'])) {
$dotRule = new MappingRule($this->scope, '.', $mapping['.']); $dotRule = new MappingRule($this->scope, '.', $mapping['.']);
$this->scope = $dotRule->getTarget(); $this->scope = $dotRule->getTarget();
$mapping = $this->scope->getAttribute('error_mapping'); $mapping = $this->scope->getConfig()->getAttribute('error_mapping');
} }
// Only add the error if the form is synchronized // Only add the error if the form is synchronized
@ -281,7 +281,7 @@ class ViolationMapper implements ViolationMapperInterface
$this->children = new \RecursiveIteratorIterator( $this->children = new \RecursiveIteratorIterator(
new VirtualFormAwareIterator($form->getChildren()) new VirtualFormAwareIterator($form->getChildren())
); );
foreach ($form->getAttribute('error_mapping') as $propertyPath => $targetPath) { foreach ($form->getConfig()->getAttribute('error_mapping') as $propertyPath => $targetPath) {
// Dot rules are considered at the very end // Dot rules are considered at the very end
if ('.' !== $propertyPath) { if ('.' !== $propertyPath) {
$this->rules[] = new MappingRule($form, $propertyPath, $targetPath); $this->rules[] = new MappingRule($form, $propertyPath, $targetPath);

View File

@ -288,6 +288,9 @@ class Form implements \IteratorAggregate, FormInterface
* @param string $name The name of the attribute. * @param string $name The name of the attribute.
* *
* @return Boolean Whether the attribute exists. * @return Boolean Whether the attribute exists.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getConfig()} and {@link FormConfigInterface::hasAttribute()} instead.
*/ */
public function hasAttribute($name) public function hasAttribute($name)
{ {
@ -300,6 +303,9 @@ class Form implements \IteratorAggregate, FormInterface
* @param string $name The name of the attribute * @param string $name The name of the attribute
* *
* @return mixed The attribute value. * @return mixed The attribute value.
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getConfig()} and {@link FormConfigInterface::getAttribute()} instead.
*/ */
public function getAttribute($name) public function getAttribute($name)
{ {
@ -936,12 +942,13 @@ class Form implements \IteratorAggregate, FormInterface
$view->setParent($parent); $view->setParent($parent);
$types = (array) $this->config->getTypes(); $types = (array) $this->config->getTypes();
$options = $this->config->getOptions();
foreach ($types as $type) { foreach ($types as $type) {
$type->buildView($view, $this); $type->buildView($view, $this, $options);
foreach ($type->getExtensions() as $typeExtension) { foreach ($type->getExtensions() as $typeExtension) {
$typeExtension->buildView($view, $this); $typeExtension->buildView($view, $this, $options);
} }
} }
@ -950,10 +957,10 @@ class Form implements \IteratorAggregate, FormInterface
} }
foreach ($types as $type) { foreach ($types as $type) {
$type->buildViewBottomUp($view, $this); $type->buildViewBottomUp($view, $this, $options);
foreach ($type->getExtensions() as $typeExtension) { foreach ($type->getExtensions() as $typeExtension) {
$typeExtension->buildViewBottomUp($view, $this); $typeExtension->buildViewBottomUp($view, $this, $options);
} }
} }

View File

@ -61,9 +61,9 @@ class FormBuilder extends FormConfig
* @param EventDispatcherInterface $dispatcher * @param EventDispatcherInterface $dispatcher
* @param FormFactoryInterface $factory * @param FormFactoryInterface $factory
*/ */
public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, FormFactoryInterface $factory) public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, FormFactoryInterface $factory, array $options = array())
{ {
parent::__construct($name, $dataClass, $dispatcher); parent::__construct($name, $dataClass, $dispatcher, $options);
$this->factory = $factory; $this->factory = $factory;
} }

View File

@ -113,6 +113,11 @@ class FormConfig implements FormConfigInterface
*/ */
private $dataClass; private $dataClass;
/**
* @var array
*/
private $options;
/** /**
* Creates an empty form configuration. * Creates an empty form configuration.
* *
@ -124,7 +129,7 @@ class FormConfig implements FormConfigInterface
* @throws \InvalidArgumentException If the data class is not a valid class or if * @throws \InvalidArgumentException If the data class is not a valid class or if
* the name contains invalid characters. * the name contains invalid characters.
*/ */
public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher) public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, array $options = array())
{ {
$name = (string) $name; $name = (string) $name;
@ -137,6 +142,7 @@ class FormConfig implements FormConfigInterface
$this->name = $name; $this->name = $name;
$this->dataClass = $dataClass; $this->dataClass = $dataClass;
$this->dispatcher = $dispatcher; $this->dispatcher = $dispatcher;
$this->options = $options;
} }
/** /**
@ -408,9 +414,9 @@ class FormConfig implements FormConfigInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getAttribute($name) public function getAttribute($name, $default = null)
{ {
return isset($this->attributes[$name]) ? $this->attributes[$name] : null; return isset($this->attributes[$name]) ? $this->attributes[$name] : $default;
} }
/** /**
@ -429,6 +435,30 @@ class FormConfig implements FormConfigInterface
return $this->dataClass; return $this->dataClass;
} }
/**
* {@inheritdoc}
*/
public function getOptions()
{
return $this->options;
}
/**
* {@inheritdoc}
*/
public function hasOption($name)
{
return isset($this->options[$name]);
}
/**
* {@inheritdoc}
*/
public function getOption($name, $default = null)
{
return isset($this->options[$name]) ? $this->options[$name] : $default;
}
/** /**
* Sets the value for an attribute. * Sets the value for an attribute.
* *

View File

@ -150,10 +150,11 @@ interface FormConfigInterface
* Returns the value of the given attribute. * Returns the value of the given attribute.
* *
* @param string $name The attribute name. * @param string $name The attribute name.
* @param mixed $default The value returned if the attribute does not exist.
* *
* @return mixed The attribute value. * @return mixed The attribute value.
*/ */
function getAttribute($name); function getAttribute($name, $default = null);
/** /**
* Returns the initial data of the form. * Returns the initial data of the form.
@ -168,4 +169,30 @@ interface FormConfigInterface
* @return string The data class or null. * @return string The data class or null.
*/ */
function getDataClass(); function getDataClass();
/**
* Returns all options passed during the construction of the form.
*
* @return array The passed options.
*/
function getOptions();
/**
* Returns whether a specific option exists.
*
* @param string $name The option name,
*
* @return Boolean Whether the option exists.
*/
function hasOption($name);
/**
* Returns the value of a specific option.
*
* @param string $name The option name.
* @param mixed $default The value returned if the option does not exist.
*
* @return mixed The option value.
*/
function getOption($name, $default = null);
} }

View File

@ -228,20 +228,6 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
*/ */
function bind($data); function bind($data);
/**
* Returns whether the form has an attribute with the given name.
*
* @param string $name The name of the attribute
*/
function hasAttribute($name);
/**
* Returns the value of the attributes with the given name.
*
* @param string $name The name of the attribute
*/
function getAttribute($name);
/** /**
* Returns the root of the form tree. * Returns the root of the form tree.
* *

View File

@ -41,8 +41,9 @@ interface FormTypeExtensionInterface
* *
* @param FormView $view The view * @param FormView $view The view
* @param FormInterface $form The form * @param FormInterface $form The form
* @param array $options The options
*/ */
function buildView(FormView $view, FormInterface $form); function buildView(FormView $view, FormInterface $form, array $options);
/** /**
* Builds the view. * Builds the view.
@ -54,8 +55,9 @@ interface FormTypeExtensionInterface
* *
* @param FormView $view The view * @param FormView $view The view
* @param FormInterface $form The form * @param FormInterface $form The form
* @param array $options The options
*/ */
function buildViewBottomUp(FormView $view, FormInterface $form); function buildViewBottomUp(FormView $view, FormInterface $form, array $options);
/** /**
* Overrides the default options from the extended type. * Overrides the default options from the extended type.

View File

@ -43,8 +43,9 @@ interface FormTypeInterface
* *
* @param FormView $view The view * @param FormView $view The view
* @param FormInterface $form The form * @param FormInterface $form The form
* @param array $options The options
*/ */
function buildView(FormView $view, FormInterface $form); function buildView(FormView $view, FormInterface $form, array $options);
/** /**
* Builds the form view. * Builds the form view.
@ -60,8 +61,9 @@ interface FormTypeInterface
* *
* @param FormView $view The view * @param FormView $view The view
* @param FormInterface $form The form * @param FormInterface $form The form
* @param array $options The options
*/ */
function buildViewBottomUp(FormView $view, FormInterface $form); function buildViewBottomUp(FormView $view, FormInterface $form, array $options);
/** /**
* Returns a builder for the current type. * Returns a builder for the current type.

View File

@ -18,33 +18,6 @@ use Symfony\Component\Form\FormConfigInterface;
use Symfony\Component\Form\Util\PropertyPath; use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
abstract class PropertyPathMapperTest_Form implements FormInterface
{
private $attributes = array();
private $data;
public function setAttribute($name, $value)
{
$this->attributes[$name] = $value;
}
public function getAttribute($name)
{
return isset($this->attributes[$name]) ? $this->attributes[$name] : null;
}
public function setData($data)
{
$this->data = $data;
}
public function getData()
{
return $this->data;
}
}
class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase
{ {
/** /**

View File

@ -74,17 +74,17 @@ class ChoiceTypeTest extends TypeTestCase
*/ */
public function testChoicesOptionExpectsArray() public function testChoicesOptionExpectsArray()
{ {
$form = $this->factory->create('choice', null, array( $this->factory->create('choice', null, array(
'choices' => new \ArrayObject(), 'choices' => new \ArrayObject(),
)); ));
} }
/** /**
* @expectedException Symfony\Component\Form\Exception\FormException * @expectedException Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
*/ */
public function testChoiceListOptionExpectsChoiceListInterface() public function testChoiceListOptionExpectsChoiceListInterface()
{ {
$form = $this->factory->create('choice', null, array( $this->factory->create('choice', null, array(
'choice_list' => array('foo' => 'foo'), 'choice_list' => array('foo' => 'foo'),
)); ));
} }
@ -94,7 +94,7 @@ class ChoiceTypeTest extends TypeTestCase
*/ */
public function testEitherChoiceListOrChoicesMustBeSet() public function testEitherChoiceListOrChoicesMustBeSet()
{ {
$form = $this->factory->create('choice', null, array( $this->factory->create('choice', null, array(
)); ));
} }

View File

@ -39,15 +39,15 @@ class CollectionTypeTest extends TypeTestCase
$this->assertCount(2, $form); $this->assertCount(2, $form);
$this->assertEquals('foo@foo.com', $form[0]->getData()); $this->assertEquals('foo@foo.com', $form[0]->getData());
$this->assertEquals('foo@bar.com', $form[1]->getData()); $this->assertEquals('foo@bar.com', $form[1]->getData());
$this->assertEquals(20, $form[0]->getAttribute('max_length')); $this->assertEquals(20, $form[0]->getConfig()->getOption('max_length'));
$this->assertEquals(20, $form[1]->getAttribute('max_length')); $this->assertEquals(20, $form[1]->getConfig()->getOption('max_length'));
$form->setData(array('foo@baz.com')); $form->setData(array('foo@baz.com'));
$this->assertInstanceOf('Symfony\Component\Form\Form', $form[0]); $this->assertInstanceOf('Symfony\Component\Form\Form', $form[0]);
$this->assertFalse(isset($form[1])); $this->assertFalse(isset($form[1]));
$this->assertCount(1, $form); $this->assertCount(1, $form);
$this->assertEquals('foo@baz.com', $form[0]->getData()); $this->assertEquals('foo@baz.com', $form[0]->getData());
$this->assertEquals(20, $form[0]->getAttribute('max_length')); $this->assertEquals(20, $form[0]->getConfig()->getOption('max_length'));
} }
public function testThrowsExceptionIfObjectIsNotTraversable() public function testThrowsExceptionIfObjectIsNotTraversable()
@ -174,7 +174,7 @@ class CollectionTypeTest extends TypeTestCase
'allow_add' => true, 'allow_add' => true,
)); ));
$this->assertSame('__name__', $form->getAttribute('prototype')->getName(), '__name__ is the default'); $this->assertSame('__name__', $form->getConfig()->getAttribute('prototype')->getName(), '__name__ is the default');
$form = $this->factory->create('collection', null, array( $form = $this->factory->create('collection', null, array(
'type' => 'form', 'type' => 'form',
@ -183,7 +183,7 @@ class CollectionTypeTest extends TypeTestCase
'prototype_name' => '__test__', 'prototype_name' => '__test__',
)); ));
$this->assertSame('__test__', $form->getAttribute('prototype')->getName()); $this->assertSame('__test__', $form->getConfig()->getAttribute('prototype')->getName());
} }
public function testPrototypeDefaultLabel() public function testPrototypeDefaultLabel()

View File

@ -341,13 +341,6 @@ class FormTypeTest extends TypeTestCase
$this->assertEquals('Bernhard', $author->firstName); $this->assertEquals('Bernhard', $author->firstName);
} }
public function testGetAttributesIsEmpty()
{
$form = $this->factory->create('form', null, array('attr' => array()));
$this->assertCount(0, $form->getAttribute('attr'));
}
/** /**
* @see https://github.com/symfony/symfony/issues/1986 * @see https://github.com/symfony/symfony/issues/1986
*/ */
@ -379,11 +372,11 @@ class FormTypeTest extends TypeTestCase
} }
/** /**
* @expectedException Symfony\Component\Form\Exception\FormException * @expectedException Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
*/ */
public function testAttributesException() public function testAttributesException()
{ {
$form = $this->factory->create('form', null, array('attr' => '')); $this->factory->create('form', null, array('attr' => ''));
} }
public function testNameCanBeEmptyString() public function testNameCanBeEmptyString()

View File

@ -41,8 +41,8 @@ class RepeatedTypeTest extends TypeTestCase
'options' => array('label' => 'Global'), 'options' => array('label' => 'Global'),
)); ));
$this->assertEquals('Global', $form['first']->getAttribute('label')); $this->assertEquals('Global', $form['first']->getConfig()->getOption('label'));
$this->assertEquals('Global', $form['second']->getAttribute('label')); $this->assertEquals('Global', $form['second']->getConfig()->getOption('label'));
$this->assertTrue($form['first']->isRequired()); $this->assertTrue($form['first']->isRequired());
$this->assertTrue($form['second']->isRequired()); $this->assertTrue($form['second']->isRequired());
} }
@ -56,8 +56,8 @@ class RepeatedTypeTest extends TypeTestCase
'second_options' => array('label' => 'Test2') 'second_options' => array('label' => 'Test2')
)); ));
$this->assertEquals('Test', $form['first']->getAttribute('label')); $this->assertEquals('Test', $form['first']->getConfig()->getOption('label'));
$this->assertEquals('Test2', $form['second']->getAttribute('label')); $this->assertEquals('Test2', $form['second']->getConfig()->getOption('label'));
$this->assertTrue($form['first']->isRequired()); $this->assertTrue($form['first']->isRequired());
$this->assertTrue($form['second']->isRequired()); $this->assertTrue($form['second']->isRequired());
} }
@ -81,8 +81,8 @@ class RepeatedTypeTest extends TypeTestCase
'second_options' => array('label' => 'Second label') 'second_options' => array('label' => 'Second label')
)); ));
$this->assertEquals('Label', $form['first']->getAttribute('label')); $this->assertEquals('Label', $form['first']->getConfig()->getOption('label'));
$this->assertEquals('Second label', $form['second']->getAttribute('label')); $this->assertEquals('Second label', $form['second']->getConfig()->getOption('label'));
$this->assertTrue($form['first']->isRequired()); $this->assertTrue($form['first']->isRequired());
$this->assertTrue($form['second']->isRequired()); $this->assertTrue($form['second']->isRequired());
} }

View File

@ -64,8 +64,8 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
$context = $this->getExecutionContext(); $context = $this->getExecutionContext();
$graphWalker = $context->getGraphWalker(); $graphWalker = $context->getGraphWalker();
$object = $this->getMock('\stdClass'); $object = $this->getMock('\stdClass');
$form = $this->getBuilder('name', '\stdClass') $options = array('validation_groups' => array('group1', 'group2'));
->setAttribute('validation_groups', array('group1', 'group2')) $form = $this->getBuilder('name', '\stdClass', $options)
->setData($object) ->setData($object)
->getForm(); ->getForm();
@ -88,9 +88,11 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
$constraint1 = $this->getMock('Symfony\Component\Validator\Constraint'); $constraint1 = $this->getMock('Symfony\Component\Validator\Constraint');
$constraint2 = $this->getMock('Symfony\Component\Validator\Constraint'); $constraint2 = $this->getMock('Symfony\Component\Validator\Constraint');
$form = $this->getBuilder('name', '\stdClass') $options = array(
->setAttribute('validation_groups', array('group1', 'group2')) 'validation_groups' => array('group1', 'group2'),
->setAttribute('constraints', array($constraint1, $constraint2)) 'constraints' => array($constraint1, $constraint2),
);
$form = $this->getBuilder('name', '\stdClass', $options)
->setData($object) ->setData($object)
->getForm(); ->getForm();
@ -126,12 +128,9 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
$graphWalker = $context->getGraphWalker(); $graphWalker = $context->getGraphWalker();
$object = $this->getMock('\stdClass'); $object = $this->getMock('\stdClass');
$parent = $this->getBuilder() $parent = $this->getBuilder('parent', null, array('cascade_validation' => false))->getForm();
->setAttribute('cascade_validation', false) $options = array('validation_groups' => array('group1', 'group2'));
->getForm(); $form = $this->getBuilder('name', '\stdClass', $options)->getForm();
$form = $this->getBuilder('name', '\stdClass')
->setAttribute('validation_groups', array('group1', 'group2'))
->getForm();
$parent->add($form); $parent->add($form);
$form->setData($object); $form->setData($object);
@ -151,12 +150,12 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
$constraint1 = $this->getMock('Symfony\Component\Validator\Constraint'); $constraint1 = $this->getMock('Symfony\Component\Validator\Constraint');
$constraint2 = $this->getMock('Symfony\Component\Validator\Constraint'); $constraint2 = $this->getMock('Symfony\Component\Validator\Constraint');
$parent = $this->getBuilder() $parent = $this->getBuilder('parent', null, array('cascade_validation' => false))->getForm();
->setAttribute('cascade_validation', false) $options = array(
->getForm(); 'validation_groups' => array('group1', 'group2'),
$form = $this->getBuilder('name', '\stdClass') 'constraints' => array($constraint1, $constraint2),
->setAttribute('validation_groups', array('group1', 'group2')) );
->setAttribute('constraints', array($constraint1, $constraint2)) $form = $this->getBuilder('name', '\stdClass', $options)
->setData($object) ->setData($object)
->getForm(); ->getForm();
$parent->add($form); $parent->add($form);
@ -184,9 +183,8 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
$graphWalker = $context->getGraphWalker(); $graphWalker = $context->getGraphWalker();
$object = $this->getMock('\stdClass'); $object = $this->getMock('\stdClass');
$form = $this->getBuilder('name', '\stdClass') $form = $this->getBuilder('name', '\stdClass', array('invalid_message' => 'Invalid!'))
->setData($object) ->setData($object)
->setAttribute('invalid_message', 'Invalid!')
->appendClientTransformer(new CallbackTransformer( ->appendClientTransformer(new CallbackTransformer(
function ($data) { return $data; }, function ($data) { return $data; },
function () { throw new TransformationFailedException(); } function () { throw new TransformationFailedException(); }
@ -214,10 +212,12 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
$constraint1 = $this->getMock('Symfony\Component\Validator\Constraint'); $constraint1 = $this->getMock('Symfony\Component\Validator\Constraint');
$constraint2 = $this->getMock('Symfony\Component\Validator\Constraint'); $constraint2 = $this->getMock('Symfony\Component\Validator\Constraint');
$form = $this->getBuilder('name', '\stdClass') $options = array(
'validation_groups' => array('group1', 'group2'),
'constraints' => array($constraint1, $constraint2),
);
$form = $this->getBuilder('name', '\stdClass', $options)
->setData($object) ->setData($object)
->setAttribute('validation_groups', array('group1', 'group2'))
->setAttribute('constraints', array($constraint1, $constraint2))
->appendClientTransformer(new CallbackTransformer( ->appendClientTransformer(new CallbackTransformer(
function ($data) { return $data; }, function ($data) { return $data; },
function () { throw new TransformationFailedException(); } function () { throw new TransformationFailedException(); }
@ -239,8 +239,8 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
$context = $this->getExecutionContext(); $context = $this->getExecutionContext();
$graphWalker = $context->getGraphWalker(); $graphWalker = $context->getGraphWalker();
$object = $this->getMock('\stdClass'); $object = $this->getMock('\stdClass');
$form = $this->getBuilder('name', '\stdClass') $options = array('validation_groups' => array($this, 'getValidationGroups'));
->setAttribute('validation_groups', array($this, 'getValidationGroups')) $form = $this->getBuilder('name', '\stdClass', $options)
->setData($object) ->setData($object)
->getForm(); ->getForm();
@ -260,10 +260,10 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
$context = $this->getExecutionContext(); $context = $this->getExecutionContext();
$graphWalker = $context->getGraphWalker(); $graphWalker = $context->getGraphWalker();
$object = $this->getMock('\stdClass'); $object = $this->getMock('\stdClass');
$form = $this->getBuilder('name', '\stdClass') $options = array('validation_groups' => function(FormInterface $form){
->setAttribute('validation_groups', function(FormInterface $form){
return array('group1', 'group2'); return array('group1', 'group2');
}) });
$form = $this->getBuilder('name', '\stdClass', $options)
->setData($object) ->setData($object)
->getForm(); ->getForm();
@ -284,13 +284,12 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
$graphWalker = $context->getGraphWalker(); $graphWalker = $context->getGraphWalker();
$object = $this->getMock('\stdClass'); $object = $this->getMock('\stdClass');
$parent = $this->getBuilder() $parentOptions = array(
->setAttribute('validation_groups', 'group') 'validation_groups' => 'group',
->setAttribute('cascade_validation', true) 'cascade_validation' => true,
->getForm(); );
$form = $this->getBuilder('name', '\stdClass') $parent = $this->getBuilder('parent', null, $parentOptions)->getForm();
->setAttribute('validation_groups', null) $form = $this->getBuilder('name', '\stdClass')->getForm();
->getForm();
$parent->add($form); $parent->add($form);
$form->setData($object); $form->setData($object);
@ -309,13 +308,12 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
$graphWalker = $context->getGraphWalker(); $graphWalker = $context->getGraphWalker();
$object = $this->getMock('\stdClass'); $object = $this->getMock('\stdClass');
$parent = $this->getBuilder() $parentOptions = array(
->setAttribute('validation_groups', array($this, 'getValidationGroups')) 'validation_groups' => array($this, 'getValidationGroups'),
->setAttribute('cascade_validation', true) 'cascade_validation' => true,
->getForm(); );
$form = $this->getBuilder('name', '\stdClass') $parent = $this->getBuilder('parent', null, $parentOptions)->getForm();
->setAttribute('validation_groups', null) $form = $this->getBuilder('name', '\stdClass')->getForm();
->getForm();
$parent->add($form); $parent->add($form);
$form->setData($object); $form->setData($object);
@ -337,15 +335,14 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
$graphWalker = $context->getGraphWalker(); $graphWalker = $context->getGraphWalker();
$object = $this->getMock('\stdClass'); $object = $this->getMock('\stdClass');
$parent = $this->getBuilder() $parentOptions = array(
->setAttribute('validation_groups', function(FormInterface $form){ 'validation_groups' => function(FormInterface $form){
return array('group1', 'group2'); return array('group1', 'group2');
}) },
->setAttribute('cascade_validation', true) 'cascade_validation' => true,
->getForm(); );
$form = $this->getBuilder('name', '\stdClass') $parent = $this->getBuilder('parent', null, $parentOptions)->getForm();
->setAttribute('validation_groups', null) $form = $this->getBuilder('name', '\stdClass')->getForm();
->getForm();
$parent->add($form); $parent->add($form);
$form->setData($object); $form->setData($object);
@ -398,9 +395,8 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
{ {
$context = $this->getExecutionContext(); $context = $this->getExecutionContext();
$form = $this->getBuilder() $form = $this->getBuilder('parent', null, array('extra_fields_message' => 'Extra!'))
->add($this->getBuilder('child')) ->add($this->getBuilder('child'))
->setAttribute('extra_fields_message', 'Extra!')
->getForm(); ->getForm();
$form->bind(array('foo' => 'bar')); $form->bind(array('foo' => 'bar'));
@ -422,9 +418,8 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('1G')); ->will($this->returnValue('1G'));
$context = $this->getExecutionContext(); $context = $this->getExecutionContext();
$form = $this->getBuilder() $options = array('post_max_size_message' => 'Max {{ max }}!');
->setAttribute('post_max_size_message', 'Max {{ max }}!') $form = $this->getBuilder('name', null, $options)->getForm();
->getForm();
$this->validator->initialize($context); $this->validator->initialize($context);
$this->validator->validate($form, new Form()); $this->validator->validate($form, new Form());
@ -443,9 +438,8 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('1g')); ->will($this->returnValue('1g'));
$context = $this->getExecutionContext(); $context = $this->getExecutionContext();
$form = $this->getBuilder() $options = array('post_max_size_message' => 'Max {{ max }}!');
->setAttribute('post_max_size_message', 'Max {{ max }}!') $form = $this->getBuilder('name', null, $options)->getForm();
->getForm();
$this->validator->initialize($context); $this->validator->initialize($context);
$this->validator->validate($form, new Form()); $this->validator->validate($form, new Form());
@ -482,9 +476,8 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('1M')); ->will($this->returnValue('1M'));
$context = $this->getExecutionContext(); $context = $this->getExecutionContext();
$form = $this->getBuilder() $options = array('post_max_size_message' => 'Max {{ max }}!');
->setAttribute('post_max_size_message', 'Max {{ max }}!') $form = $this->getBuilder('name', null, $options)->getForm();
->getForm();
$this->validator->initialize($context); $this->validator->initialize($context);
$this->validator->validate($form, new Form()); $this->validator->validate($form, new Form());
@ -521,9 +514,8 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('1K')); ->will($this->returnValue('1K'));
$context = $this->getExecutionContext(); $context = $this->getExecutionContext();
$form = $this->getBuilder() $options = array('post_max_size_message' => 'Max {{ max }}!');
->setAttribute('post_max_size_message', 'Max {{ max }}!') $form = $this->getBuilder('name', null, $options)->getForm();
->getForm();
$this->validator->initialize($context); $this->validator->initialize($context);
$this->validator->validate($form, new Form()); $this->validator->validate($form, new Form());
@ -598,9 +590,8 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue(' 1K ')); ->will($this->returnValue(' 1K '));
$context = $this->getExecutionContext(); $context = $this->getExecutionContext();
$form = $this->getBuilder() $options = array('post_max_size_message' => 'Max {{ max }}!');
->setAttribute('post_max_size_message', 'Max {{ max }}!') $form = $this->getBuilder('name', null, $options)->getForm();
->getForm();
$this->validator->initialize($context); $this->validator->initialize($context);
$this->validator->validate($form, new Form()); $this->validator->validate($form, new Form());
@ -679,12 +670,13 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
/** /**
* @return FormBuilder * @return FormBuilder
*/ */
private function getBuilder($name = 'name', $dataClass = null) private function getBuilder($name = 'name', $dataClass = null, array $options = array())
{ {
$builder = new FormBuilder($name, $dataClass, $this->dispatcher, $this->factory); $options = array_replace(array(
$builder->setAttribute('constraints', array()); 'constraints' => array(),
), $options);
return $builder; return new FormBuilder($name, $dataClass, $this->dispatcher, $this->factory, $options);
} }
private function getForm($name = 'name', $dataClass = null) private function getForm($name = 'name', $dataClass = null)

View File

@ -19,7 +19,7 @@ class FormTypeValidatorExtensionTest extends TypeTestCase
{ {
$form = $this->factory->create('form'); $form = $this->factory->create('form');
$this->assertNull($form->getAttribute('validation_groups')); $this->assertNull($form->getConfig()->getOption('validation_groups'));
} }
public function testValidationGroupsCanBeSetToString() public function testValidationGroupsCanBeSetToString()
@ -28,7 +28,7 @@ class FormTypeValidatorExtensionTest extends TypeTestCase
'validation_groups' => 'group', 'validation_groups' => 'group',
)); ));
$this->assertEquals(array('group'), $form->getAttribute('validation_groups')); $this->assertEquals(array('group'), $form->getConfig()->getOption('validation_groups'));
} }
public function testValidationGroupsCanBeSetToArray() public function testValidationGroupsCanBeSetToArray()
@ -37,7 +37,7 @@ class FormTypeValidatorExtensionTest extends TypeTestCase
'validation_groups' => array('group1', 'group2'), 'validation_groups' => array('group1', 'group2'),
)); ));
$this->assertEquals(array('group1', 'group2'), $form->getAttribute('validation_groups')); $this->assertEquals(array('group1', 'group2'), $form->getConfig()->getOption('validation_groups'));
} }
public function testValidationGroupsCanBeSetToCallback() public function testValidationGroupsCanBeSetToCallback()
@ -46,7 +46,7 @@ class FormTypeValidatorExtensionTest extends TypeTestCase
'validation_groups' => array($this, 'testValidationGroupsCanBeSetToCallback'), 'validation_groups' => array($this, 'testValidationGroupsCanBeSetToCallback'),
)); ));
$this->assertTrue(is_callable($form->getAttribute('validation_groups'))); $this->assertTrue(is_callable($form->getConfig()->getOption('validation_groups')));
} }
public function testValidationGroupsCanBeSetToClosure() public function testValidationGroupsCanBeSetToClosure()
@ -55,7 +55,7 @@ class FormTypeValidatorExtensionTest extends TypeTestCase
'validation_groups' => function(FormInterface $form){ return null; }, 'validation_groups' => function(FormInterface $form){ return null; },
)); ));
$this->assertTrue(is_callable($form->getAttribute('validation_groups'))); $this->assertTrue(is_callable($form->getConfig()->getOption('validation_groups')));
} }
public function testBindValidatesData() public function testBindValidatesData()

View File

@ -112,6 +112,11 @@ class UnmodifiableFormConfig implements FormConfigInterface
*/ */
private $dataClass; private $dataClass;
/**
* @var array
*/
private $options;
/** /**
* Creates an unmodifiable copy of a given configuration. * Creates an unmodifiable copy of a given configuration.
* *
@ -142,6 +147,7 @@ class UnmodifiableFormConfig implements FormConfigInterface
$this->attributes = $config->getAttributes(); $this->attributes = $config->getAttributes();
$this->data = $config->getData(); $this->data = $config->getData();
$this->dataClass = $config->getDataClass(); $this->dataClass = $config->getDataClass();
$this->options = $config->getOptions();
} }
/** /**
@ -285,9 +291,9 @@ class UnmodifiableFormConfig implements FormConfigInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getAttribute($name) public function getAttribute($name, $default = null)
{ {
return isset($this->attributes[$name]) ? $this->attributes[$name] : null; return isset($this->attributes[$name]) ? $this->attributes[$name] : $default;
} }
/** /**
@ -305,4 +311,28 @@ class UnmodifiableFormConfig implements FormConfigInterface
{ {
return $this->dataClass; return $this->dataClass;
} }
/**
* {@inheritdoc}
*/
public function getOptions()
{
return $this->options;
}
/**
* {@inheritdoc}
*/
public function hasOption($name)
{
return isset($this->options[$name]);
}
/**
* {@inheritdoc}
*/
public function getOption($name, $default = null)
{
return isset($this->options[$name]) ? $this->options[$name] : $default;
}
} }