Doctrine2:在参考表中添加多列的多对多(添加记录)

时间:2013-02-18 23:17:54

标签: doctrine-orm entity-relationship one-to-many symfony-2.1 many-to-one

剧透:我想我找到了答案,但我不是百分百肯定;)

我一直在看这个question一段时间,但我无法让它发挥作用。所以我创建了虚拟实体以测试关系,这里是:

  • Product可以包含多个Cart
  • Cart可以包含多个Product
  • Product中的Cartposition
  • 排序

产品

<?php

namespace Acme\DemoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\Table(name="demo_product")
 */
class Product
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\OneToMany(targetEntity="CartHasProduct", mappedBy="product", cascade={"all"})
     */
    protected $productCarts;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->productCarts = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Add productCarts
     *
     * @param \Acme\DemoBundle\Entity\CartHasProduct $productCarts
     * @return Product
     */
    public function addProductCart(\Acme\DemoBundle\Entity\CartHasProduct $productCarts)
    {
        $this->productCarts[] = $productCarts;

        return $this;
    }

    /**
     * Remove productCarts
     *
     * @param \Acme\DemoBundle\Entity\CartHasProduct $productCarts
     */
    public function removeProductCart(\Acme\DemoBundle\Entity\CartHasProduct $productCarts)
    {
        $this->productCarts->removeElement($productCarts);
    }

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

<?php

namespace Acme\DemoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\Table(name="demo_cart")
 */
class Cart
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\OneToMany(targetEntity="CartHasProduct", mappedBy="cart", cascade={"all"})
     */
    protected $cartProducts;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->cartProducts = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Add cartProducts
     *
     * @param \Acme\DemoBundle\Entity\CartHasProduct $cartProducts
     * @return Cart
     */
    public function addCartProduct(\Acme\DemoBundle\Entity\CartHasProduct $cartProducts)
    {
        $this->cartProducts[] = $cartProducts;

        return $this;
    }

    /**
     * Remove cartProducts
     *
     * @param \Acme\DemoBundle\Entity\CartHasProduct $cartProducts
     */
    public function removeCartProduct(\Acme\DemoBundle\Entity\CartHasProduct $cartProducts)
    {
        $this->cartProducts->removeElement($cartProducts);
    }

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

最后 CartHasProduct 参考表

<?php

namespace Acme\DemoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\Table(name="demo_cartHasProduct")
 */
class CartHasProduct
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="Cart", inversedBy="productCarts")
     */
    protected $cart;

    /**
     * @ORM\ManyToOne(targetEntity="Product", inversedBy="cartProducts")
     */
    protected $product;

    /**
     * @ORM\Column(type="integer")
     */
    protected $position;

    public function __construct(Cart $cart, Product $product, $position=0) {
        $this->cart = $cart;
        $this->product = $product;
        $this->setPosition($position);
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set position
     *
     * @param integer $position
     * @return CartHasProduct
     */
    public function setPosition($position)
    {
        $this->position = $position;

        return $this;
    }

    /**
     * Get position
     *
     * @return integer 
     */
    public function getPosition()
    {
        return $this->position;
    }

    /**
     * Set cart
     *
     * @param \Acme\DemoBundle\Entity\Cart $cart
     * @return CartHasProduct
     */
    public function setCart(\Acme\DemoBundle\Entity\Cart $cart = null)
    {
        $this->cart = $cart;

        return $this;
    }

    /**
     * Get cart
     *
     * @return \Acme\DemoBundle\Entity\Cart 
     */
    public function getCart()
    {
        return $this->cart;
    }

    /**
     * Set product
     *
     * @param \Acme\DemoBundle\Entity\Product $product
     * @return CartHasProduct
     */
    public function setProduct(\Acme\DemoBundle\Entity\Product $product = null)
    {
        $this->product = $product;

        return $this;
    }

    /**
     * Get product
     *
     * @return \Acme\DemoBundle\Entity\Product 
     */
    public function getProduct()
    {
        return $this->product;
    }
}

我手动创建了实体,添加@ORM注释来设置关系,然后我使用app/console generate:doctrine:entities AcmeDemoBundle填充gettersetter和{{1} }

现在我是一个控制器,我必须遵循以下代码:

__construct

这样做我出现以下错误:

  

在关联Acme \ DemoBundle \ Entity \ Cart#cartProducts上找到Acme \ DemoBundle \ Entity \ Product类型的实体,但期待Acme \ DemoBundle \ Entity \ CartHasProduct

所以我的问题是如何将产品添加到购物车中?我是否需要手动创建关系对象(<?php namespace Acme\DemoBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class WelcomeController extends Controller { public function indexAction() { // Create a Cart Entity $cart = new \Acme\DemoBundle\Entity\Cart(); // Create a Product Entity $product = new \Acme\DemoBundle\Entity\Product(); // Add the Product into the Cart $cart->getCartProducts()->add($product); // Save the Cart $em = $this->getDoctrine()->getManager(); $em->persist($cart); $em->flush(); return $this->render('AcmeDemoBundle:Welcome:index.html.twig'); } } )?我认为Doctrine会做到这一点。我在Doctrine文档中到处查看,我找不到与额外字段关系的例子。

我也调查了供应商的测试,有很多模型(非常有趣),但关系中没有额外的字段。

我在想这样在Cart中创建我自己的方法:

CartHasProduct

但我想知道我是否需要实施它,或者它是否意味着要自动处理?

#### 更新1 ####

所以我最后添加了这个方法public function addProduct(Product $product, $position=0) { $relation = new CartHasProduct($this, $product, $position); if (!$this->cartProducts->contains($relation)) { $this->cartProducts->add($relation); } } 。问题是addProduct没有按预期工作。因此,我尝试从contains()中删除所有Product并添加新的Cart

以下是我删除产品的功能:

/**
 * Reset the product for the cart
 *
 * @return bool
 */
public function resetCart() {
    foreach ($this->getCartProducts() as $relation) {
        $relation->getProduct()->removeProductCart($relation);
        $this->removeCartProducts($relation);
    }
}

以下是我的称呼方式:

    $em = $this->getDoctrine()->getManager();
    $cart->resetCart();
    $em->persist($cart);
    $em->flush();

但是CartHasProduct表中没有删除记录。

更新2

我发现问题是什么,如果要删除2个主要实体(orphanRemoval=true和{{1}之间的关系,则需要在OneTwoMany关系中添加Cart(两侧) }}):

Product

并且

/**
 * @ORM\Entity
 * @ORM\Table(name="demo_product")
 */
class Product
{
...

    /**
     * @ORM\OneToMany(targetEntity="CartHasProduct", mappedBy="product", cascade={"persist", "remove"}, orphanRemoval=true)
     */
    protected $productCarts;

干杯,

马克西姆

1 个答案:

答案 0 :(得分:2)

通过使用第三个中间实体,可以实现与额外参数的多对多关联。您有正确的方法,但定义了错误的关联。这是它应该如何。

将您的3个实体ProductCartCartProducts

带走

Cart应与one-to-many

建立CartProducts关系

CartProducts应与many-to-one建立Product关联,Many-to-oneCart建立关联

首先初始化Cart,并将产品添加到Cart,如下所示:

Product

  • 使用CartProductProduct以及您需要的其他额外参数初始化Cart
  • 将其添加到Cart