基于双值的自定义规则:Region模型Tag唯一性验证规则创建
搞定Region模型Tag唯一性验证的方案
嘿,我明白你的需求了——Tag是由name和countries_id拼接成的小写字符串,得保证它唯一,而且是动态生成的,不能让用户传。咱们一步步来解决这个问题:
核心思路
因为Tag不是请求里直接传的参数,是咱们自己拼的,所以验证的关键是:先拿请求里的name和countries_id生成Tag,再去数据库里查这个Tag是不是已经存在。而且还要考虑更新场景,不能把当前编辑的记录当成重复项。
方案1:完善你已经在用的自定义验证规则
你已经写了RegionUniqueRule,那咱们直接改造这个规则类就行,让它自动处理Tag的生成和唯一性检查:
改造后的自定义规则类
use Illuminate\Contracts\Validation\Rule; use App\Models\Region; class RegionUniqueRule implements Rule { public function passes($attribute, $value) { // 先从请求里拿到countries_id $countriesId = request()->input('countries_id'); // 按照要求生成小写的Tag $tag = strtolower($value) . '-' . $countriesId; // 开始查数据库,看看有没有重复的Tag $query = Region::where('tag', $tag); // 如果是更新操作(比如传了id),要排除当前这条记录 if ($id = request()->input('id')) { $query->where('id', '!=', $id); } // 没找到重复的就返回true,验证通过 return $query->count() === 0; } public function message() { // 给用户友好的提示 return '这个地区名称和国家的组合已经存在啦(重复的Tag)!'; } }
调整你的验证规则数组
然后把验证规则补全,别忘了给countries_id加必填和合法性验证(比如检查这个id是不是真的在countries表里存在):
return [ 'name' => ['required', new RegionUniqueRule()], 'countries_id' => ['required', 'exists:countries,id'], ];
方案2:用Laravel内置的Unique规则,不用写自定义类
要是不想搞自定义规则,直接用Laravel自带的Rule::unique也能搞定,用闭包动态生成查询条件就行:
use Illuminate\Validation\Rule; return [ 'name' => ['required'], 'countries_id' => ['required', 'exists:countries,id'], // 给name加唯一性验证,通过闭包指定Tag的查询条件 'name' => [ 'required', Rule::unique('regions')->where(function ($query) { // 生成要检查的Tag $tag = strtolower(request()->input('name')) . '-' . request()->input('countries_id'); return $query->where('tag', $tag); })->ignore(request()->input('id')) // 更新时跳过当前记录 ], ];
额外的小建议
- 数据库层面加保险:为了防止并发情况下出现重复Tag(比如两个请求同时验证通过,然后都插入数据库),记得给
regions表的tag字段加唯一索引,这样数据库本身会帮咱们拦住重复数据。 - 自动生成Tag:在保存Region记录的时候,自动生成Tag,不用手动写:
// 在Region模型里加这段代码 protected static function boot() { parent::boot(); // 创建记录时自动生成Tag static::creating(function ($region) { $region->tag = strtolower($region->name) . '-' . $region->countries_id; }); // 如果允许更新名称或国家ID,更新时也同步更新Tag static::updating(function ($region) { $region->tag = strtolower($region->name) . '-' . $region->countries_id; }); }
内容的提问来源于stack exchange,提问作者ramiromd
相关产品推荐
相关产品推荐

