从 Symfony/Doctrine One->Many Relationship 中的表单集合中删除记录

Removing records from Form Collection in Symfony / Doctrine One->Many Relationship

正在尝试从嵌入另一个表单的表单集合中删除实体记录。我已成功将实体记录添加到同一个表单集合中。

表单集合实体 (quoteItemDeliverable) 与父实体 (quoteItem) 处于一对多关系。

使用 symfony 3.3/Doctrine 并一直在使用相应的文档https://symfony.com/doc/3.3/form/form_collections.html

使用文档我可以删除表单元素,这是集合中的项目,因为它存在于表单 (twig) 中。下面控制器代码中的 dump() 将显示项目已从编辑表单中的集合中删除。但是当 $quoteItem 持久存在时,表单中删除的集合项不会从实体中的集合中删除(记录未删除)。

我们正在使用的控制器代码

    /**
 * Edit an existing ring quote entity.
 *
 * @Route("/{id}/edit", name="quote-ring_edit")
 * @Method({"GET", "POST"})
 */
public function editAction (Request $request, QuoteItem $quoteItem)
{
    $type = $quoteItem->getCategory();

    $form = $this->createForm('UniflyteBundle\Form\QuoteItemType', $quoteItem, ['allow_extra_fields' => true, 'attr' => ['quote-type' => 2, 'category-type' => $type]]);
    $form->add('QuoteRing', QuoteRingType::class, ['label' => false]);

    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        dump($quoteItem);
        $em = $this->getDoctrine()->getManager();

        $em->persist($quoteItem);
        $em->flush();

        //return $this->redirectToRoute('quote-ring_edit', ['id' => $quoteItem->getId()]);
    }

    return $this->render("quoteitem/ring.html.twig", [
        'quoteItem' => $quoteItem,
        'form_new'  => false,
        'type'      => $type,
        'form'      => $form->createView()
    ]);
}

集合的表单类型看起来像

          ->add('quoteItemDeliverables', CollectionType::class, [
        'entry_type'    => QuoteItemDeliverableType::class,
        'entry_options' => array ('label' => false),
        'by_reference'  => false,
        'allow_add'     => true,
        'allow_delete'  => true,
        'prototype'     => true,
      ])

构成集合注释的 quoteItem 实体。

/**
 * @ORM\OneToMany(
 *     targetEntity="UniflyteBundle\Entity\QuoteItemDeliverable",
 *     mappedBy="quoteItem",
 *     cascade={"persist","detach","remove"}
 * )
 */
private $quoteItemDeliverables;

quoteItem 中的方法 class 用于在集合中添加和删除项目

/**
 * Add quoteItemDeliverable
 *
 * @param \UniflyteBundle\Entity\QuoteItemDeliverable $quoteItemDeliverable
 *
 * @return QuoteItem
 */
public function addQuoteItemDeliverable (\UniflyteBundle\Entity\QuoteItemDeliverable $quoteItemDeliverable)
{
    $quoteItemDeliverable->setQuoteItem($this);
    $this->quoteItemDeliverables[] = $quoteItemDeliverable;

    return $this;
}

/**
 * Remove quoteItemDeliverable
 *
 * @param \UniflyteBundle\Entity\QuoteItemDeliverable $quoteItemDeliverable
 */
public function removeQuoteItemDeliverable (\UniflyteBundle\Entity\QuoteItemDeliverable $quoteItemDeliverable)
{
    $this->quoteItemDeliverables->removeElement($quoteItemDeliverable);
}

/**
 * Get quoteItemDeliverables
 *
 * @return \Doctrine\Common\Collections\Collection
 */
public function getQuoteItemDeliverables ()
{
    return $this->quoteItemDeliverables;
}

文档指出,对于一对多,我们可能必须明确删除关系(上面提供的文档 link 中的片段)。我不明白为什么。

foreach ($originalTags as $tag) {
        if (false === $task->getTags()->contains($tag)) {
            // remove the Task from the Tag
            $tag->getTasks()->removeElement($task);

            // if it was a many-to-one relationship, remove the relationship like this
            // $tag->setTask(null);

            $em->persist($tag);

            // if you wanted to delete the Tag entirely, you can also do that
            // $em->remove($tag);
        }

有没有人知道我在控制器上做错了什么转储正确反映但没有发生持续删除记录的操作?

预先感谢您花时间和精力协助完成这项挑战。

更新 - :我听从了 DonCallisto 的建议,并成功地从实体级别的集合中删除了控制器中的项目

if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();

        // NOTE: Remove the quote item deliverables - will need for additional work as well?
        foreach ($em->getRepository('UniflyteBundle:QuoteItemDeliverable')->findAll() as $quoteItemDeliverable) {
            if (false === $quoteItem->getQuoteItemDeliverables()->contains($quoteItemDeliverable)) {
                $em->remove($quoteItemDeliverable);
                $em->persist($quoteItem);
            }
        }
        $em->flush();

        return $this->redirectToRoute('blah', ['id' => $quoteItem->getId()]);
    }

那是因为您要从 inversed side of the relation. Doctrine can actually check only for changes in owning side 中删除它,所以就好像您根本没有删除它一样,因为拥有方没有更改。

您需要通过 EntityManager 以编程方式删除项目或在注释中将 orphanRemoval 设置为 true(但我不推荐这样做!)。 我不建议使用 orphanRemoval 因为,即使它可以让你免于编写更多代码,也无法将删除的元素重新分配给其他集合(只是为了让你远离未来的麻烦)

另外一定要在from at collection字段中有by_reference => false,否则不会调用add*remove*方法。