Reputation: 875
I have a situation where I need to add columns to a many-to-many join table, so I'm trying to follow the recommended practice of having the join table represented by an entity with ManyToOne relationships with each of the other two entities.
In this case, we have a court interpreter management system where there's an entity called Event, another called Interpreter. The InterpreterAssignment entity is one-to-many with both of these, but it also needs two metadata columns: a created
datetime, and the Application\Entity\User
who created it (I leave out the latter for simplicity's sake).
So, this works just fine:
$interpreter = $entityManager->getRepository('Application\Entity\Interpreter')
->findOneBy(['lastname'=>'Mintz']);
$assignment = new Entity\InterpreterAssignment();
$assignment->setInterpreter($interpreter)->setEvent($event);
$event->addInterpretersAssigned($assignment);
$em->flush();
...and I don't even need to say persist()
because of the cascade={"persist","remove"})
on Event#interpretersAssigned
.
However, when I try to do the reverse, that is,
use the removeInterpretersAssigned()
method that Doctrine wrote for me:
$event = $entityManager->find('Application\Entity\Event',103510);
$assignment = $event->getInterpretersAssigned()[0];
$event->removeInterpretersAssigned($assignment);
$em->flush();
the database is untouched; Doctrine does not delete the row in the join table.
I can work around by saying $entityManager->remove($assignment)
. But I can't help but think that $event->removeInterpretersAssigned($assignment)
is supposed to work.
So, I must be missing something but I can't see what. The Doctrine cli tool says my mappings are OK. Here are the entities, in relevant part:
/* namespace declarations and use statements omitted */
class Event
{
/* other fields and methods omitted */
/**
* @ORM\OneToMany(targetEntity="InterpreterAssignment",mappedBy="event",cascade={"persist","remove"})
* @var InterpreterAssignment[]
*/
protected $interpretersAssigned;
/* the following created by the Doctrine cli tool */
/**
* Remove interpretersAssigned
*
* @param \Application\Entity\InterpreterAssignment $interpretersAssigned
*/
public function removeInterpretersAssigned(\Application\Entity\InterpreterAssignment $interpretersAssigned)
{
$this->interpretersAssigned->removeElement($interpretersAssigned);
}
/**
* Get interpretersAssigned
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getInterpretersAssigned()
{
return $this->interpretersAssigned;
}
}
class Interpreter
{
/**
* @ORM\OneToMany(targetEntity="InterpreterAssignment",mappedBy="interpreter")
* @var InterpreterAssignment[]
*/
protected $assignments;
/**
* Remove assignment
*
* @param \Application\Entity\InterpreterAssignment $assignment
*/
public function removeAssignment(\Application\Entity\InterpreterAssignment $assignment)
{
$this->assignments->removeElement($assignment);
}
/**
* Get assignments
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getAssignments()
{
return $this->assignments;
}
}
and here is the InterpreterAssignment
/**
* @ORM\Entity
* @ORM\Table(name="interp_events", uniqueConstraints={@ORM\UniqueConstraint(name="unique_deft_event",columns={"interp_id","event_id"})})
* @ORM\HasLifeCycleCallbacks
*/
class InterpreterAssignment
{
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="Interpreter",inversedBy="assignments")
* @ORM\JoinColumn(name="interp_id", referencedColumnName="interp_id")
* @var Interpreter
*/
protected $interpreter;
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="Event",inversedBy="interpretersAssigned")
* @ORM\JoinColumn(name="event_id", referencedColumnName="event_id")
* @var Event
*/
protected $event;
/**
* @ORM\Column(type="datetime",nullable=false)
* @var \DateTime
*/
protected $created;
/**
* @ORM\PrePersist
*/
public function onPrePersist()
{
$this->created = new \DateTime();
}
/**
* Set interpreter
*
* @param \Application\Entity\Interpreter $interpreter
*
* @return InterpreterAssignment
*/
public function setInterpreter(\Application\Entity\Interpreter $interpreter)
{
$this->interpreter = $interpreter;
return $this;
}
/**
* Get interpreter
*
* @return \Application\Entity\Interpreter
*/
public function getInterpreter()
{
return $this->interpreter;
}
/**
* Set event
*
* @param \Application\Entity\Event $event
*
* @return InterpreterAssignment
*/
public function setEvent(\Application\Entity\Event $event)
{
$this->event = $event;
return $this;
}
/**
* Get event
*
* @return \Application\Entity\Event
*/
public function getEvent()
{
return $this->event;
}
/* other stuff ommitted */
}
Many thanks.
Upvotes: 1
Views: 69
Reputation: 1688
I think you need to do 2 things:
(optional) You need to call $assignment->setEvent(null)
after calling $event->removeInterpretersAssigned($assignment);
Also you may want to use Orphan Removal to remove the entity from the many to many table. and so the entity code should changed to (notice the addition of , orphanRemoval=true
to the mapping code):
/**
* @ORM\OneToMany(targetEntity="InterpreterAssignment",mappedBy="event",cascade={"persist","remove"}, orphanRemoval=true)
* @var InterpreterAssignment[]
*/
protected $interpretersAssigned;
Upvotes: 1