title: Keep good data in form after failed validation on symfony form collection
body: <p>I have a form with a dynamic form collection. The point is that I don't want to allow the user to remove specific entries (that are modified in another part of the app). So I added a specific validation constraint that works: the form is not valid if I remove an element that is not "deletable".</p>
  
  <p>The problem is that, as the element was removed in what the user submitted, the element is not in the form anymore, and after submit form data is locked.</p>
  
  <p>Here is an example to show the problem:</p>
  
  <pre><code>class AppointmentController extends Controller
  {
  
      public function editAppointment(Request $request, Appointment $appointment)
      {
          // Here
          // count($appointment-&gt;getSlot()) === 3
  
          $form = $this-&gt;createForm('appointment', $appointment, [
              'questionnaire' =&gt; $questionnaire
          ]);
          $form-&gt;handleRequest($request);
  
          if ($form-&gt;isValid()) {
              // Persisting
          }
  
          // Here on failing validation, there is
          // count($appointment-&gt;getSlot()) === 2
          // Because we removed one slot from "dynamically" in the form, but the user can't do that,
          // so we need to reset the slots but it's not possible because form data is locked after "submit".
          return $this-&gt;render('App:Appointment:edit.html.twig', ['form' =&gt; $form-&gt;createView()]);
      }
  }
  
  class AppointmentType extends AbstractTYpe
  {
      public function buildForm(FormBuilderInterface $builder, array $options)
      {
          $builder
              -&gt;add('slots', 'collection', [
                  'type' =&gt; new SlotType(),
                  'allow_add' =&gt; true,
                  'prototype' =&gt; true,
                  'allow_delete' =&gt; true,
                  'error_bubbling' =&gt; false,
                  'by_reference' =&gt; false,
                  'constraints' =&gt; [
                      new WrongSlotRemoval($builder-&gt;getData()-&gt;getSlots())
                  ]
              ])
          ;
      }
  }
  
  class WrongSlotRemoval extends Constraint
  {
      public $message = 'Impossible to delete slog.';
  
      /**
       * @var null|\App\Entity\AppointmentSlot[]
       */
      private $slots;
  
      /**
       * @param \App\Entity\AppointmentSlot[]|null $slots
       */
      public function __construct($slots = null)
      {
          // Clone the collection because it can be modified by reference
          // in order to add or delete items.
          if ($slots !== null) {
              $this-&gt;slots = clone $slots;
          }
      }
  
      /**
       * @return \App\Entity\AppointmentSlot[]
       */
      public function getSlots()
      {
          return $this-&gt;slots;
      }
  
      /**
       * @param \App\Entity\AppointmentSlot[] $slots
       * @return self
       */
      public function setSlots($slots)
      {
          $this-&gt;slots = $slots;
  
          return $this;
      }
  }
  
  class WrongSlotRemovalValidator extends ConstraintValidator
  {
      /**
       * @param \App\Entity\AppointmentSlot[] $object
       * @param WrongSlotRemoval $constraint
       */
      public function validate($object, Constraint $constraint)
      {
          foreach($constraint-&gt;getSlots() as $slot) {
              if (!$object-&gt;contains($slot) &amp;&amp; !$slot-&gt;isDeletable()) {
  
                  $this-&gt;context
                      -&gt;buildViolation($constraint-&gt;message)
                      -&gt;addViolation()
                  ;
  
                  return;
              }
          }
      }
  }
  </code></pre>
  
  <p><strong>Any idea about how to modify form data after submit ?</strong></p>
  
  <p>Here is a screen of the problem: <a href="http://file.nekland.fr/dev/pb_form_collection.jpeg" rel="nofollow">http://file.nekland.fr/dev/pb_form_collection.jpeg</a></p>