title: Symfony Form: OneToMany and CollectionType Field
body: <p>I got stucked into building a form with Symfony 3. </p>
  
  <p>I defined an entity 'News' containing an attribute 'newsArticle', which has a OneToMany Relation to the entity 'NewsArticle', holding translations of its attributes 'headline', 'subheader and 'bodytext'.
  The goal is to provide a form that holds on the one hand fields for the attributes of 'News' and on the other hand fields to create an 'NewsArticle' entry for the default language.</p>
  
  <p>Entity News (excerpt):</p>
  
  <pre><code>/**
   * @ORM\Entity
   * @ORM\Table(name="news")
   */
  class News {
      /**
       * @ORM\Column(type="integer")
       * @ORM\Id
       * @ORM\GeneratedValue(strategy="AUTO")
       */
      private $id;
  
      /**
       * @ORM\OneToMany(targetEntity="NewsArticle", mappedBy="news", cascade={"persist", "remove"})
       */
      private $newsArticle;
  
      /**
       * Constructor
       */
      public function __construct()
      {
          $this-&gt;newsArticle = new \Doctrine\Common\Collections\ArrayCollection();
      }
  }
  </code></pre>
  
  <p>Entity NewsArticle (excerpt):</p>
  
  <pre><code>/**
   * @ORM\Entity
   * @ORM\Table(name="news_article")
   */
  class NewsArticle {
  
      /**
       * @ORM\Column(type="integer")
       * @ORM\Id
       * @ORM\GeneratedValue(strategy="AUTO")
       */
      private $id;
  
      /**
       * @ORM\ManyToOne(targetEntity="News")
       * @ORM\JoinColumn(name="news_id", referencedColumnName="id")
       */
      private $news;
  
      /**
       * @ORM\Column(type="string", length=150, unique=false, nullable=false)
       * @Assert\NotBlank()
       */
      private $headline;
  
      /**
       * @ORM\Column(type="string", length=150, nullable=true)
       */
      private $subheadline;
  
      /**
       * @ORM\Column(type="string", length=65536, nullable=false)
       * @Assert\NotBlank()
       */
      private $bodytext;
  
      /**
       * @ORM\ManyToOne(targetEntity="Language")
       * @ORM\JoinColumn(name="language_id", referencedColumnName="id")
       */
      private $languageId;
  }
  </code></pre>
  
  <p>The Controller (excerpt):</p>
  
  <pre><code>public function addAction(Request $request) {
      $lang = $this-&gt;getDoctrine()
          -&gt;getRepository('Bundle:Language')
          -&gt;findOneBy(array('deleted' =&gt; 0, 'fallback' =&gt; 1));
  
      $news = new News();
      //$news-&gt;newsArticle-&gt;setLanguageId($lang);
  
      $form = $this-&gt;createForm(NewsType::class, $news);
  
      $form-&gt;handleRequest($request);
  
      if ($form-&gt;isSubmitted() &amp;&amp; $form-&gt;isValid()) {
  
          $em = $this-&gt;getDoctrine()-&gt;getManager();
          $em-&gt;persist($news);
          $em-&gt;flush();
      }
  
      return $this-&gt;render('Bundle:News:add.html.twig', array(
          'form' =&gt; $form-&gt;createView(),
          'news' =&gt; $news,
      ));
  }
  </code></pre>
  
  <p>TWIG Template (excerpt):</p>
  
  <pre><code>{{ form_start(form) }}
      &lt;div class="form-group"&gt;
          {{ form_label(form.headline) }}
          &lt;div class="col-sm-8 col-md-6"&gt;
              {{ form_errors(form.headline) }}
              {{ form_widget(form.headline) }}
          &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="form-group"&gt;
          {{ form_label(form.subheadline) }}
          &lt;div class="col-sm-8 col-md-6"&gt;
              {{ form_errors(form.subheadline) }}
              {{ form_widget(form.subheadline) }}
          &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="form-group"&gt;
          {{ form_label(form.bodytext) }}
          &lt;div class="col-sm-8 col-md-6"&gt;
              {{ form_errors(form.bodytext) }}
              {{ form_widget(form.bodytext) }}
          &lt;/div&gt;
      &lt;/div&gt;
  {{ form_end(form) }}
  </code></pre>
  
  <p>NewsType (excerpt):</p>
  
  <pre><code>class NewsType extends AbstractType
  {
      public function buildForm(FormBuilderInterface $builder, array $options) {
          $builder
              -&gt;add('newsArticle', CollectionType::class, array(
                  'entry_type'   =&gt; NewsArticleType::class,
                  'allow_add'   =&gt; true,
                  'allow_delete'   =&gt; true,
              ))
      }
  
      public function configureOptions(OptionsResolver $resolver) {
          $resolver-&gt;setDefaults(array(
              'data_class' =&gt; 'Bundle\Entity\News',
          ));
      }
  }
  </code></pre>
  
  <p>NewsArticleType (excerpt):</p>
  
  <pre><code>class NewsArticleType extends AbstractType
  {
      public function buildForm(FormBuilderInterface $builder, array $options) {
          $builder
              -&gt;add('headline', TextType::class, array(
                  'required' =&gt; false,
              ))
              -&gt;add('subheadline', TextType::class, array(
                  'required' =&gt; false,
              ))
              -&gt;add('bodytext', CKEditorType::class, array(
                  'required' =&gt; false,
              ))
          ;
      }
  
      public function configureOptions(OptionsResolver $resolver) {
          $resolver-&gt;setDefaults(array(
              'data_class' =&gt; 'Bundle\Entity\NewsArticle',
          ));
      }
  }
  </code></pre>
  
  <p>Unfortunately I get an error message...</p>
  
  <blockquote>
    <p>Neither the property "headline" nor one of the methods "headline()", "getheadline()"/"isheadline()" or "__call()" exist and have public access in class "Symfony\Component\Form\FormView" in Bundle:_Partials:Form/news.html.twig at line 27 </p>
  </blockquote>
  
  <p>... and have no idea, how to access the attributes of the related entity? Any hints?</p>
  
  <p><em>EDIT #1:</em></p>
  
  <p>The complete 'Child'-Entity including getters/ setters:</p>
  
  <pre><code>/**
   * @ORM\Entity
   * @ORM\Table(name="news_article")
   */
  class NewsArticle {
  
      /**
       * @ORM\Column(type="integer")
       * @ORM\Id
       * @ORM\GeneratedValue(strategy="AUTO")
       */
      private $id;
  
      /**
       * @ORM\ManyToOne(targetEntity="News", inversedBy="newsArticle")
       * @ORM\JoinColumn(name="news_id", referencedColumnName="id")
       */
      private $news;
  
      /**
       * @ORM\Column(type="string", length=150, unique=false, nullable=false)
       * @Assert\NotBlank()
       */
      private $headline;
  
      /**
       * @ORM\Column(type="string", length=150, nullable=true)
       */
      private $subheadline;
  
      /**
       * @ORM\Column(type="string", length=65536, nullable=false)
       * @Assert\NotBlank()
       */
      private $bodytext;
  
      /**
       * @ORM\ManyToOne(targetEntity="Language")
       * @ORM\JoinColumn(name="language_id", referencedColumnName="id")
       */
      private $languageId;
  
  
  
      /**
       * Get id
       *
       * @return integer
       */
      public function getId()
      {
          return $this-&gt;id;
      }
  
      /**
       * Set headline
       *
       * @param string $headline
       *
       * @return NewsArticle
       */
      public function setHeadline($headline)
      {
          $this-&gt;headline = $headline;
  
          return $this;
      }
  
      /**
       * Get headline
       *
       * @return string
       */
      public function getHeadline()
      {
          return $this-&gt;headline;
      }
  
      /**
       * Set subheadline
       *
       * @param string $subheadline
       *
       * @return NewsArticle
       */
      public function setSubheadline($subheadline)
      {
          $this-&gt;subheadline = $subheadline;
  
          return $this;
      }
  
      /**
       * Get subheadline
       *
       * @return string
       */
      public function getSubheadline()
      {
          return $this-&gt;subheadline;
      }
  
      /**
       * Set bodytext
       *
       * @param string $bodytext
       *
       * @return NewsArticle
       */
      public function setBodytext($bodytext)
      {
          $this-&gt;bodytext = $bodytext;
  
          return $this;
      }
  
      /**
       * Get bodytext
       *
       * @return string
       */
      public function getBodytext()
      {
          return $this-&gt;bodytext;
      }
  
      /**
       * Set news
       *
       * @param \Bundle\Entity\News $news
       *
       * @return NewsArticle
       */
      public function setNews(\Bundle\Entity\News $news = null)
      {
          $this-&gt;news = $news;
  
          return $this;
      }
  
      /**
       * Get news
       *
       * @return \Bundle\Entity\News
       */
      public function getNews()
      {
          return $this-&gt;news;
      }
  
      /**
       * Set languageId
       *
       * @param \Bundle\Entity\Language $languageId
       *
       * @return NewsArticle
       */
      public function setLanguageId(\Bundle\Entity\Language $languageId = null)
      {
          $this-&gt;languageId = $languageId;
  
          return $this;
      }
  
      /**
       * Get languageId
       *
       * @return \Bundle\Entity\Language
       */
      public function getLanguageId()
      {
          return $this-&gt;languageId;
      }
  }
  </code></pre>
  
  <p>The getters and setters for the attributes exist, but I wonder why the error message misses the method <strong>get<em>h</em>eadline()</strong> instead of <strong>get<em>H</em>eadline()</strong>? Could it be, the problem is a wrong syntax in the TWIG: {{ form_errors(form.headline) }} ? I've tried {{ form_errors(form.newsArticle.headline) }} too, but the error message remains the same.</p>
  
  <p>Any hints, please?</p>