title: Symfony 3 form collection Call to a member function add() on a non-object
body: <p>i'm trying to understand how to work with form collections in sf 3 but i'm having trouble following the tutorial from sf website because it hits me with an error and i kind manage understanding what i'm doing wrong and i hope you can help me out.</p>
  
  <p>Offer Entity</p>
  
  <pre><code>&lt;?php
  
  namespace Zenith\OfferGeneratorBundle\Entity;
  
  use Doctrine\ORM\Mapping as ORM;
  
  use Gedmo\Mapping\Annotation as Gedmo;
  use Doctrine\Common\Collections\ArrayCollection;
  use Zenith\productsBundle\Entity\products;
  /**
   * Offer
   *
   * @ORM\Table(name="offer")
   * @ORM\Entity(repositoryClass="Zenith\OfferGeneratorBundle\Repository\OfferRepository")
   */
  class Offer
  {
      /**
       * @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\ManyToMany(targetEntity="ProductCollection", inversedBy="offer", cascade={"persist"})
       */
      private $products;
  
  
      /**
       * @var \DateTime
       *
       * @Gedmo\Timestampable(on="create")
       * @ORM\Column(name="createdAt", type="datetime")
       */
      private $createdAt;
  
      /**
       * @var \DateTime
       *
       * @Gedmo\Timestampable(on="update")
       * @ORM\Column(name="modifiedAt", type="datetime")
       */
      private $modifiedAt;
  
      /**
       * Get id
       *
       * @return integer
       */
      public function getId()
      {
          return $this-&gt;id;
      }
  
      /**
       * Set name
       *
       * @param string $name
       *
       * @return Offer
       */
      public function setName($name)
      {
          $this-&gt;name = $name;
  
          return $this;
      }
  
      /**
       * Get name
       *
       * @return string
       */
      public function getName()
      {
          return $this-&gt;name;
      }
  
      /**
       * Set createdAt
       *
       * @param \DateTime $createdAt
       *
       * @return Offer
       */
      public function setCreatedAt($createdAt)
      {
          $this-&gt;createdAt = $createdAt;
  
          return $this;
      }
  
      /**
       * Get createdAt
       *
       * @return \DateTime
       */
      public function getCreatedAt()
      {
          return $this-&gt;createdAt;
      }
  
      /**
       * Set modifiedAt
       *
       * @param \DateTime $modifiedAt
       *
       * @return Offer
       */
      public function setModifiedAt($modifiedAt)
      {
          $this-&gt;modifiedAt = $modifiedAt;
  
          return $this;
      }
  
      /**
       * Get modifiedAt
       *
       * @return \DateTime
       */
      public function getModifiedAt()
      {
          return $this-&gt;modifiedAt;
      }
  
      /**
       * Add product
       *
       * @param \Zenith\OfferGeneratorBundle\Entity\ProductCollection $product
       *
       * @return Offer
       */
      public function addProduct(ProductCollection $product)
      {
          $product-&gt;addOffer($this);
  
          $this-&gt;products-&gt;add($product);
      }
  
      /**
       * Remove product
       *
       * @param \Zenith\OfferGeneratorBundle\Entity\ProductCollection $product
       */
      public function removeProduct(\Zenith\OfferGeneratorBundle\Entity\ProductCollection $product)
      {
          $this-&gt;products-&gt;removeElement($product);
      }
  
      /**
       * Get products
       *
       * @return \Doctrine\Common\Collections\Collection
       */
      public function getProducts()
      {
          return $this-&gt;products;
      }
  }
  </code></pre>
  
  <p>ProductCollection Entity</p>
  
  <pre><code>&lt;?php
  
  namespace Zenith\OfferGeneratorBundle\Entity;
  
  use Doctrine\ORM\Mapping as ORM;
  
  /**
   * Product
   *
   * @ORM\Table(  )
   * @ORM\Entity(repositoryClass="Zenith\OfferGeneratorBundle\Repository\ProductRepository")
   */
  class ProductCollection
  {
      /**
       * @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 int
       *
       * @ORM\Column(name="price", type="integer")
       */
      private $price;
  
      /**
       * @var int
       *
       * @ORM\Column(name="quantity", type="integer")
       */
      private $quantity;
  
      /**
       * @var  string
       *
       * @ORM\ManyToMany(targetEntity="Offer", mappedBy="products")
       */
      private $offer;
  
      /**
       * @var int
       *
       * @ORM\ManyToMany(targetEntity="Zenith\ProductBundle\Entity\Product")
       */
      private $product;
      /**
       * Constructor
       */
      public function __construct()
      {
          $this-&gt;offer = new \Doctrine\Common\Collections\ArrayCollection();
          $this-&gt;product = new \Doctrine\Common\Collections\ArrayCollection();
      }
  
      /**
       * Get id
       *
       * @return integer
       */
      public function getId()
      {
          return $this-&gt;id;
      }
  
      /**
       * Set name
       *
       * @param string $name
       *
       * @return ProductCollection
       */
      public function setName($name)
      {
          $this-&gt;name = $name;
  
          return $this;
      }
  
      /**
       * Get name
       *
       * @return string
       */
      public function getName()
      {
          return $this-&gt;name;
      }
  
      /**
       * Set price
       *
       * @param integer $price
       *
       * @return ProductCollection
       */
      public function setPrice($price)
      {
          $this-&gt;price = $price;
  
          return $this;
      }
  
      /**
       * Get price
       *
       * @return integer
       */
      public function getPrice()
      {
          return $this-&gt;price;
      }
  
      /**
       * Set quantity
       *
       * @param integer $quantity
       *
       * @return ProductCollection
       */
      public function setQuantity($quantity)
      {
          $this-&gt;quantity = $quantity;
  
          return $this;
      }
  
      /**
       * Get quantity
       *
       * @return integer
       */
      public function getQuantity()
      {
          return $this-&gt;quantity;
      }
  
      /**
       * Add offer
       *
       * @param \Zenith\OfferGeneratorBundle\Entity\Offer $offer
       *
       * @return ProductCollection
       */
      public function addOffer(\Zenith\OfferGeneratorBundle\Entity\Offer $offer)
      {
          if (!$this-&gt;offer-&gt;contains($offer)) {
              $this-&gt;offer-&gt;add($offer);
          }
      }
  
      /**
       * Remove offer
       *
       * @param \Zenith\OfferGeneratorBundle\Entity\Offer $offer
       */
      public function removeOffer(\Zenith\OfferGeneratorBundle\Entity\Offer $offer)
      {
          $this-&gt;offer-&gt;removeElement($offer);
      }
  
      /**
       * Get offer
       *
       * @return \Doctrine\Common\Collections\Collection
       */
      public function getOffer()
      {
          return $this-&gt;offer;
      }
  
      /**
       * Add product
       *
       * @param \Zenith\ProductBundle\Entity\Product $product
       *
       * @return ProductCollection
       */
      public function addProduct(\Zenith\ProductBundle\Entity\Product $product)
      {
          $this-&gt;product[] = $product;
  
          return $this;
      }
  
      /**
       * Remove product
       *
       * @param \Zenith\ProductBundle\Entity\Product $product
       */
      public function removeProduct(\Zenith\ProductBundle\Entity\Product $product)
      {
          $this-&gt;product-&gt;removeElement($product);
      }
  
      /**
       * Get product
       *
       * @return \Doctrine\Common\Collections\Collection
       */
      public function getProduct()
      {
          return $this-&gt;product;
      }
  }
  </code></pre>
  
  <p>When i try to add something using the form after the submit i get the following error.</p>
  
  <pre><code>Error: Call to a member function add() on a non-object
  500 Internal Server Error - FatalErrorException
  </code></pre>
  
  <p>Stack Trace:</p>
  
  <pre><code>{
      $product-&gt;addOffer($this);
      $this-&gt;products-&gt;add($product);
  }
  /**
  </code></pre>
  
  <p>Based on one of the answers from here i changed the code and i got another error that i think it's from data transformer that i'm using on one of the fields.</p>
  
  <pre><code>&lt;?php
  
  namespace Zenith\OfferGeneratorBundle\Form\DataTransformer;
  
  use Zenith\ProductBundle\Entity\Product;
  use Doctrine\Common\Persistence\ObjectManager;
  use Symfony\Component\Form\DataTransformerInterface;
  use Symfony\Component\Form\Exception\TransformationFailedException;
  
  class ProductNameTransformer implements DataTransformerInterface
  {
      private $manager;
  
      public function __construct(ObjectManager $manager)
      {
          $this-&gt;manager = $manager;
      }
  
      /**
       * Transforms an object (issue) to a string (number).
       *
       * @param  Issue|null $issue
       * @return string
       */
      public function transform($issue)
      {
          if (null === $issue) {
  
              return '';
          }
  
          return $issue-&gt;getId();
      }
  
      /**
       * Transforms a string (number) to an object (issue).
       *
       * @param  string $issueNumber
       * @return Issue|null
       * @throws TransformationFailedException if object (issue) is not found.
       */
      public function reverseTransform($issueNumber)
      {
          // no issue number? It's optional, so that's ok
          if (!$issueNumber) {
              return;
          }
  
          $issue = $this-&gt;manager
              -&gt;getRepository('ProductBundle:Product')
              // query for the issue with this id
              -&gt;findByName($issueNumber)
          ;
  
          if (null === $issue) {
              // causes a validation error
              // this message is not shown to the user
              // see the invalid_message option
              throw new TransformationFailedException(sprintf(
                  'An issue with number "%s" does not exist!',
                  $issueNumber
              ));
          }
  
          return $issue;
      }
  }
  
  Notice: Array to string conversion
  500 Internal Server Error - ContextErrorException
  
  Stack Trace
  in vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php at line 67   -
      public function bindValue($param, $value, $type = \PDO::PARAM_STR)
      {
          try {
              return parent::bindValue($param, $value, $type);
          } catch (\PDOException $exception) {
              throw new PDOException($exception);
          }
  at ErrorHandler -&gt;handleError ('8', 'Array to string conversion', '/var/www/f.dev/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php', '67', array('param' =&gt; '1', 'value' =&gt; array(object(Product)), 'type' =&gt; '2')) 
  at PDOStatement -&gt;bindValue ('1', array(object(Product)), '2') 
  in vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php at line 67   + 
  at PDOStatement -&gt;bindValue ('1', array(object(Product)), '2') 
  in vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php at line 120   + 
  at Statement -&gt;bindValue ('1', array(object(Product)), 'string') 
  in vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php at line 277   + 
  at BasicEntityPersister -&gt;executeInserts () 
  in vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php at line 1018   + 
  at UnitOfWork -&gt;executeInserts (object(ClassMetadata)) 
  in vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php at line 378   + 
  at UnitOfWork -&gt;commit (null) 
  in vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php at line 356   + 
  at EntityManager -&gt;flush () 
  in src/Zenith/OfferGeneratorBundle/Controller/OfferController.php at line 118   + 
  at OfferController -&gt;newOfferSubmitedAction (object(Request)) 
  at call_user_func_array (array(object(OfferController), 'newOfferSubmitedAction'), array(object(Request))) 
  in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php at line 139   + 
  at HttpKernel -&gt;handleRaw (object(Request), '1') 
  in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php at line 62   + 
  at HttpKernel -&gt;handle (object(Request), '1', true) 
  in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php at line 169   + 
  at Kernel -&gt;handle (object(Request)) 
  in web/app_dev.php at line 30   + 
  </code></pre>