title: Symfony FOS Rest Bundle Api Call Many to Many Relationship
body: <p>I seem to have an issue. And I'm sure it has a really simple fix. I have an API which uses FOS Rest bundle. I have a call which sends a POST request to postCreateTimesheetAction( Request $request ) which creates an empty row in the Timesheet Table. I have another call patchTimesheetAction which laters adds some data to the table. Okay all is well. I have another call patchCareoptionAction( Timesheet $timesheet ) which creates a row in a table which has a many to many relationship built from CareOptions.php(below) and Timesheet.php(below). All the api calls work good and function as they should. I will post them below here:</p>
  
  <p>creates a blank new timesheet row in the Timesheet table: (Timesheet.php)</p>
  
  <p>curl -H "Accept: application/json" -H "Content-type: application/json" -i -X POST -d '{"homecare_homecarebundle_timesheet":""}' www.hc-timesheets-demo.com/app_dev.php/api/v1/create/timesheet</p>
  
  <p>updates the timesheet row with data:</p>
  
  <p>curl -i -H "Accept: application/json" -H "Content-type: application/json" -d '{"homecare_homecarebundle_timesheet":{"agency":"157","recipient":"154","pca":"16","service":"6"}}' -X PATCH  www.hc-timesheets-demo.com/app_dev.php/api/v1/timesheet/31</p>
  
  <p>and finally creates the many to many relationship:</p>
  
  <p>curl -i -H "Accept: application/json" -H "Content-type: application/json" -d '{"homecare_homecarebundle_timesheet":{"careOption":[456,457] }}' -X PATCH  www.hc-timesheets-demo.com/app_dev.php/api/v1/careoption/31</p>
  
  <p>notice the 31 at the end of the patch request. That is the id of the timesheet created in the table from the first api call. So lets get to my question! Whenever i call the 3rd api call i successfully create the many to many rows in the table. But when i call it again it does not replace the old rows with the new ones. It just adds more rows to the table. I want the many to many table rows to be updated and the old ones gone. Do i need to delete them out first? Let me explain a little more. If you see in the 3rd api call I'm adding 2 careOptions to the timesheet: (careOptions 456 and 457). Well if I call it again, and lets say I want to add 458 and 459. I want 456 and 457 to automatically delete and be gone. Please someone help me out??!!</p>
  
  <p>Here is the owning side of the many to many relationship</p>
  
  <pre><code>&lt;?php
  //src/Homecare/HomecareBundle/Entity/CareOptions.php
  namespace Homecare\HomecareBundle\Entity;
  
  use Doctrine\ORM\Mapping as ORM;
  use Doctrine\Common\Collections\ArrayCollection;
  
  /**
   * CareGoals
   *
   * @ORM\Table(name="careoptions")
   * @ORM\Entity(repositoryClass="Homecare\HomecareBundle\Entity\Repository\CareOptionsRepository")
   */
  class CareOptions
  {
  /**
   * @var integer
   *
   * @ORM\Column(name="id", type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="AUTO")
   */
  private $id;
  
  /**
   * @ORM\OneToMany(targetEntity="CareOptionsTimesheets", mappedBy="careOption")
       */
          private $care_options_timesheets;
  
  
  /**
   * @var string
   *
   * @ORM\Column(name="care_option", type="string", length=255)
   */
      private $careOption;
  
  
      /**
      * @ORM\ManyToMany(targetEntity="CareGoals", mappedBy="careOption")
      */
      private $careGoals;
  
  
  
  
  
      /**
      * @ORM\ManyToMany(targetEntity="Timesheet", inversedBy="careOption", cascade={"persist"})
      */
      private $timesheet;
  
  
  
  
      public function __construct()
       {
           $this-&gt;care_options_timesheets = new ArrayCollection();
  
                   $this-&gt;timesheet = new ArrayCollection();
  
       }
  
  
  
  /**
   * Get id
   *
   * @return integer 
   */
  public function getId()
  {
      return $this-&gt;id;
  }
  
  
  
  
  
  
  
      //add a to string method so that the object can be displayed in the twig template
      /*
      public function __toString()
              {
                  return $this-&gt;getCareGoal();
              }
      */
  
  
  /**
   * Set careOption
   *
   * @param string $careOption
   * @return CareOptions
   */
  public function setCareOption($careOption)
  {
      $this-&gt;careOption = $careOption;
  
      return $this;
  }
  
  /**
   * Get careOption
   *
   * @return string 
   */
  public function getCareOption()
  {
      return $this-&gt;careOption;
  }
  
  /**
   * Add care_options_timesheets
   *
   * @param \Homecare\HomecareBundle\Entity\CareOptions_Timesheets $careOptionsTimesheets
   * @return CareOptions
   */
  public function addCareOptionsTimesheet(\Homecare\HomecareBundle\Entity\CareOptionsTimesheets $careOptionsTimesheets)
  {
      $this-&gt;care_options_timesheets[] = $careOptionsTimesheets;
  
      return $this;
  }
  
  /**
   * Remove care_options_timesheets
   *
   * @param \Homecare\HomecareBundle\Entity\CareOptions_Timesheets $careOptionsTimesheets
   */
  public function removeCareOptionsTimesheet(\Homecare\HomecareBundle\Entity\CareOptionsTimesheets $careOptionsTimesheets)
  {
      $this-&gt;care_options_timesheets-&gt;removeElement($careOptionsTimesheets);
  }
  
  /**
   * Get care_options_timesheets
   *
   * @return \Doctrine\Common\Collections\Collection 
   */
  public function getCareOptionsTimesheets()
  {
      return $this-&gt;care_options_timesheets;
  }
  
  /**
   * Add careGoals
   *
   * @param \Homecare\HomecareBundle\Entity\CareGoals $careGoals
   * @return CareOptions
   */
  public function addCareGoal(\Homecare\HomecareBundle\Entity\CareGoals $careGoals)
  {
      $this-&gt;careGoals[] = $careGoals;
  
      return $this;
  }
  
  /**
   * Remove careGoals
   *
   * @param \Homecare\HomecareBundle\Entity\CareGoals $careGoals
   */
  public function removeCareGoal(\Homecare\HomecareBundle\Entity\CareGoals $careGoals)
  {
      $this-&gt;careGoals-&gt;removeElement($careGoals);
  }
  
  /**
   * Get careGoals
   *
   * @return \Doctrine\Common\Collections\Collection 
   */
  public function getCareGoals()
  {
      return $this-&gt;careGoals;
  }
  
  
  
      public function __toString() {
          return $this-&gt;getCareOption();
      }
  
  
  
  /**
   * Add timesheet
   *
   * @param \Homecare\HomecareBundle\Entity\Timesheet $timesheet
   * @return CareOptions
   */
  public function addTimesheet(\Homecare\HomecareBundle\Entity\Timesheet $timesheet)
  {
      $this-&gt;timesheet[] = $timesheet;
  
      return $this;
  }
  
  /**
   * Remove timesheet
   *
   * @param \Homecare\HomecareBundle\Entity\Timesheet $timesheet
   */
  public function removeTimesheet(\Homecare\HomecareBundle\Entity\Timesheet $timesheet)
  {
      $this-&gt;timesheet-&gt;removeElement($timesheet);
  }
  
  /**
   * Get timesheet
   *
   * @return \Doctrine\Common\Collections\Collection 
   */
  public function getTimesheet()
  {
      return $this-&gt;timesheet;
  }
  }
  </code></pre>
  
  <p>Here is the other side of the many to many relationship:</p>
  
  <pre><code>&lt;?php
  //src/Homecare/HomecareBundle/Entity/Timesheet.php
  namespace Homecare\HomecareBundle\Entity;
  
  use Doctrine\ORM\Mapping as ORM;
  use JMS\Serializer\Annotation\Type;
  use JMS\Serializer\Annotation\SerializedName;
  
  /**
   * Timesheet
   *
   * @ORM\Table(name="timesheet")
   * @ORM\Entity(repositoryClass="Homecare\HomecareBundle\Entity\Repository\TimesheetRepository")
   */
  class Timesheet
  {
  /**
   * @var integer
   *
   * @ORM\Column(name="id", type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="AUTO")
       * @Type("integer")
       * @SerializedName("id")
   */
  private $id;
  
  
  
  /**
   * @ORM\ManyToOne(targetEntity="Agency", inversedBy="actualTimesheets")
       * @ORM\JoinColumn(name="agency_id", referencedColumnName="id")
       * @Type("Homecare\HomecareBundle\Entity\Agency")
       * @SerializedName("agency")
   */
  private $agency;
  
  
  
  /**
   * @ORM\ManyToOne(targetEntity="Recipient", inversedBy="actualTimesheets")
       * @ORM\JoinColumn(name="recipient_id", referencedColumnName="id")
       * @Type("Homecare\HomecareBundle\Entity\Recipient")
       * @SerializedName("recipient")
   */
  private $recipient;
  
  
  /**
   * @ORM\ManyToOne(targetEntity="Pca", inversedBy="actualTimesheets")
       * @ORM\JoinColumn(name="pca_id", referencedColumnName="id")
       * @Type("Homecare\HomecareBundle\Entity\Pca")
       * @SerializedName("pca")
   */
  private $pca;
  
  
  /**
   * @ORM\ManyToOne(targetEntity="Services", inversedBy="actualTimesheets")
       * @ORM\JoinColumn(name="service_id", referencedColumnName="id")
       * @Type("Homecare\HomecareBundle\Entity\Services")
       * @SerializedName("service")
   */
  private $service;
  
  
  
  
  
      /**
      * @ORM\Column(name="continueTimesheetNumber",type="integer",nullable=true)
      * @Type("integer")
      * @SerializedName("continueTimesheetNumber")
      */
      private $continueTimesheetNumber;
  
  
  
  
  
      /**
      * @ORM\ManyToOne(targetEntity="VisitRatios", inversedBy="timesheets")
      * @Type("Homecare\HomecareBundle\Entity\VisitRatios")
      * @SerializedName("visitRatio")
      */
      private $visitRatio;
  
  
  
  
  
  /**
   * @ORM\ManyToOne(targetEntity="TimeIn", inversedBy="timesheets")
       * @Type("Homecare\HomecareBundle\Entity\TimeIn")
       * @SerializedName("timeIn")
   */
  private $timeIn;
  
  
  
  
  /**
   * @ORM\ManyToOne(targetEntity="TimeOut", inversedBy="timesheets")
       * @Type("Homecare\HomecareBundle\Entity\TimeOut")
       * @SerializedName("timeOut")
   */
  private $timeOut;
  
  
  
  
  
  /**
   * @ORM\ManyToOne(targetEntity="Files", inversedBy="timesheets")
       * @Type("Homecare\HomecareBundle\Entity\Files")
       * @SerializedName("file")
   */
  private $file;
  
  
  
      /**
      * @ORM\ManyToMany(targetEntity="CareOptions", mappedBy="timesheet", cascade={"persist"})
      * @Type("Homecare\HomecareBundle\Entity\CareOptions")
      * @SerializedName("careOption")
      */
      private $careOption;
  
  
  
  
  /**
   * Get id
   *
   * @return integer 
   */
  public function getId()
  {
      return $this-&gt;id;
  }
  
  
  
  
  /**
   * Set agency
   *
   * @param \Homecare\HomecareBundle\Entity\Agency $agency
   * @return Timesheet
   */
  public function setAgency(\Homecare\HomecareBundle\Entity\Agency $agency = null)
  {
      $this-&gt;agency = $agency;
  
      return $this;
  }
  
  /**
   * Get agency
   *
   * @return \Homecare\HomecareBundle\Entity\Agency 
   */
  public function getAgency()
  {
      return $this-&gt;agency;
  }
  
  /**
   * Set recipient
   *
   * @param \Homecare\HomecareBundle\Entity\Recipient $recipient
   * @return Timesheet
   */
  public function setRecipient(\Homecare\HomecareBundle\Entity\Recipient $recipient = null)
  {
      $this-&gt;recipient = $recipient;
  
      return $this;
  }
  
  /**
   * Get recipient
   *
   * @return \Homecare\HomecareBundle\Entity\Recipient 
   */
  public function getRecipient()
  {
      return $this-&gt;recipient;
  }
  
  /**
   * Set pca
   *
   * @param \Homecare\HomecareBundle\Entity\Pca $pca
   * @return Timesheet
   */
  public function setPca(\Homecare\HomecareBundle\Entity\Pca $pca = null)
  {
      $this-&gt;pca = $pca;
  
      return $this;
  }
  
  /**
   * Get pca
   *
   * @return \Homecare\HomecareBundle\Entity\Pca 
   */
  public function getPca()
  {
      return $this-&gt;pca;
  }
  
  /**
   * Set service
   *
   * @param \Homecare\HomecareBundle\Entity\Services $service
   * @return Timesheet
   */
  public function setService(\Homecare\HomecareBundle\Entity\Services $service = null)
  {
      $this-&gt;service = $service;
  
      return $this;
  }
  
  /**
   * Get service
   *
   * @return \Homecare\HomecareBundle\Entity\Services 
   */
  public function getService()
  {
      return $this-&gt;service;
  }
  
  
  
  
  /**
   * Set continueTimesheetNumber
   *
   * @param integer $continueTimesheetNumber
   * @return Timesheet
   */
  public function setContinueTimesheetNumber($continueTimesheetNumber)
  {
      $this-&gt;continueTimesheetNumber = $continueTimesheetNumber;
  
      return $this;
  }
  
  /**
   * Get continueTimesheetNumber
   *
   * @return integer 
   */
  public function getContinueTimesheetNumber()
  {
      return $this-&gt;continueTimesheetNumber;
  }
  
  /**
   * Set visitRatio
   *
   * @param \Homecare\HomecareBundle\Entity\VisitRatios $visitRatio
   * @return Timesheet
   */
  public function setVisitRatio(\Homecare\HomecareBundle\Entity\VisitRatios $visitRatio = null)
  {
      $this-&gt;visitRatio = $visitRatio;
  
      return $this;
  }
  
  /**
   * Get visitRatio
   *
   * @return \Homecare\HomecareBundle\Entity\VisitRatios 
   */
  public function getVisitRatio()
  {
      return $this-&gt;visitRatio;
  }
  
  /**
   * Set timeIn
   *
   * @param \Homecare\HomecareBundle\Entity\TimeIn $timeIn
   * @return Timesheet
   */
  public function setTimeIn(\Homecare\HomecareBundle\Entity\TimeIn $timeIn = null)
  {
      $this-&gt;timeIn = $timeIn;
  
      return $this;
  }
  
  /**
   * Get timeIn
   *
   * @return \Homecare\HomecareBundle\Entity\TimeIn 
   */
  public function getTimeIn()
  {
      return $this-&gt;timeIn;
  }
  
  /**
   * Set timeOut
   *
   * @param \Homecare\HomecareBundle\Entity\TimeOut $timeOut
   * @return Timesheet
   */
  public function setTimeOut(\Homecare\HomecareBundle\Entity\TimeOut $timeOut = null)
  {
      $this-&gt;timeOut = $timeOut;
  
      return $this;
  }
  
  /**
   * Get timeOut
   *
   * @return \Homecare\HomecareBundle\Entity\TimeOut 
   */
  public function getTimeOut()
  {
      return $this-&gt;timeOut;
  }
  
  /**
   * Set file
   *
   * @param \Homecare\HomecareBundle\Entity\Files $file
   * @return Timesheet
   */
  public function setFile(\Homecare\HomecareBundle\Entity\Files $file = null)
  {
      $this-&gt;file = $file;
  
      return $this;
  }
  
  /**
   * Get file
   *
   * @return \Homecare\HomecareBundle\Entity\Files 
   */
  public function getFile()
  {
      return $this-&gt;file;
  }
  /**
   * Constructor
   */
  public function __construct()
  {
      $this-&gt;careOption = new \Doctrine\Common\Collections\ArrayCollection();
  }
  
  
  
  
  /**
   * Add careOption
   *
   * @param \Homecare\HomecareBundle\Entity\CareOptions $careOption
   * @return Timesheet
   */
  public function addCareOption(\Homecare\HomecareBundle\Entity\CareOptions $careOption)
  {
  
            $careOption-&gt;addTimesheet( $this );
  
      $this-&gt;careOption[] = $careOption;
  
      return $this;
  }
  
  /**
   * Remove careOption
   *
   * @param \Homecare\HomecareBundle\Entity\CareOptions $careOption
   */
  public function removeCareOption(\Homecare\HomecareBundle\Entity\CareOptions $careOption)
  {
      $this-&gt;careOption-&gt;removeElement($careOption);
  }
  
  /**
   * Get careOption
   *
   * @return \Doctrine\Common\Collections\Collection 
   */
  public function getCareOption()
  {
      return $this-&gt;careOption;
  }
  }
  </code></pre>
  
  <p>Here is the formBuilder TimesheetType.php</p>
  
  <pre><code>&lt;?php
  //src/Homecare/HomecareBundle/Form/TimesheetType.php
  namespace Homecare\HomecareBundle\Form;
  
  use Symfony\Component\Form\AbstractType;
  use Symfony\Component\Form\FormBuilderInterface;
  use Symfony\Component\OptionsResolver\OptionsResolverInterface;
  
   class TimesheetType extends AbstractType
  {
  /**
   * @param FormBuilderInterface $builder
   * @param array $options
   */
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
      $builder
          -&gt;add('agency')
          -&gt;add('recipient')
          -&gt;add('pca')
          -&gt;add('service')
                      -&gt;add('continueTimesheetNumber')
                      -&gt;add('visitRatio')
                      -&gt;add('timeIn')
                      -&gt;add('timeOut')
      ;
  
              $builder-&gt;add('careOption', 'entity', array(
                  'class' =&gt; 'HomecareHomecareBundle:CareOptions',
                  'property' =&gt; 'careOption',
                      'expanded' =&gt; true,
                      'multiple' =&gt; true,
                      'label' =&gt; false,
                      'by_reference' =&gt; false,
  
              ));
  
  }
  
  /**
   * @param OptionsResolverInterface $resolver
   */
  public function setDefaultOptions(OptionsResolverInterface $resolver)
  {
      $resolver-&gt;setDefaults(array(
          'data_class' =&gt; 'Homecare\HomecareBundle\Entity\Timesheet',
                      'csrf_protection'   =&gt; false,
      ));
  }
  
  /**
   * @return string
   */
  public function getName()
  {
      return 'homecare_homecarebundle_timesheet';
  }
  }
  </code></pre>
  
  <p>Here are the ApiControllers: </p>
  
  <pre><code>&lt;?php
  //src/Homecare/HomecareApiBundle/Controller/TimesheetApiController.php
  namespace Homecare\HomecareApiBundle\Controller;
  
  use Symfony\Bundle\FrameworkBundle\Controller\Controller;
  
  use FOS\RestBundle\Controller\Annotations\View;
  use Symfony\Component\HttpFoundation\Response;
  use Symfony\Component\HttpFoundation\Request;
  use Homecare\HomecareBundle\Entity\Timesheet;
  use Homecare\HomecareBundle\Entity\Services;
  use Homecare\HomecareBundle\Entity\CareOptions;
  use Homecare\HomecareBundle\Form\TimesheetType;
  use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  use JMS\Serializer\SerializerBuilder;
  use FOS\RestBundle\View\View as V;
  use Doctrine\Common\Collections\ArrayCollection;
  
  
  class TimesheetApiController extends Controller
  {
  
  
  
  
  /**
  * @View()
  */
  public function patchCareoptionAction( Timesheet $timesheet )
  {
  
      return $this-&gt;updateTimesheetForm( $timesheet );
  
      }
  
  
  
  
  
  
  
  
  
  /**
  * @View()
  */
  public function postCreateTimesheetAction( Request $request )
  {
  
          return $this-&gt;createTimesheetForm( $request, new Timesheet() );
  
      }
  
  
  
  
  
  
  
  
  
      /**
      * @View()
      */
      public function patchTimesheetAction( Timesheet $timesheet )
      {
  
          return $this-&gt;updateTimesheetForm( $timesheet );
  
          }
  
  
  
  
  
  
  
          private function setMethod( $statusCode, $timesheet = null ){
  
             switch( $statusCode ) {
  
                  case 201:
                  return array( 'method' =&gt; 'POST' );
                  break;
  
                  case 204:
                  return array( 
                      'action' =&gt; $this-&gt;generateUrl('patch_timesheet', array('timesheet' =&gt; $timesheet-&gt;getId())),
                      'method' =&gt; 'PATCH' 
                  );
                  break;
  
              }
  
          }
  
  
  
  
  
  
  
              /**
              * @View()
              */
              private function updateTimesheetForm( Timesheet $timesheet)
                  {
  
  
  
                      $statusCode = 204;
  
                      $form = $this-&gt;createForm(new TimesheetType(), $timesheet, $this-&gt;setMethod( $statusCode, $timesheet ) );
  
  
  
                           $form-&gt;handleRequest( $this-&gt;getRequest() );
  
  
                      if ($form-&gt;isValid()) {
  
  
                                  $em = $this-&gt;getDoctrine()-&gt;getManager();
  
  
                                  //$careOption = $em-&gt;getRepository( "HomecareHomecareBundle:CareOptions" )-&gt;findOneById(456);
  
  
                                  //$timesheet-&gt;addCareOption( $careOption );
  
                                  $em-&gt;persist( $timesheet );
                      $em-&gt;flush();
  
                          $response = new Response();
                          $response-&gt;setStatusCode( $statusCode );
  
  
                          return $response;
                      }
  
                      return V::create($form, 400);
                  }
  
  
  
  
  
  
  
  
  
                      /**
                      * @View()
                      */
                    private function createTimesheetForm( $request, Timesheet $timesheet )
                       {
  
  
                                $statusCode = 201;
  
                                  $form = $this-&gt;createForm( new TimesheetType(), $timesheet, $this-&gt;setMethod( $statusCode ) );
  
  
                           $form-&gt;handleRequest( $this-&gt;getRequest() );
  
                           if ( $form-&gt;isValid() ) {
                               //$user-&gt;save();
  
                                           //$timesheet = $form-&gt;getData();
  
                               $response = new Response();
                               $response-&gt;setStatusCode(201);
  
  
                                          $em = $this-&gt;getDoctrine()-&gt;getManager();
                                          $em-&gt;persist( $timesheet );
                              $em-&gt;flush();
  
  
  
  
                         //return V::create($form, 201);
                               //return $response;
  
                               //return array( $form, array("timesheet" =&gt; array("id" =&gt; $timesheet-&gt;getId() ) ) );
  
  
  
       return V::create( array("createdTimesheet" =&gt; array("id" =&gt; $timesheet-&gt;getId() ) ), $statusCode );
  
  
                                          // return array( $form, array("timesheet" =&gt; array("id" =&gt; $timesheet-&gt;getId() ) ) );
  
                           }
  
                           return V::create($form, 400);
                       }
  
  
  
  
  
  
  
  }
  </code></pre>