我想爲食譜及其相關成分實現搜索功能。用戶應該指定他想要從搜索中排除的成分,同時指定他正在尋找的配方中包含的成分。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;
}
在控制器I撥打:
$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函數。這有效,但它感覺不對。
還有其他解決方案嗎?
匹配/ notMatching函數期望第一個參數是關聯的名稱,而不是表名或別名。可悲的是,這是行不通的。 – napolin