关键词新增拼音查询支持,减少大量 orWhere () 的分享
最新甲方提出了搜索产品支持拼音及其首字母查询的需求,此前支持按产品的编码、正式名称、别名、生产商的搜索。
按照传统方法,需要添加大量 ->orWhere(‘field’, ‘like’, ‘%’ . $keyword . ‘%’) 语句,造成冗余。
后来根据 where() 里面可以传入闭包,在 helpers.php 写了一个函数,调用该函数,即可省去大量 orWhere() 语句。
/**
* 带拼音的查询
* @author long2ge
* @param string $keyword 关键词
* @param string[] $prefixes 前缀
* @param string[] $suffixes 后缀
* @param bool $hasLeftPercentage 有否左百分号
* @param mixed ...$fields 字段
* @return Closure
*/
function queryWithPinyin(
string $keyword,
array $prefixes,
array $suffixes,
bool $hasLeftPercentage = true,
...$fields
): Closure {
if (func_num_args() < 5 || ! func_get_arg(4)) {
throw new BadFunctionCallException(__FUNCTION__ . '() requires a 5th parameter which is not empty!');
}
$keyword = ($hasLeftPercentage ? '%' : '') . $keyword . '%';
$arg_5 = func_get_arg(4);
$keywordConds = $prefixConds = $suffixConds = [];
if (is_array($arg_5)) {
$fields = $arg_5;
} elseif ($arg_5 instanceof Illuminate\Contracts\Support\Arrayable) {
$fields = $arg_5->toArray();
}
$keywordConds = array_map(function ($field) use ($keyword) {
return [$field, 'like', $keyword];
}, $fields);
$hasMultibyteChar = strlen($keyword) != mb_strlen($keyword);
if ($prefixes && ! $hasMultibyteChar) {
foreach ($prefixes as $prefix) {
$prefixConds = array_merge($prefixConds, array_map(function ($field) use ($keyword) {
return [$prefix . '_' . $field, 'like', $keyword];
}, $fields));
}
}
if ($suffixes && ! $hasMultibyteChar) {
foreach ($suffixes as $suffix) {
$suffixConds = array_merge($suffixConds, array_map(function ($field) use ($keyword) {
return [$field . '_' . $suffix, 'like', $keyword];
}, $fields));
}
}
$conds = array_merge($keywordConds, $prefixConds, $suffixConds);
return function ($query) use ($conds) {
foreach ($conds as $cond) {
$query->orWhere([$cond]);
}
};
}
这样子,添加拼音及其首字母查询功能,就无须再大量调用 orWhere() 方法,可以把上述函数返回结果直接作为传入 where() 乃至 whereHas() 的参数。
public function getProductCollection(int $shopId, string $keyword)
{
return Product::where('shop_id', $shopId)
->where(function ($q) use ($keyword) {
$q->where(queryWithPinyin(
$keyword,
['initial'],
['pinyin'],
true,
'product_code',
'product_name',
'product_alias'
))->orWhereHas('factory', queryWithPinyin( // 生产商暂不支持首字母搜索
$keyword,
[],
['pinyin'],
false,
['factory_name', 'factory_alias']
));
})->get();
}
推荐文章: