I ran into the following problem. An application should be able to clone a Season object with all the objects associated with it. I inspired this great question - and everything works as it should, but there is a problem with the ManyToMany attitude on the way.
Please take a look at the attached image, which depicts a small part of the database diagram showing the section that I'm having problems with.

The state I want to achieve is to have a clone of the Price object associated with an existing Offer object. It is clear that I cannot and should not clone the Offer object, the new cloned instance of the Price object must be bound to the same instance to which the Price wizard instance is bound.
Sample contents of offer_price table before cloning
offer_id | price_id ----------+---------- 47 | 77
Estimated contents of offer_price table after cloning
offer_id | price_id ----------+---------- 47 | 77 47 | 79
... assuming Price ID 77 is the master record, and Price ID 79 is the newly cloned instance associated with the same Offer record.
Entity definitions - simplified as much as possible
Price
class Price { ... private $offers; public function __construct() { parent::__construct(); $this->offers = new ArrayCollection(); } public function __clone() { if ($this->getId()) { $this->setId(null); $this->offers = new ArrayCollection(); } } public function addOffer(Offer $offer) { $this->offers->add($offer); return $this; } ... }
Sentence
class Offer { ... private $prices; public function __construct() { parent::__construct(); $this->prices = new ArrayCollection(); } ... }
Season
class Season { ... private $prices; public function __construct() { parent::__construct(); $this->prices = new ArrayCollection(); } public function __clone() { if ($this->getId()) { $this->setId(null); ... $priceClonedCollection = new ArrayCollection(); foreach ($this->prices as $price) { $priceClone = clone $price; $priceClone->setSeason($this); foreach ($price->getOffers() as $offer) { $priceClone->addOffer($offer); } $priceClonedCollection->add($priceClone); } $this->prices = $priceClonedCollection; ... } } ... }
I consist in that I have all the objects in the relation that I need, but only until the whole set is saved. After cleaning all the objects, preserving the parent ( Season ), everyone else will get a cascade, like them, except for the ManyToMany binding ManyToMany , where new entries are not added.
The solution that I used in the application is rather dirty. After clearing all the saved objects, I simply iterate over the Offer records associated with the Price instance (since they are correctly connected to each other) and save all identifiers, which are then manually inserted into the database. This solution is obviously not ideal and rather fragile.
... public function getCloneBindingHack(Season $clone) { foreach ($clone->getPrices() as $price) { foreach ($price->getOffers() as $offer) { $bindingHack[] = [ 'offer_id' => $offer->getId(), 'price_id' => $price->getId(), ]; } } return $bindingHack ?? []; } ...
Therefore, I am interested in how to persist in such a relationship. I assume there is an elegant solution that I just skipped, as these operations are quite common in real-world scenarios. But perhaps Doctrine2 cannot do it this way: “You have to do it yourself, since Doctrine cannot help you” might also be the right answer (which would make ORM completely useless IMHO).
Just to add objects on both sides, ManyToMany relationships are created and saved, everything works as it should, so I assume that the ManyToMany relationship binding table is annotated correctly.
PHP version 7.0.22
Doctrine2 ORM version 2.4.8
Note. I read this this question , but it does not address the same issue.