Editing form for relationship n:m with extra attri

2019-09-06 16:20发布

问题:

I have this mapping betwenn two entities:

class Orders {
    // Other attributes 

    /**
     * @ORM\OneToMany(targetEntity="OrderHasProduct", mappedBy="order") 
     */
    protected $orderProducts;

    // Other set/get methods

    public function getOrderProducts()
    {
        return $this->orderProducts;
    }
}

class Product {
    // Other attributes

    /**
     * @ORM\OneToMany(targetEntity="\Tanane\FrontendBundle\Entity\OrderHasProduct", mappedBy="product")
     */
    protected $orderProducts;

    // Other set/get methods

    public function getOrderProducts()
    {
        return $this->orderProducts;
    }
}

And of course since many Orders can have many products but also there is an extra attribute this other entity is needed:

class OrderHasProduct
{
    /**
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="\Tanane\FrontendBundle\Entity\Orders")
     * @ORM\JoinColumn(name="general_orders_id", referencedColumnName="id")
     */
    protected $order;

    /**
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="\Tanane\ProductBundle\Entity\Product")
     * @ORM\JoinColumn(name="product_id", referencedColumnName="id")
     */
    protected $product;

    /**
     * @ORM\Column(type="integer", nullable=false)
     */
    protected $amount;

    public function setOrder(\Tanane\FrontendBundle\Entity\Orders $order)
    {
        $this->order = $order;
    }

    public function getOrder()
    {
        return $this->order;
    }

    public function setProduct(\Tanane\ProductBundle\Entity\Product $product)
    {
        $this->product = $product;
    }

    public function getProduct()
    {
        return $this->product;
    }

    public function setAmount($amount)
    {
        $this->amount = $amount;
    }

    public function getAmount()
    {
        return $this->amount;
    }
}

When I edit a order I should able to add/remove the products on that order but I don't know how to achieve this. I knew that I must use a form collection but how? I mean a collection should be embed as follow:

$builder->add('product', 'collection', array(
    'type' => new OrderHasProductType(),
    'allow_add' => true,
    'allow_delete' => true
));

When I should create a new OrderHasProductType form and I think I understand until this point but my question now is, what happens to the ID of the order? What is the proper way to handle an embedded form a relationship n:m with extra parameters?

Can any give me some code example to order my ideas?

Extra resources

  • Orders Entity Complete Source
  • Product Entity Complete Source
  • Orders Form Type Complete Source
  • OrderHasProduct Form Type Complete Source

回答1:

I think your situation is slightly complicated by having not a standard Doctrine many-to-many relationship with two Entities, but two separate one-to-many and many-to-one relationships, with three Entities.

Normally, with a full many-to-many, the process is to have, for example, an OrderType form, containing a Collection field full of ProductTypes representing the Products assigned to the Order.

('allow_add' => true means that if Symfony sees an entry with no ID it expects it to be a brand new item added via Javascript, and is happy to call the form Valid and add the new item to the Entity. 'allow_delete' => true conversely means that if one of the items is missing then Symfony will remove it from the Entity.)

However, you have one further level of Entities, it goes Order->OrderHasProduct->Product. So logically your OrderType form contains a Collection of OrderHasProductType forms (as you've put above), which in turn contains a ProductType form.

So your OrderType becomes more like this:

$builder->add('orderHasProducts', 'collection', array(
    'type' => new OrderHasProductType(),
    'allow_add' => true,
    'allow_delete' => true
));

And you also have another level for the Products:

OrderHasProductType

$builder->add('product', 'collection', array(
    'type' => new ProductType(),
    'allow_add' => true,
    'allow_delete' => true
));

And a ProductType as well:

$builder->add('product', 'entity', array(
    'class' => 'ProductBundle:Product'
));

Symfony should be happy to map your Entities to the correct level of Types. In your View you will need to include Javascript which will understand that adding a Product to an Order also involves the ProductHasOrder level - best to put some data in and see how Symfony turns that into a form, and then mimic the structure in the Javascript.