У меня есть много-много отношений между продуктами и тегами.На данный момент это определяется как однонаправленная связь с продуктом, являющимся владельцем, но я могу изменить его на двунаправленный, если требуется.
Я хочу создать функцию для предложения тегов для существующего продукта.Я хочу, чтобы сначала были предложены самые популярные теги, и, очевидно, я не хочу, чтобы предлагался какой-либо тег, уже назначенный продукту.Под популярными тегами я подразумеваю те, которые чаще назначаются другим продуктам.Кроме того, предлагаемые теги должны начинаться с заданного префикса.
У меня есть рабочий запрос 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