我希望实现一个搜索功能,其中可以选择包含供用户搜索的各个字段。
到目前为止我的代码:
$categories = $request->input('category'); // array(int)
$textSearch = $request->input('text'); // string
$query = Product::query();
if(!is_null($categories)){
//$query->selectSub();
foreach($categories as $catId){
$category = ShopCategory::find($catId);
$query = $query->whereBelongsTo($category);//TODO
}
}
if(!is_null($textSearch)){
$query = $query->whereAny([
'name',
'description',
'shortDescription',
],
'like', '%'.$textSearch.'%');
}
$searchResults = $query->paginate(36);
我的目标是达到相当于以下内容的 SQL 语句:
SELECT * FROM products WHERE (shop_category_id = ? OR shop_category_id = ?) AND (/* text search LIKE */)
但到目前为止,我最终得到的更多的是:
SELECT * FROM products WHERE shop_category_id = ? AND shop_category_id = ? AND (/* text search LIKE */)
每个类别 ID 都作为整体查询的一部分进行
AND
编辑,而不是在组中进行 OR
编辑。
我知道
or*()
查询方法,但不清楚如何正确地将它们分组以获得所需的效果,而不是仅仅将它们与文本搜索一起OR
。
您可以使用带有回调的
where
函数将一些 where 条件包装到一个组中。回调内应用于构建器的任何条件都将被包裹在括号中。例如:
Model::query()->where('condition1', 'value')->where(function($query) {
// those where will be wrapped into ()
$query->where('condition2', 'value')->orWhere('condition3', 'value');
})
将给出以下查询:
SELECT *
FROM models
WHERE conditon1 = 'value'
AND (condition2 = 'value'
OR condition3 = 'value')
并且由于第一个位置是
OR
或 AND
并不重要,因此您可以将其放入循环中,而不必担心第一个 OR
:
$columns = [
'column1',
'column2',
'column3'
]
Model::query()->where('condition1', 'value')->query(function($query) use ($columns) {
foreach($columns as $column) {
$query->orWhere($column, 'value');
}
});
此查询是动态生成的,将返回以下 SQL:
SELECT *
FROM models
WHERE condition1 = 'value'
AND (column1 = 'value'
OR column2 = 'value'
OR column3 = 'value')
并且由于“列条件”被包装到一个组中,因此它们不会干扰第一个条件。