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

Skip to content

Commit 70e1b0e

Browse files
cristoforocervinoCristoforo Cervino
authored andcommitted
add keepAsList option to ResizeFormListener
1 parent 5bd334d commit 70e1b0e

File tree

3 files changed

+83
-20
lines changed

3 files changed

+83
-20
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
@@ -31,15 +31,17 @@ class ResizeFormListener implements EventSubscriberInterface
3131
protected bool $allowDelete;
3232

3333
private \Closure|bool $deleteEmpty;
34+
private bool $keepAsList;
3435

35-
public function __construct(string $type, array $options = [], bool $allowAdd = false, bool $allowDelete = false, bool|callable $deleteEmpty = false, array $prototypeOptions = null)
36+
public function __construct(string $type, array $options = [], bool $allowAdd = false, bool $allowDelete = false, bool|callable $deleteEmpty = false, array $prototypeOptions = null, bool $keepAsList = false)
3637
{
3738
$this->type = $type;
3839
$this->allowAdd = $allowAdd;
3940
$this->allowDelete = $allowDelete;
4041
$this->options = $options;
4142
$this->deleteEmpty = \is_bool($deleteEmpty) ? $deleteEmpty : $deleteEmpty(...);
4243
$this->prototypeOptions = $prototypeOptions ?? $options;
44+
$this->keepAsList = $keepAsList;
4345
}
4446

4547
public static function getSubscribedEvents(): array
@@ -153,6 +155,20 @@ public function onSubmit(FormEvent $event): void
153155
}
154156
}
155157

158+
if ($this->keepAsList) {
159+
$formReindex = [];
160+
foreach ($form as $name => $child) {
161+
$formReindex[] = $child;
162+
$form->remove($name);
163+
}
164+
foreach ($formReindex as $index => $child) {
165+
$form->add($index, $this->type, array_replace([
166+
'property_path' => '['.$index.']',
167+
], $this->options));
168+
}
169+
$data = array_values($data);
170+
}
171+
156172
$event->setData($data);
157173
}
158174
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
4545
$options['allow_add'],
4646
$options['allow_delete'],
4747
$options['delete_empty'],
48+
$options['keep_as_list'],
4849
$resizePrototypeOptions
4950
);
5051

@@ -114,12 +115,14 @@ public function configureOptions(OptionsResolver $resolver): void
114115
'prototype_options' => [],
115116
'delete_empty' => false,
116117
'invalid_message' => 'The collection is invalid.',
118+
'keep_as_list' => false,
117119
]);
118120

119121
$resolver->setNormalizer('entry_options', $entryOptionsNormalizer);
120122

121123
$resolver->setAllowedTypes('delete_empty', ['bool', 'callable']);
122124
$resolver->setAllowedTypes('prototype_options', 'array');
125+
$resolver->setAllowedTypes('keep_as_list', ['bool']);
123126
}
124127

125128
public function getBlockPrefix(): string

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)