更新多对多关系

时间:2018-05-15 11:10:43

标签: php symfony doctrine-orm many-to-many symfony-forms

我正在研究symfony 3和doctrine的项目。 Pack和Produit之间有很多关系:

包实体:

class Pack
{ 
    /**
     * @var ArrayCollection | Produit[]
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Produit", inversedBy="packs")
     * @ORM\JoinTable(name="link_pack")
     */
    private $produits;

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

    }


    /**
     * @return Produit[]|ArrayCollection
     */
    public function getProduits()
    {
        return $this->produits;
    }

    public function addProduit(Produit $produit)
    {
        if ($this->produits->contains($produit)) {
            return;
        }
        $this->produits[] =  $produit;
    }

    public function removeProduit(Produit $produit)
    {
        if (! $this->produits->contains($produit)) {
            return;
        }
       return $this->produits->removeElement($produit);
    }
}

生产实体:

class Produit
{
    /**
     * @var ArrayCollection | Pack[]
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Pack", mappedBy="produits")
     */
    private $packs;

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

    }

    /**
     * @return Pack[]|ArrayCollection
     */
    public function getPacks()
    {
        return $this->packs;
    }

    public function addPack(Pack $pack)
    {
        if ($this->packs->contains($pack)) {
            return;
        }
        $pack->addProduit($this);
        $this->packs[] =  $pack;
    }
}

我想将产品分配给一个包,所以我有一个包含选择字段中的产品的表单。 (包装和产品在之前创建)。

表单类型:

class PackAffectProduitType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('produits', EntityType::class, array(
            'class' => Produit::class,        
            'choice_label' => 'libelle',
                    'multiple' => true,       
        ));
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Pack::class,
        ));
    }
}

控制器:

public function affectProduitsAction(Pack $pack, Request $request)
    {

        $form = $this->createForm(PackAffectProduitType::class, $pack);

        $form->handleRequest($request);
        dump($pack);
        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            dump($pack);
            $em->flush();
           // ...
        }
       //...
    }

问题是当我选择产品并提交时,它会将所选产品分配给包,但之前分配的产品将被删除。我希望它们仍然分配,那么如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

  • 如果您希望视图添加或删除值,如果手动生成字段视图结构,则不必忘记填充已设置的值(例如,之前添加到Pack的产品)。

例如,将selected属性添加到select的选项中。这样做会使用当前值预先填充您的字段,因此仅在提交时删除那些故意未被选中的字段。

  • 如果您不希望自己的视图显示或了解此包装中已设置的Produit实体,只是盲目执行添加,您可以将mapped => false添加到您的字段选项并处理手动将产品添加到控制器中的包中。

这只允许你添加,因为它不知道已经设置的值,你必须做另一个案例/动作来执行删除。在我看来,上面的方式更好。

在最后一种情况下,您的控制器将如下所示:

public function affectProduitsAction(Pack $pack, Request $request)
{

    $form = $this->createForm(PackAffectProduitType::class, $pack);

    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        if(is_array($form->get('produits')->getData()){
            foreach($form->get('produits')->getData() as $produit){
                $pack->addProduit($produit);
            }
        }
        $em->flush();
       // ...
    }
   //...
}

你的FormType:

class PackAffectProduitType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('produits', EntityType::class, array(
            'class' => Produit::class,     
            'mapped' => false,   
            'choice_label' => 'libelle',
                    'multiple' => true,       
        ));
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Pack::class,
        ));
    }
}

答案 1 :(得分:0)

尝试向表单添加'by_reference' => false选项,它将强制使用您实体的setter和getter