Laravel 内置了丰富的验证规则,但实际业务中常常需要特定的验证逻辑,例如检查用户名是否包含敏感词、验证自定义的优惠券格式等。 本章将介绍如何创建和使用自定义验证规则,让你的验证逻辑更加灵活和可复用。
最简单的自定义规则方式是在验证时直接使用闭包。适用于逻辑简单且只在单个地方使用的情况。
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($request->all(), [
'username' => [
'required',
function ($attribute, $value, $fail) {
if (str_contains($value, 'admin')) {
$fail('用户名不能包含 "admin"。');
}
},
],
]);
if ($validator->fails()) {
// 处理错误
}
>
闭包接收三个参数:$attribute(字段名)、$value(字段值)、$fail(回调函数)。当验证失败时调用 $fail 并传入错误消息。
对于需要复用的验证规则,最佳实践是创建独立的规则类。使用 Artisan 命令快速生成:
php artisan make:rule Uppercase
生成的规则类位于 app/Rules 目录,包含 passes 和 message 两个方法:
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class Uppercase implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (strtoupper($value) !== $value) {
$fail('The :attribute must be uppercase.');
}
}
}
在验证器中使用规则对象:
use App\Rules\Uppercase;
$request->validate([
'code' => ['required', new Uppercase],
]);
ValidationRule 接口(如上所示),也可以实现传统的 Rule 接口,但新方式更简洁。
有时规则需要接收参数,如检查最小长度、特定条件等。可以通过构造函数传递参数:
namespace App\Rules;
use Illuminate\Contracts\Validation\ValidationRule;
class ContainsNumber implements ValidationRule
{
protected $minCount;
public function __construct($minCount = 1)
{
$this->minCount = $minCount;
}
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (preg_match_all('/\d/', $value) < $this->minCount) {
$fail("The :attribute must contain at least {$this->minCount} number(s).");
}
}
}
使用:
$request->validate([
'password' => ['required', new ContainsNumber(2)],
]);
如果你更喜欢使用字符串形式的规则(如 'uppercase'),可以通过 Validator::extend 注册规则。通常在服务提供者的 boot 方法中注册:
namespace App\Providers;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
Validator::extend('uppercase', function ($attribute, $value, $parameters, $validator) {
return strtoupper($value) === $value;
});
// 自定义错误消息
Validator::replacer('uppercase', function ($message, $attribute, $rule, $parameters) {
return str_replace(':attribute', $attribute, 'The :attribute must be uppercase.');
});
}
}
现在可以在验证中直接使用 'uppercase' 规则:
$request->validate([
'code' => 'required|uppercase',
]);
extend 注册的规则是全局的,命名应避免与内置规则冲突。建议为自定义规则添加前缀,如 custom_uppercase。
对于规则对象,可以在 message 方法中返回错误消息。如果需要支持多语言,可以使用 __() 辅助函数:
public function message()
{
return __('validation.custom.uppercase');
}
然后在语言文件(如 resources/lang/zh_CN/validation.php)中定义:
'custom' => [
'uppercase' => '字段必须为大写字母。',
],
假设我们需要一个规则,禁止用户名包含预定义的敏感词列表。
1. 创建规则类
namespace App\Rules;
use Illuminate\Contracts\Validation\ValidationRule;
class NoSensitiveWords implements ValidationRule
{
protected $sensitiveWords = ['admin', 'root', 'test'];
public function validate(string $attribute, mixed $value, Closure $fail): void
{
foreach ($this->sensitiveWords as $word) {
if (stripos($value, $word) !== false) {
$fail("The :attribute cannot contain the word '{$word}'.");
return;
}
}
}
}
2. 在表单请求中使用
use App\Rules\NoSensitiveWords;
public function rules(): array
{
return [
'username' => ['required', 'string', 'min:3', 'max:20', new NoSensitiveWords],
'email' => 'required|email|unique:users',
];
}
3. 在控制器中验证
public function store(StoreUserRequest $request)
{
// 验证已自动通过
User::create($request->validated());
return redirect()->route('users.index');
}
Laravel 11 允许你在验证规则数组中直接使用闭包,甚至支持 Rule::when() 条件规则,使规则定义更灵活。
use Illuminate\Validation\Rule;
$request->validate([
'country' => 'required',
'postal_code' => Rule::when(
$request->country === 'US',
['required', 'regex:/^\d{5}$/'],
['nullable', 'string']
),
]);
>
ContainsNumber、ValidPhoneNumber。Validator::extend 注册全局规则时,注意命名空间,避免与 Laravel 未来版本冲突。'items.*.code' => [new Uppercase],规则对象会逐个应用到每个元素。
validate 方法中,可以通过 $this->validator->getData() 获取所有输入数据(需要先将 validator 注入)。更简单的方式是使用闭包规则,闭包可以访问 $request 或通过 use 传入外部变量。
自定义验证规则让 Laravel 的验证系统更具扩展性,能够适应各种复杂业务场景。无论是简单的闭包规则,还是可复用的规则对象,都能帮助你保持代码整洁和可维护性。 掌握这些技巧后,你可以轻松构建健壮的验证层,提升应用的数据质量和安全性。 下一章我们将学习会话管理,掌握用户状态维护的高级技巧。