Laravel 5.5:仅在字段值变更时执行指定验证规则
解决Laravel 5.5中仅字段变更时执行昂贵验证的问题
Laravel本身确实没有内置你想要的only_changed规则,但咱们可以利用Laravel原生的验证特性轻松实现这个需求,不用额外造轮子。最直接的方式是用sometimes方法结合闭包判断字段值是否和模型存储的当前值不同,动态添加开销大的验证规则。
具体实现步骤
假设你正在更新一个User模型,需要对email字段做昂贵的API验证,只有当用户修改了邮箱时才执行这个验证:
1. 获取当前模型实例
首先在控制器里拿到要更新的模型:
$user = \App\User::findOrFail($request->route('user'));
2. 基础验证 + 动态添加条件验证
先定义基础的轻量验证规则,然后用sometimes方法添加仅在字段变更时才生效的规则:
$validator = \Illuminate\Support\Facades\Validator::make($request->all(), [ 'email' => 'required|email', // 基础的轻量验证 ]); // 当邮箱和模型当前值不同时,添加昂贵的验证规则 $validator->sometimes('email', 'unique:users,email|validate_email_via_api', function ($input) use ($user) { return $input->email !== $user->email; }); // 验证失败处理 if ($validator->fails()) { return redirect()->back()->withErrors($validator)->withInput(); }
这里的validate_email_via_api是你自定义的调用远程API的验证规则(需要自己注册),unique规则其实也算“昂贵”的数据库查询,同样可以放在这里。
3. 封装复用(多字段场景)
如果多个字段都需要这个逻辑,咱们可以封装成一个小函数避免重复代码:
/** * 为字段添加“仅变更时验证”的规则 */ function addChangedValidation($validator, $field, $rules, $model) { $validator->sometimes($field, $rules, function ($input) use ($model, $field) { // 新建模型时(模型不存在),直接执行验证;更新时仅字段变更才执行 return !isset($model) || $input->$field !== $model->$field; }); } // 使用示例 addChangedValidation($validator, 'email', 'unique:users,email|validate_email_via_api', $user); addChangedValidation($validator, 'phone', 'validate_phone_via_api', $user);
补充:自定义规则实现方式
如果你更倾向于用类似only_changed|xxx的语法,可以自定义一个验证规则:
在AppServiceProvider的boot方法里注册规则:
use Illuminate\Support\Facades\Validator; public function boot() { Validator::extend('only_changed', function ($attribute, $value, $parameters, $validator) { // 参数格式:['模型类名', '字段名'] [$modelClass, $field] = $parameters; // 从路由获取模型ID(假设路由是 /users/{user} 这种形式) $modelId = request()->route()->parameter(strtolower(class_basename($modelClass))); if (!$modelId) { // 新建场景,直接返回false(让后续规则执行) return false; } $model = $modelClass::findOrFail($modelId); // 值未变更则返回true(跳过后续验证),变更则返回false(执行后续验证) return $value === $model->$field; }); }
然后在验证规则里这样用:
'email' => 'required|email|only_changed:App\User,email|unique:users,email|validate_email_via_api'
不过这种方式需要处理路由参数的命名,灵活性不如sometimes方法,所以更推荐第一种方案。
内容的提问来源于stack exchange,提问作者cweiske
相关产品推荐
相关产品推荐

