8000 [Form] Allow pass filter callback to delete_empty option. · symfony/symfony@3b7f11a · GitHub
[go: up one dir, main page]

Skip to content

Commit 3b7f11a

Browse files
committed
[Form] Allow pass filter callback to delete_empty option.
1 parent 3de0d9b commit 3b7f11a

File tree

4 files changed

+54
-5
lines changed

4 files changed

+54
-5
lines changed

src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Form\FormEvent;
1616
use Symfony\Component\Form\Exception\UnexpectedTypeException;
1717
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
18+
use Symfony\Component\Form\FormInterface;
1819

1920
/**
2021
* Resize a collection form element based on the data sent from the client.
@@ -48,7 +49,7 @@ class ResizeFormListener implements EventSubscriberInterface
4849
protected $allowDelete;
4950

5051
/**
51-
* @var bool
52+
* @var bool|callable
5253
*/
5354
private $deleteEmpty;
5455

@@ -148,14 +149,16 @@ public function onSubmit(FormEvent $event)
148149
throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
149150
}
150151

151-
if ($this->deleteEmpty) {
152-
$previousData = $event->getForm()->getData();
152+
if ($entryFilter = $this->deleteEmpty) {
153+
$previousData = $form->getData();
153154
foreach ($form as $name => $child) {
155+
/* @var $child FormInterface */
154156
$isNew = !isset($previousData[$name]);
157+
$isEmpty = $child->isEmpty() || (is_callable($entryFilter) && true === $entryFilter($child->getData()));
155158

156159
// $isNew can only be true if allowAdd is true, so we don't
157160
// need to check allowAdd again
158-
if ($child->isEmpty() && ($isNew || $this->allowDelete)) {
161+
if ($isEmpty && ($isNew || $this->allowDelete)) {
159162
unset($data[$name]);
160163
$form->remove($name);
161164
}

src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ public function configureOptions(OptionsResolver $resolver)
100100
));
101101

102102
$resolver->setNormalizer('entry_options', $entryOptionsNormalizer);
103+
$resolver->setAllowedTypes('delete_empty', array('bool', 'callable'));
103104
}
104105

105106
/**

src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Form\Tests\Extension\Core\Type;
1313

1414
use Symfony\Component\Form\Tests\Fixtures\Author;
15+
use Symfony\Component\Form\Tests\Fixtures\AuthorType;
1516

1617
class CollectionTypeTest extends BaseTypeTest
1718
{
@@ -110,6 +111,49 @@ public function testResizedDownIfSubmittedWithEmptyDataAndDeleteEmpty()
110111
$this->assertEquals(array('foo@foo.com'), $form->getData());
111112
}
112113

114+
public function testResizedDownWithDeleteEmptyCallable()
115+
{
116+
$form = $this->factory->create(static::TESTED_TYPE, null, array(
117+
'entry_type' => AuthorType::class,
118+
'allow_delete' => true,
119+
'delete_empty' => function (Author $obj = null) {
120+
return null === $obj || empty($obj->firstName);
121+
},
122+
));
123+
124+
$form->setData(array(new Author('Bob'), new Author('Alice')));
125+
$form->submit(array(array('firstName' => 'Bob'), array('firstName' => '')));
126+
127+
$this->assertTrue($form->has('0'));
128+
$this->assertFalse($form->has('1'));
129+
$this->assertEquals(new Author('Bob'), $form[0]->getData());
130+
$this->assertEquals(array(new Author('Bob')), $form->getData());
131+
}
132+
133+
public function testResizedDownIfSubmittedWithCompoundEmptyDataDeleteEmptyAndNoDataClass()
134+
{
135+
$form = $this->factory->create(static::TESTED_TYPE, null, array(
136+
'entry_type' => AuthorType::class,
137+
// If the field is not required, no new Author will be created if the
138+
// form is completely empty
139+
'entry_options' => array('data_class' => null),
140+
'allow_add' => true,
141+
'allow_delete' => true,
142+
'delete_empty' => function ($author) {
143+
return empty($author['firstName']);
144+
},
145+
));
146+
$form->setData(array(array('firstName' => 'first', 'lastName' => 'last')));
147+
$form->submit(array(
148+
array('firstName' => 's_first', 'lastName' => 's_last'),
149+
array('firstName' => '', 'lastName' => ''),
150+
));
151+
$this->assertTrue($form->has('0'));
152+
$this->assertFalse($form->has('1'));
153+
$this->assertEquals(array('firstName' => 's_first', 'lastName' => 's_last'), $form[0]->getData());
154+
$this->assertEquals(array(array('firstName' => 's_first', 'lastName' => 's_last')), $form->getData());
155+
}
156+
113157
public function testDontAddEmptyDataIfDeleteEmpty()
114158
{
115159
$form = $this->factory->create(static::TESTED_TYPE, null, array(

src/Symfony/Component/Form/Tests/FormErrorIteratorTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\Form\FormBuilder;
1717
use Symfony\Component\Form\FormError;
1818
use Symfony\Component\Form\FormErrorIterator;
19+
use Symfony\Component\Form\FormFactoryInterface;
1920
use Symfony\Component\Validator\ConstraintViolation;
2021

2122
class FormErrorIteratorTest extends TestCase
@@ -33,7 +34,7 @@ public function testFindByCodes($code, $violationsCount)
3334
'form',
3435
null,
3536
new EventDispatcher(),
36-
$this->getMockBuilder('Symfony\Component\Form\FormFactoryInterface')->getMock(),
37+
$this->getMockBuilder(FormFactoryInterface::class)->getMock(),
3738
array()
3839
);
3940

0 commit comments

Comments
 (0)
0