Laravel如何验证非关联表字段?禁止分配cat_c类区域
问题场景
用户信息可编辑,用户与区域关联,区域分为不同类别(1: cat_a, 2: cat_b, 3: cat_c),新需求规定区域不得分配至cat_c类别。
表结构
users: id, name areas: id, area_name, responsible_id Categories: id, area_name, cat_name, permissions
请求参数包含areas键,值为区域ID数组(如[1,2,3])。
现有验证规则
public function rules() { $userId = $this->route('user'); $roles = User::listRoles(); return [ 'areas.*' => 'exists:area,id', ]; }
技术问询
Laravel中有没有现成的验证规则,能检查areas表(和users表无直接关联),如果区域属于分类3(cat_c)就验证失败?
请求示例
[1,2,3]:验证失败[1,2]:验证通过
Laravel没有直接匹配该需求的内置验证规则,但可以通过闭包验证或者自定义验证规则类实现,以下是两种可行方案:
方案1:使用闭包验证(快速实现)
直接在现有规则中添加闭包,先验证区域ID存在,再检查其对应的分类是否为禁止的ID:
public function rules() { $userId = $this->route('user'); $roles = User::listRoles(); return [ 'areas.*' => [ 'exists:areas,id', function ($attribute, $value, $fail) { // 通过子查询获取当前区域对应的分类ID $categoryId = DB::table('Categories') ->where('area_name', function ($query) use ($value) { $query->select('area_name') ->from('areas') ->where('id', $value); }) ->value('id'); // 若分类ID为3,抛出验证错误 if ($categoryId == 3) { $fail("区域 {$value} 属于禁止分配的cat_c类别"); } }, ], ]; }
方案2:自定义验证规则类(复用性更高)
如果该验证逻辑需要在多个场景使用,推荐创建独立的规则类:
- 生成规则类:
php artisan make:rule ForbiddenCategoryArea
- 编辑规则类
app/Rules/ForbiddenCategoryArea.php:
namespace App\Rules; use Illuminate\Contracts\Validation\Rule; use Illuminate\Support\Facades\DB; class ForbiddenCategoryArea implements Rule { protected $forbiddenCatId; // 支持传入禁止的分类ID,默认值为3(对应cat_c) public function __construct($forbiddenCatId = 3) { $this->forbiddenCatId = $forbiddenCatId; } public function passes($attribute, $value) { // 关联areas和Categories表,检查是否存在匹配禁止分类的记录 $matchCount = DB::table('areas') ->join('Categories', 'areas.area_name', '=', 'Categories.area_name') ->where('areas.id', $value) ->where('Categories.id', $this->forbiddenCatId) ->count(); // 无匹配记录则验证通过 return $matchCount === 0; } public function message() { return '该区域属于禁止分配的cat_c类别'; } }
- 在验证规则中引入该类:
public function rules() { $userId = $this->route('user'); $roles = User::listRoles(); return [ 'areas.*' => [ 'exists:areas,id', new \App\Rules\ForbiddenCategoryArea(), ], ]; }
两种方案均可实现需求:当传入的区域ID对应分类为3时验证失败,否则验证通过。
内容的提问来源于stack exchange,提问作者MartinTTS
相关产品推荐
相关产品推荐

