在构建支持多语言的后台管理系统时,我们常遇到这样的业务约束:同一个分类ID在不同的语言下可以存在,但某一语言加分类ID的组合必须唯一。借助Laravel的表单请求(Form Request),可以把这种组合唯一性校验从控制器中剥离出来,让代码更清晰。

基础组合唯一性规则
假设数据表 categories 中包含字段 id、lang、category_id 与 name。我们要在新增时确保 lang 与 category_id 的组合不重复,可在表单请求的 rules 方法中使用 unique 规则的 where 约束。
<?php
namespace AppHttpRequests;
use IlluminateFoundationHttpFormRequest;
class StoreCategoryRequest extends FormRequest
{
public function rules()
{
return [
// lang 与 category_id 组合唯一
'lang' => 'required|string',
'category_id' => 'required|integer',
'name' => [
'required',
'string',
// 在 categories 表中,name 唯一,且 lang 等于当前输入的语言
IlluminateValidationRule::unique('categories')
->where(function ($query) {
return $query->where('lang', $this->input('lang'))
->where('category_id', $this->input('category_id'));
}),
],
];
}
}
更新时忽略自身记录
在编辑分类时,需要忽略当前正在更新的那一条记录,否则会因为查到自身而报错。此时应使用 ignore 方法。
<?php
namespace AppHttpRequests;
use IlluminateFoundationHttpFormRequest;
use IlluminateValidationRule;
class UpdateCategoryRequest extends FormRequest
{
public function rules()
{
$id = $this->route('category');
return [
'lang' => 'required|string',
'category_id' => 'required|integer',
'name' => [
'required',
'string',
Rule::unique('categories')
->where(function ($query) {
return $query->where('lang', $this->input('lang'))
->where('category_id', $this->input('category_id'));
})
->ignore($id), // 忽略当前记录
],
];
}
}
常见错误与排查
- 忘记在 where 闭包中使用 $this->input() 获取请求参数,导致语言或分类ID条件为空。
- 数据表中 lang 与 category_id 字段类型不一致,如一个是 varchar 一个是 int,引起隐式转换使唯一判断失效。
- 使用 ignore 时传入了错误的主键字段,应确认表主键是否为 id。
小结
通过表单请求类的 Rule::unique 配合 where 条件,可以非常直观地实现语言与分类ID的组合唯一性校验。这种做法将校验逻辑集中管理,既方便单元测试,也避免了控制器中堆砌重复判断代码。