title: One to One Relationship and compound forms (Symfony 3.4)
body: <p>I have 2 entities, Exercise and Product, they have a One to One relationship (the owning side is Product), and I have an ExerciseFormType and a ProductFormType.</p>
  
  <p>What I want I to be able to create an exercise, and the product associated with it at the same time.</p>
  
  <p>My idea was to add the the builder of exerciseFormType, 'product' and its type would be a ProductFormType. The problem is that the product needs the exercise_id, and the exercise isn't persisted yet so it doesn't have one. Here's what I have so far (it works only for creating a product when the exercise exists).</p>
  
  <pre><code>    class ExerciseType extends AbstractType {
  
          /**
           * {@inheritdoc}
           */
          public function buildForm(FormBuilderInterface $builder, array $options) {
              $builder-&gt;add('name')
                      -&gt;add('content')
                      -&gt;add('language')
                      -&gt;add('level')
                      -&gt;add('skillsRequired')
                      -&gt;add('skillsTargetted')
                      -&gt;add('tags')
                      -&gt;add('product', ProductType::class, array(
                          'required' =&gt; false,
                          'exercise'=&gt; $builder-&gt;getData()
                          )
                      );
          }
  
          /**
           * {@inheritdoc}
           */
          public function configureOptions(OptionsResolver $resolver){
              $resolver-&gt;setDefaults(array(
                  'data_class' =&gt; 'SchoolBundle\Entity\Exercise'
              ));
          }
  
          /**
           * {@inheritdoc}
           */
          public function getBlockPrefix(){
              return 'schoolbundle_exercise';
          }
  
  class ProductType extends AbstractType {
      /**
       * {@inheritdoc}
       */
      public function buildForm(FormBuilderInterface $builder, array $options){
  
          $builder-&gt;add('visibility')-&gt;add('price', MoneyType::class);
  
          $builder-&gt;addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
              $product = $event-&gt;getData();
              $form = $event-&gt;getForm();
  
              $field = (!$product || null === $product-&gt;getId()) ? 'publicationDate' : 'updateDate';
              $form-&gt;add($field, DateTimeType::class, array('data' =&gt; new \DateTime()));
  
          });
  
          $data = array(
              'data' =&gt; $options['exercise'],
              'class' =&gt; Exercise::class,
              'choice_label' =&gt; 'getName'
          );
  
          $builder-&gt;add('exercise', EntityType::class, $data);
      }
  
      /**
       * {@inheritdoc}
       */
      public function configureOptions(OptionsResolver $resolver){
          $resolver-&gt;setDefaults(array(
              'data_class' =&gt; 'MarketBundle\Entity\Product'
          ));
  
          $resolver-&gt;setRequired(array(
              'exercise'
          ));
      }
  
      /**
       * {@inheritdoc}
       */
      public function getBlockPrefix(){
          return 'marketbundle_product';
      }
  
  
  }
  </code></pre>
  
  <p>In exercise I have that</p>
  
  <pre><code>  &lt;?php
      /**
       * exercise
       *
       * @ORM\Table(name="exercise")
       * @ORM\Entity(repositoryClass="SchoolBundle\Repository\ExerciseRepository")
       */
      class Exercise {
          /**
           * @var int
           * @ORM\Column(name="id", type="integer")
           * @ORM\Id
           * @ORM\GeneratedValue(strategy="AUTO")
           */
          private $id;
  
          /**
           * @var string
           * @ORM\Column(name="name", type="string", length=255)
           */
          private $name;
  
          /**
           * @var string
           * @ORM\Column(name="content", type="string", length=255)
           */
          private $content;
  
          /**
           * @var string
           * @ORM\Column(name="language", type="string", length=255)
           */
          private $language;
  
          /**
           * @var int
           * @ORM\Column(name="level", type="integer")
           */
          private $level;
  
          /**
           * @var string
           * @ORM\Column(name="skills_required", type="string", length=255)
           */
          private $skillsRequired;
  
          /**
           * @var string
           * @ORM\Column(name="skills_targetted", type="string", length=255)
           */
          private $skillsTargetted;
  
          /**
           * @var string
           * @ORM\Column(name="tags", type="string", length=255)
           */
          private $tags;
  
          /**
           * @ORM\OneToMany(targetEntity="Session", mappedBy="exercise")
           */
          private $sessions;
  
          /**
           * @ORM\OneToMany(targetEntity="ExerciseIO", mappedBy="exercise")
           */
          private $exerciseIOs;
  
          /**
           * @ORM\OneToOne(targetEntity="MarketBundle\Entity\Product", mappedBy="exercise", cascade={"persist"}))
           */
          private $product;
  
          /**
           * @ORM\ManyToOne(targetEntity="Professor", inversedBy="createdExercises")
           * @ORM\JoinColumn(name="creator_id", referencedColumnName="id", nullable=false)
           */
          private $creator;
  
          /**
           * @ORM\ManyToMany(targetEntity="Professor", mappedBy="boughtExercises")
           */
          private $owners;
  
          public function __construct(){
              $this-&gt;sessions = new ArrayCollection();
              $this-&gt;exerciseIOs = new ArrayCollection();
              $this-&gt;owners = new ArrayCollection();
          }
  
          /**
           * Get creator
           * @return Professor
           */
          public function getCreator(){
              return $this-&gt;creator;
          }
  
          /**
           * Set creator
           * @param Professor $creator
           * @return Exercise
           */
          public function setCreator($creator){
              $this-&gt;creator = $creator;
              return $this;
          }
  
          /**
           * Get owner
           * @return ArrayCollection
           */
          public function getOwners(){
              return $this-&gt;owners;
          }
  
          /**
           * Get product
           * @return Product
           */
          public function getProduct(){
              return $this-&gt;product;
          }
  
  
          /**
           * @param Product $product
           * @return Exercise
           */
          public function setProduct($product){
              $this-&gt;product = $product;
              return $this;
          }
  
          /**
           * Get exerciseIOs
           * @return ArrayCollection
           */
          public function getExerciseIOs(){
              return $this-&gt;exerciseIOs;
          }
  
          /**
           * Get sessions
           * @return ArrayCollection
           */
          public function getSessions(){
              return $this-&gt;sessions;
          }
  
          /**
           * Get id
           * @return int
           */
          public function getId(){
              return $this-&gt;id;
          }
  
          /**
           * Set name
           * @param string $name
           * @return Exercise
           */
          public function setName($name){
              $this-&gt;name = $name;
              return $this;
          }
  
          /**
           * Get name
           * @return string
           */
          public function getName(){
              return $this-&gt;name;
          }
  
          /**
           * Set content
           * @param string $content
           * @return Exercise
           */
          public function setContent($content){
              $this-&gt;content = $content;
              return $this;
          }
  
          /**
           * Get content
           * @return string
           */
          public function getContent(){
              return $this-&gt;content;
          }
  
          /**
           * Set language
           * @param string $language
           * @return Exercise
           */
          public function setLanguage($language){
              $this-&gt;language = $language;
              return $this;
          }
  
          /**
           * Get language
           * @return string
           */
          public function getLanguage(){
              return $this-&gt;language;
          }
  
          /**
           * Set level
           * @param string $level
           * @return Exercise
           */
          public function setLevel($level){
              $this-&gt;level = $level;
              return $this;
          }
  
          /**
           * Get level
           * @return string
           */
          public function getLevel(){
              return $this-&gt;level;
          }
  
          /**
           * Set skillsRequired
           * @param string $skillsRequired
           * @return Exercise
           */
          public function setSkillsRequired($skillsRequired){
              $this-&gt;skillsRequired = $skillsRequired;
              return $this;
          }
  
          /**
           * Get skillsRequired
           * @return string
           */
          public function getSkillsRequired(){
              return $this-&gt;skillsRequired;
          }
  
          /**
           * Set skillsTargetted
           * @param string $skillsTargetted
           * @return Exercise
           */
          public function setSkillsTargetted($skillsTargetted){
              $this-&gt;skillsTargetted = $skillsTargetted;
              return $this;
          }
  
          /**
           * Get skillsTargetted
           * @return string
           */
          public function getSkillsTargetted(){
              return $this-&gt;skillsTargetted;
          }
  
          /**
           * Set tags
           * @param string $tags
           * @return Exercise
           */
          public function setTags($tags){
              $this-&gt;tags = $tags;
              return $this;
          }
  
          /**
           * Get tags
           * @return string
           */
          public function getTags(){
              return $this-&gt;tags;
          }
      }
  </code></pre>
  
  <p>And in Product</p>
  
  <pre><code>/**
   * Product
   *
   * @ORM\Table(name="product")
   * @ORM\Entity(repositoryClass="\MarketBundle\Repository\ProductRepository")
   */
  class Product {
  
      /**
       * @var int
       * @ORM\Column(name="id", type="integer")
       * @ORM\Id
       * @ORM\GeneratedValue(strategy="AUTO")
       */
      private $id;
  
      /**
       * @var bool
       * @ORM\Column(name="visibility", type="boolean")
       */
      private $visibility;
  
      /**
       * @var float
       * @ORM\Column(name="price", type="float")
       */
      private $price;
  
      /**
       * @var \DateTime
       * @ORM\Column(name="publication_date", type="datetimetz")
       */
      private $publicationDate;
  
      /**
       * @var \DateTime
       * @ORM\Column(name="update_date", type="datetimetz", nullable=true)
       */
      private $updateDate;
  
      /**
       * @ORM\OneToMany(targetEntity="ProductComment", mappedBy="product")
       */
      private $productComments;
  
      /**
       * @ORM\OneToOne(targetEntity="\SchoolBundle\Entity\Exercise", inversedBy="product")
       * @ORM\JoinColumn(name="exercise_id", referencedColumnName="id", nullable=false)
       */
      private $exercise;
  
      public function __construct(){
          $this-&gt;productComments = new ArrayCollection();
      }
  
      /**
       * Get exercise
       * @return Exercise
       */
      public function getExercise(){
          return $this-&gt;exercise;
      }
  
      /**
       * Set exercise
       * @param Exercise $exercise
       * @return Product
       */
      public function setExercise($exercise){
          $this-&gt;exercise = $exercise;
          return $this;
      }
  
  
  
      /**
       * Get productComments
       * @return ArrayCollection
       */
      public function getProductComments(){
          return $this-&gt;productComments;
      }
  
      /**
       * Get id
       * @return int
       */
      public function getId(){
          return $this-&gt;id;
      }
  
      /**
       * Set visibility
       * @param boolean $visibility
       * @return Product
       */
      public function setVisibility($visibility){
          $this-&gt;visibility = $visibility;
          return $this;
      }
  
      /**
       * Get visibility
       * @return bool
       */
      public function getVisibility(){
          return $this-&gt;visibility;
      }
  
      /**
       * Set price
       * @param float $price
       * @return Product
       */
      public function setPrice($price){
          $this-&gt;price = $price;
          return $this;
      }
  
      /**
       * Get price
       * @return float
       */
      public function getPrice(){
          return $this-&gt;price;
      }
  
      /**
       * Set publicationDate
       * @param \DateTime $publicationDate
       * @return Product
       */
      public function setPublicationDate($publicationDate){
          $this-&gt;publicationDate = $publicationDate;
          return $this;
      }
  
      /**
       * Get publicationDate
       * @return \DateTime
       */
      public function getPublicationDate(){
          return $this-&gt;publicationDate;
      }
  
      /**
       * Set updateDate
       * @param \DateTime $updateDate
       * @return Product
       */
      public function setUpdateDate($updateDate){
          $this-&gt;updateDate = $updateDate;
          return $this;
      }
  
      /**
       * Get updateDate
       * @return \DateTime
       */
      public function getUpdateDate(){
          return $this-&gt;updateDate;
      }
  }
  </code></pre>
  
  <p>I've said it works for an existing exercise (and no product).
  When I try to create both at the same time I get </p>
  
  <p>Entities passed to the choice field must be managed. Maybe persist them in the entity manager?</p>
  
  <p>It's probably from the $builder->getData(), because in that case I only passed to the form a "new Exercice()". Here's the controller action</p>
  
  <pre><code>public function newAction(Request $request){
  
          $exercise = new Exercise();
          $form = $this-&gt;createForm(ExerciseType::class, $exercise);
          $form-&gt;handleRequest($request);
  
          if ($form-&gt;isSubmitted() &amp;&amp; $form-&gt;isValid()) {
              $exercise-&gt;setCreator($this-&gt;getUser());
              $em = $this-&gt;getDoctrine()-&gt;getManager();
              $em-&gt;persist($exercise);
              $em-&gt;flush();
  
              return $this-&gt;redirectToRoute('exercise_show', array('id' =&gt; $exercise-&gt;getId()));
          }
  </code></pre>
  
  <p>(Also this is another question but when I disable a formType, it is rendered, and the value appears but it's not submitted. I would actually prefer a hiddenFormType but I need the formatting of the DateTimeFormType)</p>