Ми}{@лbI4

Блог хеллоуворлдщика

SELECT COUNT(*) FROM (sub_query) в Doctrine 2

28.11.2018 doctrine2, orm, php

Не мог не заметить, какое количество вопросов по этому поводу, т.к. сам когда-то искал на это ответ. Проблема в том, что хорошего ответа нет.

Если у вас сложный запрос и вам нужно получить по нему COUNT(*), то в сети можно найти вариант вида:

$subQuery = $qb->select('main.id')
    ->from('Order\Entity\Order', 'main')
    ->where('main.published = :published')
    ->setParameters([
        'published' => true,
    ]);

$qb->select('COUNT(o)')
    ->from('Order\Entity\Order', 'o')
    ->where($qb->expr()->in('o.id', $subQuery->getDQL()))
    ->setParameters($subQuery->getParameters());

return $qb->getQuery()->getResult();

Но такой запрос очень медленный. Он подойдет для незначительного объема данных.

А что, если нам нужно выполнить большой запрос и много данных? Здесь на помощь приходит AST Walkers. Все, на самом деле, выполняется без каких-либо проблем. Только, никто документацию не желает читать, а сразу в поиск, а в поиске-то и не всегда есть все ответы. ;) Walkers нужен для трансформации DQL в SQL. Вот так просто. =)

На странице о том, как создать кастомный AST Walkers, уже есть пример, как пользоваться им для подсчета количества. Я приведу более расширенный вариант:

$platform = $entityManager->getConnection()->getDatabasePlatform();

$rsm = new \Doctrine\ORM\Query\ResultSetMapping();
$rsm->addScalarResult($platform->getSQLResultCasing('dctrn_count'), 'count');

$query = clone $mainQuery;

$query->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker');
$query->setResultSetMapping($rsm);
$query->setParameters($mainQuery->getParameters());

return $query->getQuery()->getResult();

После этого наш запрос будет вида SELECT COUNT(*) FROM (наш подзапрос).

Вот и все. =) Также, советую посмотреть Doctrine\ORM\Tools\Pagination\Paginator, оттуда-то и был взять "более расширенный вариант". ;)