Skip to content
Permalink
Browse files

Fixing a very subtle validation issue with the CollectionType. I've d…

…oc'ed it quite a bit - it fixes (in our project) symfony/symfony#7468. Thanks to Jürgen Modic for the tip on this!
  • Loading branch information...
weaverryan committed Feb 17, 2017
1 parent 2db22bc commit ab02c4797fe1692082c099f5f722220663f68863
Showing with 74 additions and 1 deletion.
  1. +6 −1 _tuts/steps.json
  2. +68 −0 _tuts/validation-fixing-collection-index-issue.diff
@@ -1250,6 +1250,11 @@
"name": "Validation: Setting errorPath",
"description": null
},
{
"id": "validation-fixing-collection-index-issue",
"name": "Validation: Fixing collection index issue",
"description": null
},
{
"id": "form-customizing-prototype",
"name": "Form: Customizing prototype",
@@ -1301,5 +1306,5 @@
"description": null
}
],
"sha": "7d28227a16674de081ff2133036a39d19d02ebfe"
"sha": "2db22bc14b7fac9c26d6769285c0344e39c68168"
}
@@ -0,0 +1,68 @@
diff --git a/src/AppBundle/Form/GenusFormType.php b/src/AppBundle/Form/GenusFormType.php
index b27928a..cdeb7b7 100644
--- a/src/AppBundle/Form/GenusFormType.php
+++ b/src/AppBundle/Form/GenusFormType.php
@@ -12,6 +12,8 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\Form\FormEvent;
+use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
@@ -51,6 +53,8 @@ class GenusFormType extends AbstractType
'by_reference' => false,
])
;
+
+ $builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmit'));
}

public function configureOptions(OptionsResolver $resolver)
@@ -59,4 +63,45 @@ class GenusFormType extends AbstractType
'data_class' => 'AppBundle\Entity\Genus'
]);
}
+
+ /**
+ * This fixes a validation issue with the Collection. Suppose
+ * the following situation:
+ *
+ * A) Edit a Genus
+ * B) Add 2 new scientists - don't submit & leave all fields blank
+ * C) Delete the FIRST scientist
+ * D) Submit the form
+ *
+ * The one new scientist has a validation error, because
+ * the yearsStudied field was left blank. But, this error
+ * shows at the *top* of the form, not attached to the form.
+ * The reason is that, on submit, addGenusScientist() is
+ * called, and the new scientist is added to the next available
+ * index (so, if the Genus previously had 2 scientists, the
+ * new GenusScientist is added to the "2" index). However,
+ * in the HTML before the form was submitted, the index used
+ * in the name attribute of the fields for the new scientist
+ * was *3*: 0 & 1 were used for the existing scientists and 2 was
+ * used for the first genus scientist form that you added
+ * (and then later deleted). This mis-match confuses the validator,
+ * which thinks there is an error on genusScientists[2].yearsStudied,
+ * and fails to map that to the genusScientists[3].yearsStudied
+ * field.
+ *
+ * Phew! It's a big pain :). Below, we fix it! On submit,
+ * we simply re-index the submitted data before it's bound
+ * to the form. The submitted genusScientists data, which
+ * previously had index 0, 1 and 3, will now have indexes
+ * 0, 1 and 2. And these indexes will match the indexes
+ * that they have on the Genus.genusScientists property.
+ *
+ * @param FormEvent $event
+ */
+ public function onPreSubmit(FormEvent $event)
+ {
+ $data = $event->getData();
+ $data['genusScientists'] = array_values($data['genusScientists']);
+ $event->setData($data);
+ }
}

0 comments on commit ab02c47

Please sign in to comment.
You can’t perform that action at this time.