3

I am a beginner in Symfony.

I have a strange problem in my form.

I have 2 entities : Proposal_Lsi and Lsi_Beams. One proposal can have multiple beams, but a beam can only have one proposal. I figured I should use a OneToMany/ManyToOne relation, and that my owning side is the beam one, and inverse side is proposal.

I followed the official guide at https://symfony.com/doc/3.1/form/form_collections.html about Form Collections.

Everything renders just fine, I can submit a new proposal with multiple beams, and all is correctly stored in the database.

The problem occurs whenever I try to add new beams to my proposal : the systems overwrites (update query) existing beams (starting by the first one in the database) instead of adding new ones (insert query).

What am I missing ?

Here's some of my code, if that can help.

Proposal Class:

class Proposal_lsi{
/**
* @ORM\OneToOne(targetEntity="Emir2Bundle\Entity\Proposal", inversedBy="proposal_lsi")
* @ORM\JoinColumn(name="proposal", referencedColumnName="id")
* @ORM\Id
*/  
private $proposal;

/**
* @ORM\OneToMany(targetEntity="Emir2Bundle\Entity\Lsi_beams", mappedBy="proposal_lsi")
*/  
private $lsi_beams;

...

/**
 * Add lsiBeam
 *
 * @param \Emir2Bundle\Entity\Lsi_beams $lsiBeam
 * @return Proposal_lsi
 */
public function addLsiBeam(\Emir2Bundle\Entity\Lsi_beams $lsiBeam)
{
    $lsiBeam->setProposalLsi($this);
    $this->lsi_beams[] = $lsiBeam;

    return $this;
}

}

Beams Class:

class Lsi_beams{
/**
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
* @ORM\ManyToOne(targetEntity="Emir2Bundle\Entity\Proposal_lsi", inversedBy="lsi_beams", cascade={"persist"})
* @ORM\JoinColumn(name="proposal_lsi", referencedColumnName="proposal", nullable=false)
*/
private $proposal_lsi;

...
}

And the form in the controller :

$form = $this->createFormBuilder($proposallsi)
        ->setAction($this->generateUrl('lsi_submission', array('id' => $id)))
        ->setMethod('POST')
        ->add('lsi_beams', CollectionType::class, array(
            'entry_type'    => LsiBeamsType::class,
            'allow_add'     => true,
            'allow_delete'      => true,
            'prototype'     => true,
            'by_reference'  => false
            )
        )
...

What am I doing wrong ? Let me know if you need more code.

Thanks for any reply !

  • Are you rendering the options that are already saved? If they are not being submitted along with the form they will get removed. – Chip Dean Aug 22 '18 at 18:06
  • Good evening, https://stackoverflow.com/a/49028183/4350745 this will help you with your mapping and entity and after that your population and persistence will be okey :) – l13 Aug 22 '18 at 19:30
  • @chip-dean If you're talking about the view, I render it with a macro, so I can have a "Add beam" button on the form. – S. Gregoire Aug 23 '18 at 07:50
  • @l13 I'm afraid that won't help, as I use annotations. If I compare to what I have, it's similar though. Thanks. – S. Gregoire Aug 23 '18 at 07:55
  • @s-gregoire Okey, I am not sure, but can you try this change and say is the problem is still occurs yet `@ORM\ManyToOne(targetEntity="Emir2Bundle\Entity\Proposal_lsi", inversedBy="lsi_beams", cascade={"persist"}, fetch="EAGER"}` – l13 Aug 23 '18 at 11:22
  • @l13 Problem is still here :( – S. Gregoire Aug 23 '18 at 13:27

1 Answers1

0

Notes:

  1. use Doctrine ArrayCollection to better keep track of collections
  2. put cascade={"persist"} at the inverse side of association (where you have mappedBy)
  3. Keep entity names singular (e.g. Lsi_beam instead of Lsi_beams)
  4. Keep your naming strategy clear and strait. Don't use undescores in your class & property names (e.g. use $lsiBeams instead of $lsi_beams)

ProposalLsi

use Doctrine\Common\Collections\ArrayCollection;

class ProposalLsi
{
    /**
    * @ORM\OneToMany(targetEntity="LsiBeam", mappedBy="proposalLsi", cascade={"persist"})
    */  
    private $lsiBeams;

    public function __construct()
    {
        $this->lsiBeams = new ArrayCollection();
    }

    public function addLsiBeam(LsiBeams $lsiBeam)
    {
        if ($this->lsiBeams->contains($lsiBeam)) {

            return;
        } else {

            $lsiBeam->setProposalLsi($this);
            $this->lsiBeams->add($lsiBeam);
        }
    
        return $this;
    }

    public function removeLsiBeam(LsiBeams $lsiBeam)
    {
        if (!$this->lsiBeams->contains($lsiBeam)) {

            return;
        } else {

            $lsiBeam->setProposalLsi(null);
            $this->lsiBeams->removeElement($lsiBeam);
        }
    
        return $this;
    }
}

LsiBeam

class LsiBeam
{
    /**
    * @ORM\ManyToOne(targetEntity="ProposalLsi", inversedBy="lsiBeams")
    */
    private $proposalLsi;

    public function setProposalLsi(?ProposalLsi $proposalLsi)
    {
        $this->proposalLsi = $proposalLsi;
    }

}
Community
  • 1
  • 1
Peyman Mohamadpour
  • 17,954
  • 24
  • 89
  • 100