title: Sonata Admin one-to-many relationship with file upload (appendFormFieldElement)
body: <p>I'm currently facing a challenge with SonataAdminBundle, one-to-many relationships and file uploads. I have an Entity called <code>Client</code> and one called <code>ExchangeFile</code>. One <code>Client</code> can have several <code>ExchangeFile</code>s, so we have a one-to-many relationship here. I'm using the <a href="https://github.com/dustin10/VichUploaderBundle" rel="nofollow noreferrer">VichUploaderBundle</a> for file uploads.</p>
  
  <p>This is the <code>Client</code> class:</p>
  
  <pre><code>/**
   * @ORM\Table(name="client")
   * @ORM\Entity()
   * @ORM\HasLifecycleCallbacks
   */
  class Client extends BaseUser
  {    
      // SNIP
  
      /**
       * @ORM\OneToMany(targetEntity="ExchangeFile", mappedBy="client", orphanRemoval=true, cascade={"persist", "remove"})
       */
      protected $exchangeFiles;
  
      // SNIP
  }
  </code></pre>
  
  <p>and this is the <code>ExchangeFile</code> class:</p>
  
  <pre><code>/**
   * @ORM\Table(name="exchange_file")
   * @ORM\Entity
   * @Vich\Uploadable
   */
  class ExchangeFile
  {
      // SNIP
  
      /**
       * @Assert\File(
       *     maxSize="20M"
       * )
       * @Vich\UploadableField(mapping="exchange_file", fileNameProperty="fileName")
       */
      protected $file;
  
      /**
       * @ORM\Column(name="file_name", type="string", nullable=true)
       */
      protected $fileName;
  
      /**
       * @ORM\ManyToOne(targetEntity="Client", inversedBy="exchangeFiles")
       * @ORM\JoinColumn(name="client_id", referencedColumnName="id")
       */
      protected $client;
  
      // SNIP
  }
  </code></pre>
  
  <p>In my <code>ClientAdmin</code> class, i added the <code>exchangeFiles</code> field the following way:</p>
  
  <pre><code>protected function configureFormFields(FormMapper $formMapper)
  {
      $formMapper
          // SNIP
          -&gt;with('Files')
              -&gt;add('exchangeFiles', 'sonata_type_collection', array('by_reference' =&gt; false), array(
                      'edit' =&gt; 'inline',
                      'inline' =&gt; 'table',
                  ))
          // SNIP
  }
  </code></pre>
  
  <p>This allows for inline editing of various exchange files in the Client edit form. And it works well so far: <img src="https://i.stack.imgur.com/8JrSC.png" alt="Sonata Admin with one-to-many relationship and file uploads">.</p>
  
  <p><strong>The Problem</strong></p>
  
  <p>But there's one ceveat: When i hit the green "+" sign once (add a new exchange file form row), <strong>then select a file in my filesystem</strong>, then hit the "+" sign again (a new form row is appended via Ajax), select another file, and then hit "Update" (save the current Client), <strong>then the first file is not persisted</strong>. Only the second file can be found in the database and the file system.</p>
  
  <p>As far as I could find out, this has the following reason: When the green "+" sign is clicked the second time, the current form is post to the web server, including the data currently in the form (Client and all exchange files). A new form is created and the request is bound into the form (this happens in the <code>AdminHelper</code> class located in <code>Sonata\AdminBundle\Admin</code>):</p>
  
  <pre><code>public function appendFormFieldElement(AdminInterface $admin, $subject, $elementId)
  {
      // retrieve the subject
      $formBuilder = $admin-&gt;getFormBuilder();
  
      $form = $formBuilder-&gt;getForm();
      $form-&gt;setData($subject);
      $form-&gt;bind($admin-&gt;getRequest()); // &lt;-- here
      // SNIP
  }
  </code></pre>
  
  <p>So the entire form is bound, a form row is appended, the form is sent back to the browser and the entire form is overwritten by the new one. But since file inputs (<code>&lt;input type="file" /&gt;</code>) cannot be pre-populated for security reasons, the first file is lost. The file is only stored on the filesystem when the entity is persisted (I think <code>VichUploaderBundle</code> uses Doctrine's <code>prePersist</code> for this), but this does not yet happen when a form field row is appended.</p>
  
  <p><strong>My first question is</strong>: How can i solve this problem, or which direction should i go? I would like the following use case to work: I want to create a new Client and I know I'll upload three files. I click "New Client", enter the Client data, hit the green "+" button once, select the first file. Then i hit the "+" sign again, and select the second file. Same for the third file. All three files should be persisted.</p>
  
  <p><strong>Second question</strong>: Why does Sonata Admin post the entire form when I only want to add a single form row in a one-to-many relationship? Is this really necessary? This means that if I have file inputs, all files present in the form are uploaded every time a new form row is added.</p>
  
  <p>Thanks in advance for your help. If you need any details, let me know.</p>