merged branch bschussek/issue3899 (PR #4813)

Commits
-------

9c94b48 [Form] Fixed the "data" option to supersede default data set in the model

Discussion
----------

[Form] Fixed the "data" option to supersede default data set in the model

Bug fix: yes
Feature addition: no
Backwards compatibility break: no
Symfony2 tests pass: yes
Fixes the following tickets: #3899
Todo: -
This commit is contained in:
Fabien Potencier 2012-07-10 08:22:37 +02:00
commit 4bab36b2c7
9 changed files with 103 additions and 5 deletions

View File

@ -146,3 +146,4 @@ CHANGELOG
* [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
* deprecated `bindRequest` in `Form` and replaced it by a listener to FormEvents::PRE_BIND
* fixed: the "data" option supersedes default values from the model

View File

@ -43,7 +43,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)
->addEventSubscriber(new BindRequestListener())
;
@ -183,7 +184,6 @@ class FormType extends AbstractType
};
$resolver->setDefaults(array(
'data' => null,
'data_class' => $dataClass,
'empty_data' => $emptyData,
'trim' => true,
@ -205,6 +205,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',

View File

@ -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;
}

View File

@ -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.
*

View File

@ -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);
}

View File

@ -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.
*

View File

@ -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());
}
}

View File

@ -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();

View File

@ -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}
*/