Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 94bae4d

Browse files
cristoforocervinoCristoforo Cervino
authored andcommitted
add keepAsList option to ResizeFormListener
1 parent 90eb014 commit 94bae4d

File tree

3 files changed

+84
-21
lines changed

3 files changed

+84
-21
lines changed

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,16 @@ class ResizeFormListener implements EventSubscriberInterface
3030
protected $allowDelete;
3131

3232
private \Closure|bool $deleteEmpty;
33+
private $keepAsList;
3334

34-
public function __construct(string $type, array $options = [], bool $allowAdd = false, bool $allowDelete = false, bool|callable $deleteEmpty = false)
35+
public function __construct(string $type, array $options = [], bool $allowAdd = false, bool $allowDelete = false, bool|callable $deleteEmpty = false, bool $keepAsList = false)
3536
{
3637
$this->type = $type;
3738
$this->allowAdd = $allowAdd;
3839
$this->allowDelete = $allowDelete;
3940
$this->options = $options;
4041
$this->deleteEmpty = $deleteEmpty instanceof \Closure || !\is_callable($deleteEmpty) ? $deleteEmpty : \Closure::fromCallable($deleteEmpty);
42+
$this->keepAsList = $keepAsList;
4143
}
4244

4345
public static function getSubscribedEvents(): array
@@ -159,6 +161,20 @@ public function onSubmit(FormEvent $event)
159161
}
160162
}
161163

164+
if ($this->keepAsList) {
165+
$formReindex = [];
166+
foreach ($form as $name => $child) {
167+
$formReindex[] = $child;
168+
$form->remove($name);
169+
}
170+
foreach ($formReindex as $index => $child) {
171+
$form->add($index, $this->type, array_replace([
172+
'property_path' => '['.$index.']',
173+
], $this->options));
174+
}
175+
$data = array_values($data);
176+
}
177+
162178
$event->setData($data);
163179
}
164180
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ public function buildForm(FormBuilderInterface $builder, array $options)
4545
$options['entry_options'],
4646
$options['allow_add'],
4747
$options['allow_delete'],
48-
$options['delete_empty']
48+
$options['delete_empty'],
49+
$options['keep_as_list']
4950
);
5051

5152
$builder->addEventSubscriber($resizeListener);
@@ -122,10 +123,12 @@ public function configureOptions(OptionsResolver $resolver)
122123
'entry_options' => [],
123124
'delete_empty' => false,
124125
'invalid_message' => 'The collection is invalid.',
126+
'keep_as_list' => false,
125127
]);
126128

127129
$resolver->setNormalizer('entry_options', $entryOptionsNormalizer);
128130
$resolver->setAllowedTypes('delete_empty', ['bool', 'callable']);
131+
$resolver->setAllowedTypes('keep_as_list', ['bool']);
129132
}
130133

