I have a more complex query that needs to a second query builder to create extra DQL:
$qb2->select('MAX(cs2.createdAt)')
->from('AppBundle:ContractState', 'cs2')
->where('cs2.contract = ' . sprintf('%s.id', $dqlAlias))
->addOrderBy('cs2.date', 'desc')
->addOrderBy('cs2.createdAt', 'desc')
;
$qb
->andWhere('cs.createdAt = (' . $qb2->getDql() . ')')
->andWhere('cs.state = :state')
->setParameter('state', $this->state);
This worked fine so far in my repository. For using it with specs I found no other solution than cloning the original query builder:
public function modify(QueryBuilder $qb, $dqlAlias)
{
$qb2 = clone $qb;
$qb2->select('MAX(cs2.createdAt)')
->from('AppBundle:ContractState', 'cs2')
->where('cs2.contract = ' . sprintf('%s.id', $dqlAlias))
->addOrderBy('cs2.date', 'desc')
->addOrderBy('cs2.createdAt', 'desc');
$qb
->andWhere('cs.createdAt = (' . $qb2->getDql() . ')')
->andWhere('cs.state = :state')
->setParameter('state', $this->state);
parent::modify($qb, $dqlAlias);
}
My service looked like this in the first place:
$listQuery = $this->contractRepository->getQuery(
Spec::andX(
new ContractedByBranch(BranchId::create(2)),
new WithCurrentState(ContractState::create($query->state()))
)
);
This give me the following DQL for my clone subquery:
SELECT MAX(cs2.createdAt) FROM AppBundle\Entity\Contract e INNER JOIN e.branch br, AppBundle:ContractState cs2 WHERE cs2.contract = e.id ORDER BY cs2.date desc, cs2.createdAt desc
I recognized that the JOIN parts were not resetted. I changed the order of my specs:
$listQuery = $this->contractRepository->getQuery(
Spec::andX(
new WithCurrentState(ContractState::create($query->state())),
new ContractedByBranch(BranchId::create(2))
)
);
Giving me:
SELECT MAX(cs2.createdAt) FROM Plusquam\Bundle\ContractBundle\Entity\Contract e, PlusquamContractBundle:ContractState cs2 WHERE cs2.contract = e.id ORDER BY cs2.date desc, cs2.createdAt desc
Which looked better. But as you can see the FROM part hast 2 entities - including the "root" with the $dqlAlias
e.
Since the query used to work fine before I'm not sure if this is a pure query builder issue.
The workaround is to always reset the DQL parts manually:
$qb2 = clone $qb;
$qb2->resetDQLParts();
Is there a different way to get (another) query builder from the repository / entity manager?
BTW: I will refactor the query to use a HAVING clause on the subquery result. But anyways a second query builder will be required.