I have entities Campaign and Creative with relations One Campaign has Many Creatives
In Campaign:
/**
* @ORM\OneToMany(targetEntity="Creative", mappedBy="campaign", cascade={"detach", "persist"})
*/
protected $creatives;
In Creative:
/**
* @ORM\ManyToOne(targetEntity="Campaign", inversedBy="creatives", cascade={"detach", "persist"})
* @ORM\JoinColumn(name="campaign_id", referencedColumnName="id")
*/
private $campaign;
In frontend, I have multiple select where I can add/ remove creatives, and it sends an array of creative ids to the backend.
Problem is how to detach Creative from Campaign when I removing one from select.
I did not found any solution what doctrine can propose, so I tried:
$campaign->getCreatives()->clear();
foreach (json_decode($data['creatives'],true) as $creativeId) {
$campaign->addCreative($this->_em->getReference(Creative::class, $creativeId));
}
but looks like it's not working, code removing the element from Campaign object but not changing campaign_id
to null for related creative in the database. Maybe I need also detach it from Creative side, but it's extra work to do, I thought that cascade={"detach"} should handle it.
I would be grateful for any help!!!
FYI: I'm using doctrine with Laravel.
Updated I created sync method in Campaign as a workaround:
public function syncCreatives(array $creatives)
{
//detach all creatives
if(empty($creatives)) {
/** @var Creative $creative */
foreach ($this->creatives->getIterator() as $creative) {
$creative->setCampaign(null);
}
$this->creatives->clear();
return true;
}
//get nonexistent creatives
$creativesToRemove = $this->creatives->filter(function (Creative $creative) use (&$creatives) {
if(isset($creatives[$creative->getId()])) {
unset($creatives[$creative->getId()]);
return false;
}
return true;
});
//remove nonexistent creatives
foreach ($creativesToRemove->getIterator() as $creative) {
$this->removeCreative($creative);
}
//add new creatives
foreach ($creatives as $creative) {
$this->addCreative($creative);
}
}
related methodds:
/**
* @param Creative $creative
*/
public function removeCreative(Creative $creative)
{
if($this->creatives->contains($creative)) {
$creative->setCampaign(null);
$this->creatives->removeElement($creative);
}
}
/**
* @param Creative $creative
*/
public function addCreative(Creative $creative)
{
if(!$this->creatives->contains($creative)) {
$this->creatives->add($creative);
$creative->setCampaign($this);
}
}
So now I'm updating Campaign and Creative objects but still, it's not detaching creatives from campaign
Updated. I found this article Doctrine: How to unset (SET NULL) OneToMany relationship but I do not see what the difference between my code and solution? I should nnot use persist? But in my logic I update alot of Campaign fields and I need to persist campaign before flush