title: ZF2 and Doctrine2: One form -> Two entities
body: <p>I would like to make one form in which I could have elements to populate two entities.
  How can I do that? One of the objects is mapped to the other one.
  For example I have something like this:</p>
  
  <p>Table user:</p>
  
  <pre><code>id | login | password
  </code></pre>
  
  <p>Table user_email:</p>
  
  <pre><code>id | user_id | email 
  </code></pre>
  
  <p>There can be more than one row user_email mapped to user - user can have more than one email.
  But - when I'm adding first occurrence of the user I have to get his first email.</p>
  
  <p>I know everything how to map entities but I have problem with populating objects from ZF2 form.</p>
  
  <p>Can anyone suggest how should I do this? I've tried to make two fieldsets but I cannot bind object to fieldset. If this is the solution how bind objects to form which have two filedsets? Every fieldset have mapped doctrine2 hydrator but when I'm trying to bind one of the entity to form (not fieldset which i cannot do) I have error message:</p>
  
  <pre><code>Zend\Stdlib\Hydrator\ArraySerializable::extract expects the provided object to implement getArrayCopy()
  </code></pre>
  
  <p>Before my example I have to explan what i want to achieve. I have a table cameras - which contain link and some other information about streaming cameras. Second table: cameras_desc contain descriptions to those cameras in different languages. In my CMS i want to add two rows: one in cameras and second in cmaeras_desc in one form. cameras_desc will have first translation in polish language (which would be default language for CMS). As u can see cameras and cameras_desc are mapped with some other entites (cameras with checkpoints and cameras_desc with languages). but thats not a point. What i want to achieve is to populate two rows in two tables by one form. lang in cameras_desc is set by PHP code, but checkpoint is set by user in form by select element. everything works in code below but it isnt made honestly.</p>
  
  <p>This is my code:</p>
  
  <p>First entity:
      
  
  <pre><code>namespace Granica\Entity;
  
  use Doctrine\ORM\Mapping as ORM;
  
  /**
   * Cameras
   *
   * @ORM\Table(name="cameras", indexes={@ORM\Index(name="IDX_6B5F276AF27C615F", columns={"checkpoint_id"})})
   * @ORM\Entity
   */
  class Cameras
  {
      /**
       * @var integer
       *
       * @ORM\Column(name="id", type="integer", nullable=false)
       * @ORM\Id
       * @ORM\GeneratedValue(strategy="IDENTITY")
       */
      private $id;
  
      /**
       * @var string
       *
       * @ORM\Column(name="link", type="text", nullable=false)
       */
      private $link;
  
      /**
       * @var string
       *
       * @ORM\Column(name="direction", type="string", length=4, nullable=false)
       */
      private $direction;
  
      /**
       * @var \Granica\Entity\Checkpoints
       *
       * @ORM\ManyToOne(targetEntity="Granica\Entity\Checkpoints")
       * @ORM\JoinColumns({
       *   @ORM\JoinColumn(name="checkpoint_id", referencedColumnName="id")
       * })
       */
      private $checkpoint;
  
  
  
      /**
       * Get id
       *
       * @return integer 
       */
      public function getId()
      {
          return $this-&gt;id;
      }
  
      /**
       * Set link
       *
       * @param string $link
       * @return Cameras
       */
      public function setLink($link)
      {
          $this-&gt;link = $link;
  
          return $this;
      }
  
      /**
       * Get link
       *
       * @return string 
       */
      public function getLink()
      {
          return $this-&gt;link;
      }
  
      /**
       * Set direction
       *
       * @param string $direction
       * @return Cameras
       */
      public function setDirection($direction)
      {
          $this-&gt;direction = $direction;
  
          return $this;
      }
  
      /**
       * Get direction
       *
       * @return string 
       */
      public function getDirection()
      {
          return $this-&gt;direction;
      }
  
      /**
       * Set checkpoint
       *
       * @param \Granica\Entity\Checkpoints $checkpoint
       * @return Cameras
       */
      public function setCheckpoint(\Granica\Entity\Checkpoints $checkpoint = null)
      {
          $this-&gt;checkpoint = $checkpoint;
  
          return $this;
      }
  
      /**
       * Get checkpoint
       *
       * @return \Granica\Entity\Checkpoints 
       */
      public function getCheckpoint()
      {
          return $this-&gt;checkpoint;
      }
  }
  </code></pre>
  
  <p>Second entity:</p>
  
  <pre><code>&lt;?php
  
  namespace Granica\Entity;
  
  use Doctrine\ORM\Mapping as ORM;
  
  /**
   * CamerasDesc
   *
   * @ORM\Table(name="camera_desc", indexes={@ORM\Index(name="lang", columns={"lang"}), @ORM\Index(name="camera_id", columns={"camera_id"})})
   * @ORM\Entity
   */
  class CameraDesc
  {
      /**
       * @var integer
       *
       * @ORM\Column(name="id", type="integer", nullable=false)
       * @ORM\Id
       * @ORM\GeneratedValue(strategy="IDENTITY")
       */
      private $id;
  
      /**
       * @var string
       *
       * @ORM\Column(name="description", type="text", nullable=false)
       */
      private $description;
  
      /**
       * @var \Granica\Entity\Languages
       *
       * @ORM\ManyToOne(targetEntity="Granica\Entity\Languages")
       * @ORM\JoinColumns({
       *   @ORM\JoinColumn(name="lang", referencedColumnName="id")
       * })
       */
      private $lang;
  
      /**
       * @var \Granica\Entity\Cameras
       *
       * @ORM\ManyToOne(targetEntity="Granica\Entity\Cameras")
       * @ORM\JoinColumns({
       *   @ORM\JoinColumn(name="camera_id", referencedColumnName="id")
       * })
       */
      private $camera;
  
  
  
      /**
       * Get id
       *
       * @return integer 
       */
      public function getId()
      {
          return $this-&gt;id;
      }
  
      /**
       * Set description
       *
       * @param string $description
       * @return CamerasDesc
       */
      public function setDescription($description)
      {
          $this-&gt;description = $description;
  
          return $this;
      }
  
      /**
       * Get description
       *
       * @return string 
       */
      public function getDescription()
      {
          return $this-&gt;description;
      }
  
      /**
       * Set lang
       *
       * @param \Granica\Entity\Languages $lang
       * @return CamerasDesc
       */
      public function setLang(\Granica\Entity\Languages $lang = null)
      {
          $this-&gt;lang = $lang;
  
          return $this;
      }
  
      /**
       * Get lang
       *
       * @return \Granica\Entity\Languages 
       */
      public function getLang()
      {
          return $this-&gt;lang;
      }
  
      /**
       * Set camera
       *
       * @param \Granica\Entity\Cameras $camera
       * @return CamerasDesc
       */
      public function setCamera(\Granica\Entity\Cameras $camera = null)
      {
          $this-&gt;camera = $camera;
  
          return $this;
      }
  
      /**
       * Get camera
       *
       * @return \Granica\Entity\Cameras 
       */
      public function getCamera()
      {
          return $this-&gt;camera;
      }
  }
  </code></pre>
  
  <p>Fieldset ( for camera_desc  ):
      
  
  <pre><code>namespace Granica\Form;
  
  use Zend\Form\Fieldset;
  
  use DoctrineModule\Persistence\ObjectManagerAwareInterface;
  use Doctrine\Common\Persistence\ObjectManager;
  use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
  use DoctrineORMModule\Stdlib\Hydrator\DoctrineEntity;
  
  use Granica\Entity\Languages;
  
  class CameraDescFieldset extends Fieldset implements ObjectManagerAwareInterface
  {
      protected $objectManager;
      public function __construct(ObjectManager $objectManager)
      {
          parent::__construct('camera_desc');
          $this-&gt;setObjectManager($objectManager);
          $this-&gt;setHydrator(new DoctrineHydrator($this-&gt;getObjectManager(),'Granica\Entity\CameraDesc'));        
  
          $this-&gt;add(array(
              'name' =&gt; 'description',
              'attributes' =&gt; array(
                  'type'  =&gt; 'text',
                  'placeholder' =&gt; 'Opis',
                  'required' =&gt; 'true',
              ),
              'options' =&gt; array(
                  'label' =&gt; 'Opis kamery',
              ),
          ));
  
      }
  
      // implementacja interfajsu objectmanager
      public function setObjectManager(ObjectManager $objectManager)
      {
          $this-&gt;objectManager = $objectManager;
          return $this;
      }
  
      public function getObjectManager()
      {
          return $this-&gt;objectManager;
      }
  
  }
  </code></pre>
  
  <p>Form (for camera):
      
  
  <pre><code>use Zend\Form\Form;
  
  use DoctrineModule\Persistence\ObjectManagerAwareInterface;
  use Doctrine\Common\Persistence\ObjectManager;
  
  use Granica\Form\CameraDescFieldset;
  
  class AddCameraForm extends Form implements ObjectManagerAwareInterface
  {
      protected $objectManager;
      public function __construct(ObjectManager $objectManager)
      {       
          parent::__construct('checkpoint');
          $this-&gt;setObjectManager($objectManager);
  
          // tworzenie formularza
          $this-&gt;setAttribute('method', 'post');
  
          $this-&gt;add(array(
              'name'    =&gt; 'checkpoint',
              'type'    =&gt; 'DoctrineModule\Form\Element\ObjectSelect',
              'options' =&gt; array(
                  'label'          =&gt; 'Punkt graniczny',
                  'object_manager' =&gt; $this-&gt;getObjectManager(),
                  'target_class'   =&gt; 'Granica\Entity\Checkpoints',
                  'property'       =&gt; 'name',
                  'empty_option'   =&gt; '--- wybierz przejście ---'
              ),
          ));
  
          $this-&gt;add(array(
              'name' =&gt; 'link',
              'attributes' =&gt; array(
                  'type'  =&gt; 'text',
                  'placeholder' =&gt; 'Link',
                  'required' =&gt; 'true',
              ),
              'options' =&gt; array(
                  'label' =&gt; 'Adres URL kamery',
              ),
          ));
  
          $this-&gt;add(array(
              'type' =&gt; 'Zend\Form\Element\Select',
              'name' =&gt; 'direction',
              'attributes' =&gt; array(
                  'required' =&gt; 'true',
              ),
              'options' =&gt; array(
                  'label' =&gt; 'Kierunek',
                  'empty_option' =&gt; '--- wybierz kierunek ---',
                  'value_options' =&gt; array(
                      'from' =&gt; 'FROM: Wyjazd z Polski',
                      'to' =&gt;   'TO:   Wjazd do Polski',
                  ),
              )
          ));               
  
          $this-&gt;add(new CameraDescFieldset($this-&gt;getObjectManager()));
  
          $this-&gt;add(array(
              'name' =&gt; 'submit',
              'attributes' =&gt; array(
                  'type'  =&gt; 'submit',
                  'value' =&gt; 'Zapisz',
                  'id' =&gt; 'submitbutton',
              ),
          )); 
      }
  
      // implementacja interfajsu objectmanager
      public function setObjectManager(ObjectManager $objectManager)
      {
          $this-&gt;objectManager = $objectManager;
          return $this;
      }
  
      public function getObjectManager()
      {
          return $this-&gt;objectManager;
      }       
  
  }
  </code></pre>
  
  <p>And the add controller:</p>
  
  <pre><code>public function addAction()
  {
      $camera = new Cameras();
      $cameraDesc = new CameraDesc();
      $lang = $this-&gt;getEntityManager()-&gt;getRepository('Granica\Entity\Languages')-&gt;find('pl');
  
      $form = new AddCameraForm($this-&gt;getEntityManager());
      $cameraDescFieldset = new CameraDescFieldset($this-&gt;getEntityManager());
  
      $form-&gt;setHydrator(new DoctrineHydrator($this-&gt;getEntityManager(),'Granica\Entity\Cameras'));
  
      $form-&gt;bind($camera);
  
      $request = $this-&gt;getRequest();
      if ($request-&gt;isPost()) {
          $form-&gt;setData($request-&gt;getPost());
          if ($form-&gt;isValid()) {
              $data = $form-&gt;getData(); 
              $cameraDesc-&gt;setLang($lang);
              $cameraDesc-&gt;setDescription($request-&gt;getPost()['camera_desc']['description']);
  
              $this-&gt;getEntityManager()-&gt;persist($camera);            
  
              $cameraDesc-&gt;setCamera($camera);            
  
              $this-&gt;getEntityManager()-&gt;persist($cameraDesc);            
              $this-&gt;getEntityManager()-&gt;flush();
  
              return $this-&gt;redirect()-&gt;toRoute('cameras');
          }
      }
  
      return new ViewModel(array('form' =&gt; $form));
  }  
  </code></pre>
  
  <p>As you can see I've managed to overcome my problem - I've populate camera_desc with data which I get from post. This work but isn't the best solution - for example filters didn't work on cameraDesc descrition.</p>