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:
commit
4bab36b2c7
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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}
|
||||
*/
|
||||
|
|
Reference in New Issue