Хинт HINT_ENABLE_DISTINCT
Хинт HINT_ENABLE_DISTINCT передаётся в пагинатор
Paginator для включения SQL-оператора
DISTINCT в основной запрос выборки. Это
необходимо, когда запрос содержит JOIN на
коллекцию, из-за чего одна и та же корневая сущность
может попасть в результат несколько раз. Хинт
устанавливается третьим аргументом метода
paginate и принимает булево значение.
Синтаксис
$paginator->paginate($query, $page, $limit, [
Paginator::HINT_ENABLE_DISTINCT => true,
]);
Пример
Давайте включим DISTINCT для запроса, который
делает JOIN на коллекцию тегов статьи. Без
хинта одна статья с несколькими тегами вернулась бы
несколько раз:
<?php
namespace App\Controller;
use App\Entity\Article;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Doctrine\ORM\Tools\Pagination\Paginator;
class ArticleController extends AbstractController
{
#[Route('/articles', name: 'article_index')]
public function index(EntityManagerInterface $em): Response
{
$query = $em->createQuery(
'SELECT a FROM App\Entity\Article a LEFT JOIN a.tags t'
);
$paginator = new Paginator($query, true);
$paginator->setUseOutputWalkers(true);
$res = $paginator->paginate($query, 1, 10, [
Paginator::HINT_ENABLE_DISTINCT => true,
]);
foreach ($res as $article) {
echo $article->getTitle() . '<br>';
}
return new Response();
}
}
?>
Результат выполнения кода:
"article"<br>"user"<br>"abcde"<br>
Пример
Давайте сравним поведение пагинатора с хинтом и без него. Получим количество элементов в выборке:
<?php
namespace App\Controller;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Doctrine\ORM\Tools\Pagination\Paginator;
class ArticleController extends AbstractController
{
#[Route('/articles/count', name: 'article_count')]
public function count(EntityManagerInterface $em): Response
{
$query = $em->createQuery(
'SELECT a FROM App\Entity\Article a LEFT JOIN a.tags t'
);
$without = new Paginator($query, true);
$without->setUseOutputWalkers(true);
$with = new Paginator($query, true);
$with->setUseOutputWalkers(true);
$resWithout = $without->paginate($query, 1, 10, [
Paginator::HINT_ENABLE_DISTINCT => false,
]);
$resWith = $with->paginate($query, 1, 10, [
Paginator::HINT_ENABLE_DISTINCT => true,
]);
echo 'without: ' . count($resWithout) . '<br>';
echo 'with: ' . count($resWith);
return new Response();
}
}
?>
Результат выполнения кода:
"without: 6"<br>"with: 3"
Смотрите также
-
класс
Paginator,
который выполняет постраничную выборку сущностей -
хинт
HINT_FETCH_JOIN_COLLECTION,
который включает режим fetch-join для коллекций -
метод
setUseOutputWalkers,
который управляет обходом результатов при пагинации -
метод
getIterator,
который возвращает итератор по результатам выборки