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 rendering of errors for DateType, BirthdayType and similar ones
|
||||||
* [BC BREAK] fixed: form constraints are only validated if they belong to the validated group
|
* [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
|
* 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'])
|
->setByReference($options['by_reference'])
|
||||||
->setVirtual($options['virtual'])
|
->setVirtual($options['virtual'])
|
||||||
->setCompound($options['compound'])
|
->setCompound($options['compound'])
|
||||||
->setData($options['data'])
|
->setData(isset($options['data']) ? $options['data'] : null)
|
||||||
|
->setDataLocked(isset($options['data']))
|
||||||
->setDataMapper($options['compound'] ? new PropertyPathMapper() : null)
|
->setDataMapper($options['compound'] ? new PropertyPathMapper() : null)
|
||||||
->addEventSubscriber(new BindRequestListener())
|
->addEventSubscriber(new BindRequestListener())
|
||||||
;
|
;
|
||||||
@ -183,7 +184,6 @@ class FormType extends AbstractType
|
|||||||
};
|
};
|
||||||
|
|
||||||
$resolver->setDefaults(array(
|
$resolver->setDefaults(array(
|
||||||
'data' => null,
|
|
||||||
'data_class' => $dataClass,
|
'data_class' => $dataClass,
|
||||||
'empty_data' => $emptyData,
|
'empty_data' => $emptyData,
|
||||||
'trim' => true,
|
'trim' => true,
|
||||||
@ -205,6 +205,12 @@ class FormType extends AbstractType
|
|||||||
'inline' => $inline,
|
'inline' => $inline,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// If data is given, the form is locked to that data
|
||||||
|
// (independent of its value)
|
||||||
|
$resolver->setOptional(array(
|
||||||
|
'data',
|
||||||
|
));
|
||||||
|
|
||||||
$resolver->setAllowedTypes(array(
|
$resolver->setAllowedTypes(array(
|
||||||
'attr' => 'array',
|
'attr' => 'array',
|
||||||
'label_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');
|
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()) {
|
if (is_object($modelData) && !$this->config->getByReference()) {
|
||||||
$modelData = clone $modelData;
|
$modelData = clone $modelData;
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,11 @@ class FormConfig implements FormConfigEditorInterface
|
|||||||
*/
|
*/
|
||||||
private $dataClass;
|
private $dataClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Boolean
|
||||||
|
*/
|
||||||
|
private $dataLocked;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
@ -507,6 +512,14 @@ class FormConfig implements FormConfigEditorInterface
|
|||||||
return $this->dataClass;
|
return $this->dataClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getDataLocked()
|
||||||
|
{
|
||||||
|
return $this->dataLocked;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@ -675,6 +688,16 @@ class FormConfig implements FormConfigEditorInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function setDataLocked($locked)
|
||||||
|
{
|
||||||
|
$this->dataLocked = $locked;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates whether the given variable is a valid form name.
|
* Validates whether the given variable is a valid form name.
|
||||||
*
|
*
|
||||||
|
@ -227,4 +227,17 @@ interface FormConfigEditorInterface extends FormConfigInterface
|
|||||||
* @return self The configuration object.
|
* @return self The configuration object.
|
||||||
*/
|
*/
|
||||||
public function setData($data);
|
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();
|
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.
|
* Returns all options passed during the construction of the form.
|
||||||
*
|
*
|
||||||
|
@ -633,4 +633,16 @@ class FormTypeTest extends TypeTestCase
|
|||||||
$view = $form->createView();
|
$view = $form->createView();
|
||||||
$this->assertFalse($view->getVar('valid'));
|
$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
|
class SimpleFormTest extends AbstractFormTest
|
||||||
{
|
{
|
||||||
public function testDataIsInitializedEmpty()
|
public function testDataIsInitializedToConfiguredValue()
|
||||||
{
|
{
|
||||||
$model = new FixedDataTransformer(array(
|
$model = new FixedDataTransformer(array(
|
||||||
'' => 'foo',
|
'default' => 'foo',
|
||||||
));
|
));
|
||||||
$view = new FixedDataTransformer(array(
|
$view = new FixedDataTransformer(array(
|
||||||
'foo' => 'bar',
|
'foo' => 'bar',
|
||||||
@ -35,9 +35,10 @@ class SimpleFormTest extends AbstractFormTest
|
|||||||
$config = new FormConfig('name', null, $this->dispatcher);
|
$config = new FormConfig('name', null, $this->dispatcher);
|
||||||
$config->addViewTransformer($view);
|
$config->addViewTransformer($view);
|
||||||
$config->addModelTransformer($model);
|
$config->addModelTransformer($model);
|
||||||
|
$config->setData('default');
|
||||||
$form = new Form($config);
|
$form = new Form($config);
|
||||||
|
|
||||||
$this->assertNull($form->getData());
|
$this->assertSame('default', $form->getData());
|
||||||
$this->assertSame('foo', $form->getNormData());
|
$this->assertSame('foo', $form->getNormData());
|
||||||
$this->assertSame('bar', $form->getViewData());
|
$this->assertSame('bar', $form->getViewData());
|
||||||
}
|
}
|
||||||
@ -376,6 +377,18 @@ class SimpleFormTest extends AbstractFormTest
|
|||||||
$this->assertSame('', $form->getViewData());
|
$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()
|
public function testBindConvertsEmptyToNullIfNoTransformer()
|
||||||
{
|
{
|
||||||
$form = $this->getBuilder()->getForm();
|
$form = $this->getBuilder()->getForm();
|
||||||
|
@ -116,6 +116,11 @@ class UnmodifiableFormConfig implements FormConfigInterface
|
|||||||
*/
|
*/
|
||||||
private $dataClass;
|
private $dataClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Boolean
|
||||||
|
*/
|
||||||
|
private $dataLocked;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
@ -152,6 +157,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->dataLocked = $config->getDataLocked();
|
||||||
$this->options = $config->getOptions();
|
$this->options = $config->getOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,6 +331,14 @@ class UnmodifiableFormConfig implements FormConfigInterface
|
|||||||
return $this->dataClass;
|
return $this->dataClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getDataLocked()
|
||||||
|
{
|
||||||
|
return $this->dataLocked;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user