Я хочу реализовать функцию поиска рецептов и связанных с ними ингредиентов. Пользователь должен указать ингредиенты, которые он хочет исключить из поиска, и в то же время ингредиенты, которые содержатся в рецептах, которые он ищет.Cakephp3.1: Использование сопоставления() и notMatching() на одной и той же связанной модели сразу
Это мои два искатели:
public function findByContainingIngredients(Query $query, array $params)
{
$ingredients = preg_replace('/\s+/', '', $params['containing_ingredients']);
if($ingredients) {
$ingredients = explode(',', $ingredients);
$query->distinct(['Recipes.id']);
$query->matching('Ingredients', function ($query) use($ingredients) {
return $query->where(function ($exp, $query) use($ingredients) {
return $exp->in('Ingredients.title', $ingredients);
});
});
}
return $query;
}
public function findByExcludingIngredients(Query $query, array $params)
{
$ingredients = preg_replace('/\s+/', '', $params['excluding_ingredients']);
if($ingredients) {
$ingredients = explode(',', $ingredients);
$query->distinct(['Recipes.id']);
$query->notMatching('Ingredients', function ($query) use ($ingredients) {
return $query->where(function ($exp, $query) use ($ingredients) {
return $exp->in('Ingredients.title', $ingredients);
});
});
}
return $query;
}
В контроллере я зову:
$recipes = $this->Recipes->find()
->find('byExcludingIngredients', $this->request->data)
->find('byContainingIngredients', $this->request->data);
Если пользователь исключает компонент из поиска и определяет один руды более ингредиент, который он хочет включить , есть нулевые результаты. Когда я смотрю на сгенерированный SQL я вижу проблему:
SELECT
Recipes.id AS `Recipes__id`,
Recipes.title AS `Recipes__title`,
.....
FROM
recipes Recipes
INNER JOIN ingredients Ingredients ON (
Ingredients.title IN (: c0)
AND Ingredients.title IN (: c1)
AND Recipes.id = (Ingredients.recipe_id)
)
WHERE
(
Recipes.title like '%%'
AND (Ingredients.id) IS NULL
)
GROUP BY
Recipes.id,
Recipes.id
Проблема является "AND (Ingredients.id) IS NULL". Эта линия приводит к исчезновению результатов от ингредиентов. Подходы:
- Создание псевдонима при вызове функции notMatching() в ассоциации дважды. Я думаю, что это невозможно в Cake3.1
- Использование левого соединения на PK/FK и исключенного заголовка и создание псевдонима. В основном написано моя функция notMatching. Это работает, но это не кажется правильным.
Есть ли другие решения?
Функции match/notMatching ожидают, что первым параметром будет имя assoiciation, а не имя таблицы или псевдоним. К сожалению, это не работает. – napolin