在Laravel 8项目开发过程中,验证规则是处理用户输入的核心环节,很多场景下不同模块会用到相同的验证逻辑,比如手机号格式校验、身份证号校验、唯一性校验等。如果每次都重复编写相同的规则代码,不仅会增加代码量,后续修改规则时还需要逐个调整,维护成本很高。通过全局化和复用验证规则,可以把通用验证逻辑抽离成独立模块,在需要的地方直接调用,大幅提升开发效率。
自定义验证规则类实现复用
Laravel 8提供了自定义规则类的功能,我们可以把通用的验证逻辑封装到规则类中,实现规则的复用。首先使用Artisan命令创建规则类:
php artisan make:rule MobileRule
创建完成后,规则类会存放在app/Rules目录下,我们可以编写具体的验证逻辑:
<?php
namespace AppRules;
use IlluminateContractsValidationRule;
class MobileRule implements Rule
{
/**
* 判断验证规则是否通过
*
* @param string $attribute 验证的字段名
* @param mixed $value 字段的值
* @return bool
*/
public function passes($attribute, $value)
{
// 手机号正则校验,匹配1开头的11位数字
return preg_match('/^1[3-9]d{9}$/', $value);
}
/**
* 获取验证失败的错误提示
*
* @return string
*/
public function message()
{
return '请输入正确的手机号码';
}
}
这个MobileRule类封装了手机号校验的逻辑,后续所有需要校验手机号的场景都可以直接调用这个规则类,不需要重复编写正则和错误提示。
全局化验证规则的实现方式
如果希望规则可以在项目的任何地方直接使用,不需要每次都引入规则类,还可以通过扩展Validator类实现规则的全局化。我们可以创建一个规则服务提供者来注册全局规则:
php artisan make:provider RuleServiceProvider
然后在app/Providers/RuleServiceProvider.php中编写规则注册逻辑:
<?php
namespace AppProviders;
use IlluminateSupportServiceProvider;
use IlluminateSupportFacadesValidator;
class RuleServiceProvider extends ServiceProvider
{
/**
* 注册服务
*
* @return void
*/
public function register()
{
//
}
/**
* 启动服务
*
* @return void
*/
public function boot()
{
// 注册全局手机号验证规则,规则名为mobile
Validator::extend('mobile', function ($attribute, $value, $parameters, $validator) {
return preg_match('/^1[3-9]d{9}$/', $value);
});
// 注册全局规则的错误提示
Validator::replacer('mobile', function ($message, $attribute, $rule, $parameters) {
return '请输入正确的手机号码';
});
}
}
之后需要在config/app.php的providers数组中注册这个服务提供者:
'providers' => [
// 其他服务提供者
AppProvidersRuleServiceProvider::class,
],
完成注册后,mobile规则就可以像Laravel内置规则一样全局使用了。
复用验证规则的使用场景
在表单请求类中使用
Laravel的表单请求类可以集中管理验证规则,我们可以在请求类中直接调用复用后的规则:
<?php
namespace AppHttpRequests;
use IlluminateFoundationHttpFormRequest;
use AppRulesMobileRule;
class UserStoreRequest extends FormRequest
{
/**
* 确定用户是否有权限发起请求
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* 获取验证规则
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|string|max:20',
// 使用自定义规则类
'mobile' => ['required', new MobileRule()],
// 使用全局扩展规则
// 'mobile' => 'required|mobile',
'email' => 'required|email|unique:users',
];
}
}
在控制器中直接使用
如果没有使用表单请求类,也可以在控制器的验证方法中直接使用复用规则:
<?php
namespace AppHttpControllers;
use IlluminateHttpRequest;
use AppRulesMobileRule;
class UserController extends Controller
{
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|string|max:20',
'mobile' => ['required', new MobileRule()],
'email' => 'required|email|unique:users',
]);
// 验证通过后的业务逻辑
return response()->json(['message' => '用户创建成功', 'data' => $validated]);
}
}
两种全局化方式的对比
我们可以通过下面的表格了解两种规则全局化复用方式的区别:
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 自定义规则类 | 逻辑封装更独立,支持复杂验证逻辑,可复用性强,符合面向对象思想 | 使用时需要引入规则类,不能直接作为字符串规则使用 | 复杂验证规则,需要携带额外逻辑的场景 |
| 扩展Validator全局规则 | 注册后全局可用,可作为字符串规则直接使用,使用更便捷 | 复杂逻辑封装不如规则类灵活,规则过多时可能难以管理 | 简单通用的验证规则,需要快速调用的场景 |
最佳实践建议
- 简单的通用规则比如手机号、身份证号等,优先使用扩展Validator的方式实现全局化,使用更便捷
- 复杂的验证规则,比如需要查询数据库、携带多个参数的规则,优先使用自定义规则类,逻辑更清晰
- 所有复用规则统一放在
app/Rules目录下,全局规则注册统一放在规则服务提供者中,方便后续维护 - 规则的错误提示尽量统一,避免不同地方相同规则出现不同的错误提示,提升用户体验
- 如果规则需要支持参数,比如长度校验、范围校验,可以在规则类中或者扩展规则时支持参数传递
注意:自定义规则类的passes方法返回true表示验证通过,返回false表示验证失败,错误提示会调用message方法的返回值。