Laravel怎么自定义验证规则_Laravel Rule类扩展教程【灵活】

1次阅读

推荐用 php artisan make:rule uppercase 创建可复用 rule 类,passes() 必须明确返回 true 或 false,不可抛异常或写验证逻辑到 message();数据库查询宜前置缓存,避免事务干扰;不支持依赖注入,禁用 validator::make() 和 auth()->user()。

Laravel怎么自定义验证规则_Laravel Rule类扩展教程【灵活】

怎么写一个自定义 Rule 类(laravel 9+ 推荐方式)

直接用 php artisan make:rule Uppercase 生成类,比手动写闭包或在 Request 类里塞逻辑更清晰、可复用。这个命令生成的 Uppercase 类默认带 passes()message(),你只需要填逻辑。

常见错误是把验证逻辑写进 message() 里,或者忘了返回布尔值——passes() 必须明确 return truefalse,否则验证永远通过。

  • passes() 里别 throw 异常,Laravel 验证器不捕获它,会导致 500
  • 如果要访问当前请求数据,用 $this->data(Laravel 10+)或通过构造函数传入 Request 实例
  • 多语言提示别硬编码,用 __('validation.uppercase'),然后在 lang/en/validation.php 里加对应键

Rule::when() 和 Rule::requiredIf() 什么时候该用闭包而不是自定义 Rule 类

当验证逻辑只在某几个字段间联动、且不跨请求复用时,闭包更轻量。比如「只有勾选了 is_premium 才校验 expiry_date」,用 Rule::requiredIf() 比另建一个 Rule 类合理得多。

容易踩的坑是误以为 Rule::when() 能替代整个规则链——它只是条件开关,里面还得塞真正的规则,比如 Rule::when($request->is_premium, ['required', 'date']),漏掉数组会报错 Array to String conversion

  • Rule::requiredIf() 的回调参数是 Request $request,不是原始数组,别直接取 $_POST
  • 闭包里不能访问 $this,想复用逻辑得提成独立函数或静态方法
  • Laravel 9.28+ 开始,Rule::when() 支持传字符串条件,但推荐用闭包,语义更稳

validateWithBag() 和自定义 Rule 冲突吗

不冲突,但要注意错误包(Error bag)只影响前端渲染位置,不影响 Rule 类内部行为。你写了一个 UniqueEmail Rule,它抛出的错误默认进 default bag;调用 $request->validateWithBag('login') 只是把所有错误都挪到 login 这个 bag 里,Rule 本身完全无感。

真正容易出问题的是:你在 Rule 里手动调用了 Validator::make() 或改了 $validator->errors(),这会绕过 Laravel 的 bag 管理机制,导致错误不进指定 bag。

  • Rule 类里禁止 new Validator 或调用 Validator::make()
  • 想动态加错误?用 $validator->errors()->add('field', 'message'),但仅限在 FormRequestwithValidator() 里做
  • 自定义 Rule 的 message() 返回值仍受 lang/xx/validation.phpcustom 键控制,和 bag 无关

Rule 类里怎么安全地查数据库(避免 N+1 或事务干扰)

Rule 类本身没生命周期钩子,passes() 被调用时,Eloquent 已初始化但事务可能未开启。如果你在 Rule 里写 User::where('email', $value)->exists(),它走的是当前连接,和主事务一致——但若验证失败后回滚,这个查询结果其实已不可信。

更稳妥的做法是:把 DB 查询提到 FormRequestprepareForValidation() 里缓存结果,再传给 Rule;或者用 DB::table() + selectRaw('1') 减少数据传输。

  • 别在 Rule 里用 auth()->user(),因为验证发生在中间件之后、控制器之前,session 可能未完全加载
  • 涉及软删除模型,记得加 ->withoutTrashed(),否则 unique 规则可能误判已删除记录
  • Rule 类不支持依赖注入(如 UserRepository),要用 app() 手动解析,但尽量避免

最常被忽略的一点:Rule 类的 passes() 方法里,$Attribute 是字段名(如 email),$value 是原始输入值——它不会自动经过 cast 或 accessor 处理。如果你的字段是 json 字段或带 mutator,得自己 decode 或调用对应方法,不然对比永远失败。

text=ZqhQzanResources