131134
/**

src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
use Symfony\Component\Form\Tests\Extension\Core\Type\FormTypeTest;
2020
use Symfony\Component\Form\Tests\Extension\Core\Type\TextTypeTest;
2121
use Symfony\Component\Form\Tests\Fixtures\Author;
22-
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
2322
use Symfony\Component\Form\Tests\Fixtures\AuthorType;
2423
use Symfony\Component\Form\Tests\Fixtures\Organization;
24+
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
2525
use Symfony\Component\Validator\Constraints\GroupSequence;
2626
use Symfony\Component\Validator\Constraints\Length;
2727
use Symfony\Component\Validator\Constraints\NotBlank;
@@ -192,21 +192,7 @@ public function testErrorPathOnCollections()
192192
->setMetadataFactory($metadataFactory)
193193
->getValidator();
194194

195-
$form = Forms::createFormFactoryBuilder()
196-
->addExtension(new ValidatorExtension($validator))
197-
->getFormFactory()
198-
->create(FormTypeTest::TESTED_TYPE, new Organization([]), [
199-
'data_class' => Organization::class,
200-
'by_reference' => false,
201-
])
202-
->add('authors', CollectionTypeTest::TESTED_TYPE, [
203-
'entry_type' => AuthorType::class,
204-
'allow_add' => true,
205-
'allow_delete' => true,
206-
])
207-
;
208-
209-
$form->submit([
195+
$submitData = [
210196
'authors' => [
211197
0 => [
212198
'firstName' => '', // Fires a Not Blank Error
@@ -222,7 +208,23 @@ public function testErrorPathOnCollections()
222208
'lastName' => 'lastName3',
223209
],
224210
],
225-
]);
211+
];
212+
213+
$form = Forms::createFormFactoryBuilder()
214+
->addExtension(new ValidatorExtension($validator))
215+
->getFormFactory()
216+
->create(FormTypeTest::TESTED_TYPE, new Organization([]), [
217+
'data_class' => Organization::class,
218+
'by_reference' => false,
219+
])
220+
->add('authors', CollectionTypeTest::TESTED_TYPE, [
221+
'entry_type' => AuthorType::class,
222+
'allow_add' => true,
223+
'allow_delete' => true,
224+
])
225+
;
226+
227+
$form->submit($submitData);
226228

227229
//Form behaves right (...?). It has index 0, 2 and 3 (1 has been removed)
228230
$this->assertTrue($form->get('authors')->has('0'));
@@ -242,11 +244,53 @@ public function testErrorPathOnCollections()
242244
];
243245

244246
$this->assertContains('data.authors[0].firstName', $errorPaths);
245-
$this->assertNotContains('data.authors[1].firstName', $errorPaths);
247+
$this->assertContains('data.authors[1].firstName', $errorPaths);
246248
$this->assertContains('data.authors[2].firstName', $errorPaths);
247-
$this->assertContains('data.authors[3].firstName', $errorPaths);
249+
$this->assertNotContains('data.authors[3].firstName', $errorPaths);
248250

249251
//In fact, root form should NOT contain errors but it does
252+
$this->assertCount(1, $form->getErrors(false));
253+
254+
//Let's do this again, but with "keep_as_list" option set to true
255+
$form = Forms::createFormFactoryBuilder()
256+
->addExtension(new ValidatorExtension($validator))
257+
->getFormFactory()
258+
->create(FormTypeTest::TESTED_TYPE, new Organization([]), [
259+
'data_class' => Organization::class,
260+
'by_reference' => false,
261+
])
262+
->add('authors', CollectionTypeTest::TESTED_TYPE, [
263+
'entry_type' => AuthorType::class,
264+
'allow_add' => true,
265+
'allow_delete' => true,
266+
'keep_as_list' => true,
267+
])
268+
;
269+
270+
$form->submit($submitData);
271+
272+
//Errors paths are not messing up now
273+
$this->assertTrue($form->get('authors')->has('0'));
274+
$this->assertTrue($form->get('authors')->has('1'));
275+
$this->assertTrue($form->get('authors')->has('2'));
276+
$this->assertNotTrue($form->get('authors')->has('3'));
277+
278+
//Form does have 3 not blank errors
279+
$errors = $form->getErrors(true);
280+
$this->assertCount(3, $errors);
281+
282+
$errorPaths = [
283+
$errors[0]->getCause()->getPropertyPath(),
284+
$errors[1]->getCause()->getPropertyPath(),
285+
$errors[2]->getCause()->getPropertyPath(),
286+
];
287+
288+
$this->assertContains('data.authors[0].firstName', $errorPaths);
289+
$this->assertContains('data.authors[1].firstName', $errorPaths);
290+
$this->assertContains('data.authors[2].firstName', $errorPaths);
291+
$this->assertNotContains('data.authors[3].firstName', $errorPaths);
292+
293+
//Root form does NOT contain errors
250294
$this->assertCount(0, $form->getErrors(false));
251295
}
252296
}

0 commit comments

Comments
 (0)