学说:手动附加相关集合

My Doctrine based backend application has entity types Lead and Contact. One Lead can have many Contacts. My problem is that I want to keep contacts in the lead object's $contacts property, but when I fetch the lead I already have the related contacts, because I already needed them earlier in a different context. So I want to attach the already fetched contacts to the newly fetched lead object manually.

Here is the problem in the detail:

The query for fetching lead contacts must consider some important points, e.g.:

  • They must be relevant for the current user (there is another association to User)
  • It must not contain disabled entries

So there is a respective function getContactsByLead() which is called by the frontend via a web service:

$qb = $repo->createQueryBuilder('c');
$qb->where($qb->expr()->eq('c.lead', '?0'));
$qb->setParameter(0, $leadId);
$qb->andWhere('c.disabled = 0');
$qb->andWhere($qb->expr()->eq('c.user', '?1'));
$qb->setParameter(1, $this->getUser()->getId()); 
return $qb->getQuery()->execute();

Currently there is another function getLeadWithContacts() which should provide a Lead object instead with those contacts in stored in its contacts property:

/**
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\LeadContact", mappedBy="lead")
 */
protected $contacts;

So this function getLeadWithContacts() contains a query that is very similar to getContactsByLead(), but fetches a lead instead and LEFT JOINs the contacts with the same conditions:

$qb = $this->createQueryBuilder('l');
$qb->leftJoin('l.contacts', 'c', Expr\Join::WITH, 'c.disabled = 0');
$qb->addSelect('c');
$qb->where($qb->expr()->eq('l.id', $leadId));
$qb->andWhere($qb->expr()->eq('c.user', '?0'));
$qb->setParameter(0, $this->getUser()->getId()); 
return $qb->getQuery()->getOneOrNullResult();

This is problematic, as the developer has to always make sure both functions respect the conditions in the same way. It already lead to bigger problems, when a developer forgot to adjust one of the queries when the conditions changed.

That's why I want to replace getLeadWithContacts() with something like this:

public function getLeadWithContacts($leadId) {
    $lead = $this->getLead($leadId);
    $contacts = $this->getContactsByLead($lead);
    $lead->setContacts($contacts);
    return $lead;
}

But doctrine doesn't provide a setter method for the whole collection. And at this point, I also wonder if it works if I implement it on my own. Or would this lead to side effects, especially when I store the lead object again to the database later? I'm afraid of getting side effects like duplicate contacts and noticing them when it's too late. That's why I'm asking here...