Я строю форму поиска для подержанных автомобилей. В форме пользователь может установить флажки для опций, которые должен иметь автомобиль. Поскольку пользователь может выбрать несколько вариантов, мне нужно найти автомобиль, в котором есть все параметры, выбранные пользователем.
Я пытаюсь создать запрос, который проверяет, есть ли у «автомобиля» выбранные параметры. Сейчас я могу проверить, есть ли у автомобиля один из выбранных вариантов, выполнив:
// The options filter is something special, the parameter is passed as a comma separated
// String with options ids
if($param == 'car.options' && $optionsIds){
$queryBuilder->leftJoin('car.options', 'option');
$options = $queryBuilder->expr()->orX();
foreach(explode(',', $optionsIds) as $id) {
$options->add($queryBuilder->expr()->eq('option.id', $id));
}
$wheres->add($options);
continue;
}
Но когда я изменяю ‘orX’ на ‘andX’, результат всегда возвращается пустым.
Вышеприведенный кодекс является частью большой функции.
Мне наконец удалось заставить это работать. Хитрость была в том, чтобы использовать подзапрос:
$carsWithSelectedOptions = $this->getEntityManager()->createQuery('
SELECT c.id
FROM Occasions\Model\Bo\Car AS c JOIN c.options o
WHERE o.id IN ('.$optionsIds.')
AND c.id = car.id
GROUP BY c.id
HAVING COUNT(o.id) >= '.count(explode(',', $optionsIds))
);
$wheres->add($queryBuilder->expr()->exists($carsWithSelectedOptions->getDQL()));
Обратите внимание, что это часть более крупного запроса. Полный запрос приводит к:
SELECT advert, customer, car, country, brand, model
FROM Occasions\Model\Bo\Advert advert
LEFT JOIN advert.customer customer
LEFT JOIN advert.car car
LEFT JOIN customer.country country
LEFT JOIN car.model model
LEFT JOIN car.brand brand
WHERE EXISTS(
SELECT c.id FROM Occasions\Model\Bo\Car AS c
JOIN c.options o WHERE o.id IN (2,4,5,51)
AND c.id = car.id GROUP BY c.id HAVING COUNT(o.id) >= 4)
AND brand.id = :brandid
AND model.id = :modelid
AND country.country_code = :countrycountry_code
Других решений пока нет …