
在 laravel 中使用 mysql 全文搜索时,若同时添加非全文字段(如 status、type)的筛选条件,因 sql 运算符优先级问题,未加括号会导致 and/or 逻辑错误,使其他条件失效——正确做法是将所有 match...or 逻辑整体包裹在括号内。
在 laravel 中使用 mysql 全文搜索时,若同时添加非全文字段(如 status、type)的筛选条件,因 sql 运算符优先级问题,未加括号会导致 and/or 逻辑错误,使其他条件失效——正确做法是将所有 match...or 逻辑整体包裹在括号内。
Laravel 的 whereRaw() 方法直接拼接原生 SQL,但不会自动处理运算符优先级。MySQL 中 AND 的优先级高于 OR,因此原始查询:
->whereRaw(
"products.type = ?
AND MATCH(keywords.keyword) AGAINST(? IN BOOLEAN MODE)
OR MATCH(products.description) AGAINST(? IN BOOLEAN MODE)
OR MATCH(products.description_en) AGAINST(? IN BOOLEAN MODE)",
['image', $searchTerms, $searchTerms, $searchTerms]
)
实际等价于:
(products.type = 'image' AND MATCH(...) AGAINST(...)) OR MATCH(...) AGAINST(...) OR MATCH(...) AGAINST(...)
这导致 products.type = 'image' 和 status = 1(来自 scopeAccepted())仅作用于第一个 MATCH,而后续两个 OR 分支完全绕过类型与状态限制,从而返回不符合业务规则的数据。
PHP中文网提供Laravel 13.2.0版本下载,Laravel框架 是基于 PHP 8.3+ 的高性能框架,官方推荐通过 Composer 安装。它内置 AI SDK、JSON:API Resources 及原生向量搜索,支持属性驱动开发与队列路由,大幅提升开发效率。相比旧版,13.2.0 优化了缓存 TTL 管理与实时通信,无需 Redis 即可横向扩展。作为现代 Web 开发首选,它兼顾安全与极速体验,助您快速构建企业级应用。
✅ 正确写法是显式用括号提升逻辑分组优先级:
Product::accepted()
->select(
'products.id as id',
'products.type',
'products.display_image as display_path',
'products.watermark',
DB::raw("CONCAT('[', GROUP_CONCAT(JSON_OBJECT('id', keywords.id, 'keyword', keywords.keyword) ORDER BY keywords.id SEPARATOR ','), ']') AS keywords")
)
->join('products_keywords', 'products_keywords.product_id', '=', 'products.id')
->join('keywords', 'keywords.id', '=', 'products_keywords.keyword_id')
->whereRaw(
"products.type = ?
AND (
MATCH(keywords.keyword) AGAINST(? IN BOOLEAN MODE)
OR MATCH(products.description) AGAINST(? IN BOOLEAN MODE)
OR MATCH(products.description_en) AGAINST(? IN BOOLEAN MODE)
)",
['image', $searchTerms, $searchTerms, $searchTerms]
)
->groupBy('products.id', 'products.display_image', 'products.type', 'products.watermark')
->paginate(50);
⚠️ 注意事项:
- GROUP BY 中应明确列出所有 SELECT 中的非聚合字段(Laravel 8.73+ 及 MySQL 5.7+ 严格模式下必需),避免 SQL 错误;
- 确保对应字段已建立 FULLTEXT 索引(如 ALTER TABLE keywords ADD FULLTEXT(keyword););
- scopeAccepted() 返回 $this->where(...) 是正确用法(注意:应为 $query->where(...),当前代码存在模型实例误用风险,建议修正为 return $query->where('products.status', '1'););
- 若搜索关键词含特殊字符(如 +, -, "),需提前转义或使用 DB::raw() 构建安全布尔查询。
通过合理分组全文匹配逻辑,可确保业务约束(如 type = 'image' 和 status = 1)始终生效,真正实现“精准过滤 + 全文检索”的双重目标。










