Doctrine ORM: Получить теги товара без знака, отсортированные по тегам populatiry - PullRequest
0 голосов
/ 24 декабря 2018

У меня есть много-много отношений между продуктами и тегами.На данный момент это определяется как однонаправленная связь с продуктом, являющимся владельцем, но я могу изменить его на двунаправленный, если требуется.

Я хочу создать функцию для предложения тегов для существующего продукта.Я хочу, чтобы сначала были предложены самые популярные теги, и, очевидно, я не хочу, чтобы предлагался какой-либо тег, уже назначенный продукту.Под популярными тегами я подразумеваю те, которые чаще назначаются другим продуктам.Кроме того, предлагаемые теги должны начинаться с заданного префикса.

У меня есть рабочий запрос SQL, который дает точный результат, который я хочу, но у меня возникают проблемы при попытке преобразовать его в формат DQL или построитель запросов.

Предположим, 1 - это идентификатор продукта, для которого я хочу получить предложения тегов, и предположим, что префикс предлагаемых тегов равен prefix, это запрос, который возвращает нужные мне результаты:

SELECT
    t.id,
    t.name,
    COUNT(pt.product_id) AS popularity
FROM
    tags t LEFT JOIN product_tag pt ON (t.id = pt.tag_id)
WHERE
    t.id NOT IN (SELECT tag_id FROM product_tag WHERE product_id = 1) AND
    t.name LIKE 'prefix%'
GROUP BY
    t.id,
    t.name
ORDER BY
    popularity DESC,
    t.name

Мой текущий подход такой, но он возвращает пустые результаты

$queryBuilder = $entityManager->createQueryBuilder();
$product = $productRepository->find(1);
$prefix = 'prefix';

$suggestions = $queryBuilder
->select('t.id, t.name, COUNT(p) AS popularity')
->from('Tag', 't')
->leftJoin('Product', 'p', \Doctrine\ORM\Query\Expr\Join::WITH, $queryBuilder->expr()->eq('p.id', $product->getId()))
->andWhere('t NOT MEMBER OF p.tags')
->andWhere('t.name LIKE :prefix')->setParameter('prefix', "$prefix%")
->groupBy('t.id, t.name')
->addOrderby('popularity', 'desc')
->addOrderby('t.name')
->getQuery()
->getResult();

SQL, сгенерированный с помощью приведенного выше кода, близок, но неверен:

SELECT
    t.id,
    t.name,
    COUNT(p.id) AS popularity 
FROM
    tags t2_ LEFT JOIN products p ON (p.id = 1),
    tags t 
WHERE
    NOT EXISTS 
    (
        SELECT 1
        FROM
            product_tag pt INNER JOIN tags t ON pt.tag_id = t4_.id 
        WHERE
            pt.product_id = p.id AND
            t4_.id IN ( t.id )
    )
    AND t.name LIKE ? 
GROUP BY
    t.id,
    t.name 
ORDER BY
    popularity DESC,
    t.name ASC
...