[Form] Added delete_empty option to allow proper emptyData handling of collections
This commit is contained in:
parent
efcca3e2e1
commit
8bdb7a0460
@ -45,12 +45,18 @@ class ResizeFormListener implements EventSubscriberInterface
|
||||
*/
|
||||
protected $allowDelete;
|
||||
|
||||
public function __construct($type, array $options = array(), $allowAdd = false, $allowDelete = false)
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $deleteEmpty;
|
||||
|
||||
public function __construct($type, array $options = array(), $allowAdd = false, $allowDelete = false, $deleteEmpty = false)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->allowAdd = $allowAdd;
|
||||
$this->allowDelete = $allowDelete;
|
||||
$this->options = $options;
|
||||
$this->deleteEmpty = $deleteEmpty;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
@ -126,8 +132,13 @@ class ResizeFormListener implements EventSubscriberInterface
|
||||
public function onSubmit(FormEvent $event)
|
||||
{
|
||||
$form = $event->getForm();
|
||||
$previousData = $event->getForm()->getData();
|
||||
$data = $event->getData();
|
||||
|
||||
// At this point, $data is an array or an array-like object that already contains the
|
||||
// new entries, which were added by the data mapper. The data mapper ignores existing
|
||||
// entries, so we need to manually unset removed entries in the collection.
|
||||
|
||||
if (null === $data) {
|
||||
$data = array();
|
||||
}
|
||||
@ -136,10 +147,23 @@ class ResizeFormListener implements EventSubscriberInterface
|
||||
throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
|
||||
}
|
||||
|
||||
if ($this->deleteEmpty) {
|
||||
foreach ($form as $name => $child) {
|
||||
$isNew = !isset($previousData[$name]);
|
||||
|
||||
// $isNew can only be true if allowAdd is true, so we don't
|
||||
// need to check allowAdd again
|
||||
if ($child->isEmpty() && ($isNew || $this->allowDelete)) {
|
||||
unset($data[$name]);
|
||||
$form->remove($name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The data mapper only adds, but does not remove items, so do this
|
||||
// here
|
||||
if ($this->allowDelete) {
|
||||
foreach ($data as $name => $child) {
|
||||
foreach ($data as $name => $childData) {
|
||||
if (!$form->has($name)) {
|
||||
unset($data[$name]);
|
||||
}
|
||||
|
@ -37,7 +37,8 @@ class CollectionType extends AbstractType
|
||||
$options['type'],
|
||||
$options['options'],
|
||||
$options['allow_add'],
|
||||
$options['allow_delete']
|
||||
$options['allow_delete'],
|
||||
$options['delete_empty']
|
||||
);
|
||||
|
||||
$builder->addEventSubscriber($resizeListener);
|
||||
@ -86,6 +87,7 @@ class CollectionType extends AbstractType
|
||||
'prototype_name' => '__name__',
|
||||
'type' => 'text',
|
||||
'options' => array(),
|
||||
'delete_empty' => false,
|
||||
));
|
||||
|
||||
$resolver->setNormalizers(array(
|
||||
|
@ -899,7 +899,9 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
}
|
||||
|
||||
if (isset($this->children[$name])) {
|
||||
$this->children[$name]->setParent(null);
|
||||
if (!$this->children[$name]->isSubmitted()) {
|
||||
$this->children[$name]->setParent(null);
|
||||
}
|
||||
|
||||
unset($this->children[$name]);
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
namespace Symfony\Component\Form\Tests\Extension\Core\Type;
|
||||
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\Form\Tests\Fixtures\Author;
|
||||
use Symfony\Component\Form\Tests\Fixtures\AuthorType;
|
||||
|
||||
class CollectionTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
|
||||
{
|
||||
@ -88,6 +90,78 @@ class CollectionTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
|
||||
$this->assertEquals(array('foo@foo.com'), $form->getData());
|
||||
}
|
||||
|
||||
public function testResizedDownIfSubmittedWithEmptyDataAndDeleteEmpty()
|
||||
{
|
||||
$form = $this->factory->create('collection', null, array(
|
||||
'type' => 'text',
|
||||
'allow_delete' => true,
|
||||
'delete_empty' => true,
|
||||
));
|
||||
|
||||
$form->setData(array('foo@foo.com', 'bar@bar.com'));
|
||||
$form->submit(array('foo@foo.com', ''));
|
||||
|
||||
$this->assertTrue($form->has('0'));
|
||||
$this->assertFalse($form->has('1'));
|
||||
$this->assertEquals('foo@foo.com', $form[0]->getData());
|
||||
$this->assertEquals(array('foo@foo.com'), $form->getData());
|
||||
}
|
||||
|
||||
public function testDontAddEmptyDataIfDeleteEmpty()
|
||||
{
|
||||
$form = $this->factory->create('collection', null, array(
|
||||
'type' => 'text',
|
||||
'allow_add' => true,
|
||||
'delete_empty' => true,
|
||||
));
|
||||
|
||||
$form->setData(array('foo@foo.com'));
|
||||
$form->submit(array('foo@foo.com', ''));
|
||||
|
||||
$this->assertTrue($form->has('0'));
|
||||
$this->assertFalse($form->has('1'));
|
||||
$this->assertEquals('foo@foo.com', $form[0]->getData());
|
||||
$this->assertEquals(array('foo@foo.com'), $form->getData());
|
||||
}
|
||||
|
||||
public function testNoDeleteEmptyIfDeleteNotAllowed()
|
||||
{
|
||||
$form = $this->factory->create('collection', null, array(
|
||||
'type' => 'text',
|
||||
'allow_delete' => false,
|
||||
'delete_empty' => true,
|
||||
));
|
||||
|
||||
$form->setData(array('foo@foo.com'));
|
||||
$form->submit(array(''));
|
||||
|
||||
$this->assertTrue($form->has('0'));
|
||||
$this->assertEquals('', $form[0]->getData());
|
||||
}
|
||||
|
||||
public function testResizedDownIfSubmittedWithCompoundEmptyDataAndDeleteEmpty()
|
||||
{
|
||||
$form = $this->factory->create('collection', null, array(
|
||||
'type' => new AuthorType(),
|
||||
// If the field is not required, no new Author will be created if the
|
||||
// form is completely empty
|
||||
'options' => array('required' => false),
|
||||
'allow_add' => true,
|
||||
'delete_empty' => true,
|
||||
));
|
||||
|
||||
$form->setData(array(new Author('first', 'last')));
|
||||
$form->submit(array(
|
||||
array('firstName' => 's_first', 'lastName' => 's_last'),
|
||||
array('firstName' => '', 'lastName' => ''),
|
||||
));
|
||||
|
||||
$this->assertTrue($form->has('0'));
|
||||
$this->assertFalse($form->has('1'));
|
||||
$this->assertEquals(new Author('s_first', 's_last'), $form[0]->getData());
|
||||
$this->assertEquals(array(new Author('s_first', 's_last')), $form->getData());
|
||||
}
|
||||
|
||||
public function testNotResizedIfSubmittedWithExtraData()
|
||||
{
|
||||
$form = $this->factory->create('collection', null, array(
|
||||
|
@ -21,6 +21,12 @@ class Author
|
||||
|
||||
private $privateProperty;
|
||||
|
||||
public function __construct($firstName = null, $lastName = null)
|
||||
{
|
||||
$this->firstName = $firstName;
|
||||
$this->lastName = $lastName;
|
||||
}
|
||||
|
||||
public function setLastName($lastName)
|
||||
{
|
||||
$this->lastName = $lastName;
|
||||
|
Reference in New Issue
Block a user