title: saving embedded form (collection) Symfony2
body: <p>I am making an invoicing system with an embedded form. A form where you can add a date, choose a customer company from a dropdown list (-> customer is an entity) and add details to the invoice item (-> details is also an entity, with properties like price, amount,...) - with javascript. This works just fine, but at saving the form I get an error.
  I have 3 entities: InvoicingCustomer, InvoiceItem, InvoiceItemDetail.
  (Sorry; this is going to be a long post)</p>
  
  <p><strong>InvoicingCustomer.php</strong> (with properties like street, address,...) =</p>
  
  <pre><code>/**
  * @ORM\Table(name="invoicing_customer")
  * @ORM\Entity
  */
  class InvoicingCustomer
  {
     /**
     * @ORM\OneToMany(targetEntity="Invoicing\InvoicingBundle\Entity\InvoiceItem", mappedBy="customer")
     */
     private $invoice;
  
     public function __construct()
     { $this-&gt;invoice = new ArrayCollection();}
  
     public function getInvoice()
     { return $this-&gt;invoice; }
  
     public function getAllInvoices()
     {
        $invoices = $this-&gt;getInvoice()-&gt;toArray();
        return $invoices;
     }
  
     /**
     * @var integer
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
     private $id;
  
    /**
     * @var string
     * @ORM\Column(name="company_name", type="string", length=50, nullable=false)
     * @Assert\NotBlank()
     */
     private $companyName;
     //idem for next properties:
     private $firstName;
     private $lastName;
     private $street;
     private $number;
     private $postalCode;
     private $city;
  }
  </code></pre>
  
  <p>And off course the getters and setters.</p>
  
  <p><strong>InvoiceItem.php</strong> =</p>
  
  <pre><code>/**
  * @ORM\Table(name="invoicing_invoice_item")
  * @ORM\Entity
  */
  class InvoiceItem
  {
    /**
     * @ORM\OneToMany(targetEntity="Invoicing\InvoicingBundle\Entity\InvoiceItemDetail", mappedBy="item_nr", cascade={"ALL"}, fetch="EAGER", orphanRemoval=true)
     */
     private $item_detail;
  
     public function __construct()
     { $this-&gt;item_detail = new ArrayCollection(); }
  
     /**
      * @return mixed
      */
     public function getItemDetail()
     { return $this-&gt;item_detail;  }
  
     /**
     * @param mixed $item_detail
     */
     public function setItemDetail(Collection $item_detail)
     {
        foreach ($item_detail as $v)
        {
          if (is_null($v-&gt;getId()))
          {
              $v-&gt;getId($this);
          }
        }
        $this-&gt;item_detail = $item_detail;
     }
  
     public function addDetail(InvoiceItemDetail $detail){
       $detail-&gt;$this-&gt;setItemDetail($this);
       $this-&gt;detail[] = $detail;
       return $this;
     }
  
     public function removeDetail(InvoiceItemDetail $detail){
        //
     }
  
    /**
     * @var integer
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
     private $id;
  
    /**
     * @var \DateTime
     * @ORM\Column(name="date", type="date", nullable=false)
     */
     private $date;
  
    /**
     * @ORM\ManyToOne(targetEntity="Invoicing\CustomerBundle\Entity\InvoicingCustomer", inversedBy="invoice")
     * @ORM\JoinColumn(onDelete="CASCADE", nullable=false)
     * @Assert\Type(type="Invoicing\CustomerBundle\Entity\InvoicingCustomer")
     * @Assert\Valid()
     *
     */
     private $customer;
  
    // here also getters and setters
  }
  </code></pre>
  
  <p><strong>InvoiceItemDetail.php</strong> =</p>
  
  <pre><code>/**
   * @ORM\Table(name="invoicing_invoice_itemdetail")
   * @ORM\Entity
   */
  class InvoiceItemDetail
  {
     /**
      * @var integer
      * @ORM\Column(name="id", type="integer")
      * @ORM\Id
      * @ORM\GeneratedValue(strategy="IDENTITY")
      */
      private $id;
  
     /**
      * @ORM\Column(name="description", type="text", length=200, nullable=false)
      */
     private $description;
  
     /**
      * @var string
      * @ORM\Column(name="price", type="decimal", precision=10, scale=0, nullable=false)
      */
      private $price;
  
      /**
      * @var integer
      * @ORM\Column(name="amount", type="decimal", precision=10, scale=0, nullable=false)
      */
      private $amount;
  
     /**
      * @ORM\ManyToOne(targetEntity="Invoicing\InvoicingBundle\Entity\InvoiceItem", inversedBy="item_detail" )
      * @ORM\JoinColumn(onDelete="CASCADE", nullable=false, name="item_nr_id", referencedColumnName="id")
      * @Assert\Type(type="Invoicing\InvoicingBundle\Entity\InvoiceItem")
      * @Assert\Valid()
      */
      private $item_nr;
  
  // + getters and setters
  }
  </code></pre>
  
  <p>Then, I got the types.
  <strong>InvoiceItemType.php</strong> =</p>
  
  <pre><code>class InvoiceItemType extends AbstractType
   {
      /**
       * @param FormBuilderInterface $builder
       * @param array $options
       */
      public function buildForm(FormBuilderInterface $builder, array $options)
      {
         $builder
             -&gt;add('date', 'date', array(
                 'format' =&gt; 'dd-MM-yyyy',
                 'empty_value' =&gt; array('year' =&gt; 'Year', 'month' =&gt; 'Month', 'day' =&gt; 'Day'),
                 'years' =&gt; range(date('Y') -1, date('Y')),
             ))
             -&gt;add('customer', null, array(
                'empty_value' =&gt; 'Choose a company',
                'label' =&gt; 'Company',
                'required' =&gt; true,
             ))
             -&gt;add('item_detail', 'collection', array(
                 'type' =&gt; new InvoiceItemDetailType(),
                 'allow_add' =&gt; true,
                 'constraints' =&gt; new NotBlank(),
                 'by_reference' =&gt; false,
             ));
      }
     public function getName()
     { return 'invoiceitem'; }
  
     public function setDefaultOptions(OptionsResolverInterface $resolver)
     {
        $resolver-&gt;setDefaults(array(
            'data_class' =&gt; 'Invoicing\InvoicingBundle\Entity\InvoiceItem',
        ));
     }
  }
  </code></pre>
  
  <p><strong>InvoicingCustomerType.php</strong> =</p>
  
  <pre><code>class InvoicingCustomerType extends AbstractType
   {
     public function buildForm(FormBuilderInterface $builder, array $options)
     {
        $builder-&gt;add('companyName', 'text');
     }
  
     public function setDefaultOptions(OptionsResolverInterface $resolver)
     {
        $resolver-&gt;setDefaults(array(
            'data_class' =&gt; 'Invoicing\CustomerBundle\Entity\InvoicingCustomer',
        ));
     }
     public function getName()
     { return 'customer'; }
  }
  </code></pre>
  
  <p><strong>InvoiceItemDetailType.php</strong> =</p>
  
  <pre><code>class InvoiceItemDetailType extends AbstractType
   {
      public function buildForm(FormBuilderInterface $builder, array $options)
      {
         $builder
             -&gt;add('description', 'text')
             -&gt;add('price', 'number', array(
                 'label' =&gt; 'Price - €',
              ))
            -&gt;add('amount', 'number');
       }
  
       public function setDefaultOptions(OptionsResolverInterface $resolver)
       {
           $resolver-&gt;setDefaults(array(
              'data_class' =&gt; 'Invoicing\InvoicingBundle\Entity\InvoiceItemDetail',
           ));
       }
       public function getName()
       { return 'detail'; }
   } 
  </code></pre>
  
  <p>In my controller I have this (<strong>InvoiceItemController.php</strong>):</p>
  
  <pre><code>/** InvoiceItem controller */
   class InvoiceItemController extends Controller
   {
      /**
       * Creates a new invoiceitem entity.
       */
      public function createAction(Request $request)
      {
         $entity = new InvoiceItem();
  
         $form = $this-&gt;createCreateForm($entity);
         $form-&gt;handleRequest($request);
  
         if ($form-&gt;isValid()) {
             $em = $this-&gt;getDoctrine()-&gt;getManager();
  
             // hack to work around handleRequest not using class methods to populate data
             foreach($entity-&gt;getItemDetail() as $detail){
                foreach($detail as $i){
                  // if i didn't made a second loop, I get an error: "object could not be converted to string..."
                    $i-&gt;this-&gt;setItemNr($entity);
                    $em-&gt;persist($i);
                 }
             }
             $em-&gt;persist($entity);
             $em-&gt;flush();
  
             return $this-&gt;redirect($this-&gt;generateUrl('invoiceitem_show', array('id' =&gt; $entity-&gt;getId())));
          }
  
         return $this-&gt;render('InvoicingBundle:InvoiceItem:new.html.twig', array(
             'entity' =&gt; $entity,
             'form'   =&gt; $form-&gt;createView(),
         ));
      }
  }
  </code></pre>
  
  <p>In my twig it's just like: </p>
  
  <pre><code>{% block body -%}
     &lt;h1&gt;Invoice item creation&lt;/h1&gt;
     {{ form(form) }}
   {% endblock %}
  </code></pre>
  
  <p>Everything in the form is displayed good (and with javascript I can add several details to one invoice item). But when I submit the form, symfony throws an error:</p>
  
  <pre><code>An exception occurred while executing 'INSERT INTO invoicing_invoice_itemdetail (description, price, amount, item_nr_id) VALUES (?, ?, ?, ?)' with params ["test", 300, 1, null]: 
  SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'item_nr_id' cannot be null
  </code></pre>
  
  <p>I searched around on the docs of symfony (<a href="http://symfony.com/doc/current/cookbook/form/form_collections.html" rel="nofollow noreferrer">http://symfony.com/doc/current/cookbook/form/form_collections.html</a> ) and on stackoverflow (for example: <a href="https://stackoverflow.com/questions/19878192/saving-embedded-collections">Saving embedded collections</a> ), but none of these give me the right solution.</p>
  
  <p>I know this is a long post: I am sorry. But I don't know how to sort this problem out (+ I am new in learning symfony2 &amp; new in asking questions here).</p>