From 9c94b48eeb4b01459b747ce2ddfd2a677472e7c1 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Mon, 9 Jul 2012 21:04:24 +0200 Subject: [PATCH] [Form] Fixed the "data" option to supersede default data set in the model --- src/Symfony/Component/Form/CHANGELOG.md | 1 + .../Form/Extension/Core/Type/FormType.php | 10 ++++++-- src/Symfony/Component/Form/Form.php | 5 ++++ src/Symfony/Component/Form/FormConfig.php | 23 +++++++++++++++++++ .../Form/FormConfigEditorInterface.php | 13 +++++++++++ .../Component/Form/FormConfigInterface.php | 11 +++++++++ .../Extension/Core/Type/FormTypeTest.php | 12 ++++++++++ .../Component/Form/Tests/SimpleFormTest.php | 19 ++++++++++++--- .../Component/Form/UnmodifiableFormConfig.php | 14 +++++++++++ 9 files changed, 103 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 00ee6c9763..ab7fe7ffc2 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -145,3 +145,4 @@ CHANGELOG * DateType, TimeType and DateTimeType now show empty values again if not required * [BC BREAK] fixed rendering of errors for DateType, BirthdayType and similar ones * [BC BREAK] fixed: form constraints are only validated if they belong to the validated group + * fixed: the "data" option supersedes default values from the model diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index 706b92c9a0..35851cc677 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -42,7 +42,8 @@ class FormType extends AbstractType ->setByReference($options['by_reference']) ->setVirtual($options['virtual']) ->setCompound($options['compound']) - ->setData($options['data']) + ->setData(isset($options['data']) ? $options['data'] : null) + ->setDataLocked(isset($options['data'])) ->setDataMapper($options['compound'] ? new PropertyPathMapper() : null) ; @@ -181,7 +182,6 @@ class FormType extends AbstractType }; $resolver->setDefaults(array( - 'data' => null, 'data_class' => $dataClass, 'empty_data' => $emptyData, 'trim' => true, @@ -203,6 +203,12 @@ class FormType extends AbstractType 'inline' => $inline, )); + // If data is given, the form is locked to that data + // (independent of its value) + $resolver->setOptional(array( + 'data', + )); + $resolver->setAllowedTypes(array( 'attr' => 'array', 'label_attr' => 'array', diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index 729625fe51..f98dc45a63 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -331,6 +331,11 @@ class Form implements \IteratorAggregate, FormInterface throw new AlreadyBoundException('You cannot change the data of a bound form'); } + // Don't allow modifications of the configured data if the data is locked + if ($this->config->getDataLocked() && $modelData !== $this->config->getData()) { + return $this; + } + if (is_object($modelData) && !$this->config->getByReference()) { $modelData = clone $modelData; } diff --git a/src/Symfony/Component/Form/FormConfig.php b/src/Symfony/Component/Form/FormConfig.php index 08e5b006ae..55a7303407 100644 --- a/src/Symfony/Component/Form/FormConfig.php +++ b/src/Symfony/Component/Form/FormConfig.php @@ -118,6 +118,11 @@ class FormConfig implements FormConfigEditorInterface */ private $dataClass; + /** + * @var Boolean + */ + private $dataLocked; + /** * @var array */ @@ -507,6 +512,14 @@ class FormConfig implements FormConfigEditorInterface return $this->dataClass; } + /** + * {@inheritdoc} + */ + public function getDataLocked() + { + return $this->dataLocked; + } + /** * {@inheritdoc} */ @@ -675,6 +688,16 @@ class FormConfig implements FormConfigEditorInterface return $this; } + /** + * {@inheritdoc} + */ + public function setDataLocked($locked) + { + $this->dataLocked = $locked; + + return $this; + } + /** * Validates whether the given variable is a valid form name. * diff --git a/src/Symfony/Component/Form/FormConfigEditorInterface.php b/src/Symfony/Component/Form/FormConfigEditorInterface.php index c893fd223a..8463ad017c 100644 --- a/src/Symfony/Component/Form/FormConfigEditorInterface.php +++ b/src/Symfony/Component/Form/FormConfigEditorInterface.php @@ -227,4 +227,17 @@ interface FormConfigEditorInterface extends FormConfigInterface * @return self The configuration object. */ public function setData($data); + + /** + * Locks the form's data to the data passed in the configuration. + * + * A form with locked data is restricted to the data passed in + * this configuration. The data can only be modified then by + * binding the form. + * + * @param Boolean $locked Whether to lock the default data. + * + * @return self The configuration object. + */ + public function setDataLocked($locked); } diff --git a/src/Symfony/Component/Form/FormConfigInterface.php b/src/Symfony/Component/Form/FormConfigInterface.php index 74971d3ad5..25064b6adb 100644 --- a/src/Symfony/Component/Form/FormConfigInterface.php +++ b/src/Symfony/Component/Form/FormConfigInterface.php @@ -181,6 +181,17 @@ interface FormConfigInterface */ public function getDataClass(); + /** + * Returns whether the form's data is locked. + * + * A form with locked data is restricted to the data passed in + * this configuration. The data can only be modified then by + * binding the form. + * + * @return Boolean Whether the data is locked. + */ + public function getDataLocked(); + /** * Returns all options passed during the construction of the form. * diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php index d9d8866be4..81e96c6944 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php @@ -633,4 +633,16 @@ class FormTypeTest extends TypeTestCase $view = $form->createView(); $this->assertFalse($view->getVar('valid')); } + + public function testDataOptionSupersedesSetDataCalls() + { + $form = $this->factory->create('form', null, array( + 'data' => 'default', + 'compound' => false, + )); + + $form->setData('foobar'); + + $this->assertSame('default', $form->getData()); + } } diff --git a/src/Symfony/Component/Form/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php index 26640d77b2..d10d1dc9a3 100644 --- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php +++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php @@ -23,10 +23,10 @@ use Symfony\Component\Form\Tests\Fixtures\FixedFilterListener; class SimpleFormTest extends AbstractFormTest { - public function testDataIsInitializedEmpty() + public function testDataIsInitializedToConfiguredValue() { $model = new FixedDataTransformer(array( - '' => 'foo', + 'default' => 'foo', )); $view = new FixedDataTransformer(array( 'foo' => 'bar', @@ -35,9 +35,10 @@ class SimpleFormTest extends AbstractFormTest $config = new FormConfig('name', null, $this->dispatcher); $config->addViewTransformer($view); $config->addModelTransformer($model); + $config->setData('default'); $form = new Form($config); - $this->assertNull($form->getData()); + $this->assertSame('default', $form->getData()); $this->assertSame('foo', $form->getNormData()); $this->assertSame('bar', $form->getViewData()); } @@ -376,6 +377,18 @@ class SimpleFormTest extends AbstractFormTest $this->assertSame('', $form->getViewData()); } + public function testSetDataIsIgnoredIfDataIsLocked() + { + $form = $this->getBuilder() + ->setData('default') + ->setDataLocked(true) + ->getForm(); + + $form->setData('foobar'); + + $this->assertSame('default', $form->getData()); + } + public function testBindConvertsEmptyToNullIfNoTransformer() { $form = $this->getBuilder()->getForm(); diff --git a/src/Symfony/Component/Form/UnmodifiableFormConfig.php b/src/Symfony/Component/Form/UnmodifiableFormConfig.php index 448f325bcc..a39e351eb7 100644 --- a/src/Symfony/Component/Form/UnmodifiableFormConfig.php +++ b/src/Symfony/Component/Form/UnmodifiableFormConfig.php @@ -116,6 +116,11 @@ class UnmodifiableFormConfig implements FormConfigInterface */ private $dataClass; + /** + * @var Boolean + */ + private $dataLocked; + /** * @var array */ @@ -152,6 +157,7 @@ class UnmodifiableFormConfig implements FormConfigInterface $this->attributes = $config->getAttributes(); $this->data = $config->getData(); $this->dataClass = $config->getDataClass(); + $this->dataLocked = $config->getDataLocked(); $this->options = $config->getOptions(); } @@ -325,6 +331,14 @@ class UnmodifiableFormConfig implements FormConfigInterface return $this->dataClass; } + /** + * {@inheritdoc} + */ + public function getDataLocked() + { + return $this->dataLocked; + } + /** * {@inheritdoc} */