Reputation: 397
I have a classic ManyToMany on my entity. I would like to find Session by its disciplines.
class Session
/**
* @ORM\ManyToMany(targetEntity=Discipline::class)
*/
private $disciplines;
Example of my database:
Session Discipline
51 1
51 2
52 2
52 3
52 4
53 1
If I send
$disciplines = [1,2];
I would like the Session 51
If I send
$disciplines = [1];
I would like the Session 53
If I send
$disciplines = [2,3,4];
I would like the Session 52
I have this query
$queryBuilder
->innerJoin('s.disciplines', 'dis')
->andWhere($queryBuilder->expr()->in('dis.id', ':disciplines'))
->setParameter(':disciplines', $disciplines, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
;
But the request its not strict. How can I improve this?
Upvotes: 2
Views: 204
Reputation: 397
I found the solution. The only annoying thing is that makes one join per element of the array.
$values = [2,3,4];
$andX = $queryBuilder->expr()->andX();
foreach ($values as $k => $value) {
$andX->add($queryBuilder->expr()->eq("d$k.id", ':param' . $k));
$queryBuilder->setParameter(':param' . $k, $value);
$queryBuilder->innerJoin($alias . '.disciplines', "d$k");
}
$queryBuilder->andWhere($andX);
Upvotes: 1
Reputation: 33334
A solution would be to build a SQL query returning the results you want and then use a Doctrine native SQL query to map the results to your Session objects
First, the raw SQL query, it could look like this
SELECT s.*
FROM session s
WHERE id IN (
-- must match all required disciplines
SELECT session_id FROM session_discipline
WHERE discipline_id IN (:disciplines)
GROUP BY session_id
HAVING COUNT(discipline_id)=:nb
)
AND id IN (
-- must have the required number of rows
SELECT session_id FROM session_discipline
GROUP BY session_id
HAVING COUNT(discipline_id)=:nb
)
It probably can be improved, but that does the trick.
Now, we can use this query to build our request
// assuming this runs in a repository. Change at will to get your entity manager
$em = $this->getEntityManager();
$sql = "-- the raw SQL above --"; // don't forget to set the correct query
//
$rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($em);
$rsm->addRootEntityFromClassMetadata(Session::class, 's');
$query = $em->createNativeQuery($sql, $rsm);
// $disciplines is an array of ids as shown in the question
$query
->setParameter('disciplines', $disciplines)
->setParameter('nb', count($disciplines))
;
$sessions = $query->getResult();
Upvotes: 0