验证

您是视觉学习者吗?
通过我们深入的屏幕录制掌握 Livewire
立即观看

Livewire 旨在让验证用户的输入并向他们提供反馈尽可能愉快。通过构建在 Laravel 的验证功能之上,Livewire 利用您现有的知识,同时还为您提供强大的附加功能,如实时验证。

以下是一个 CreatePost 组件示例,它演示了 Livewire 中最基本的验证工作流

<?php
 
namespace App\Livewire;
 
use Livewire\Component;
use App\Models\Post;
 
class CreatePost extends Component
{
public $title = '';
 
public $content = '';
 
public function save()
{
$validated = $this->validate([
'title' => 'required|min:3',
'content' => 'required|min:3',
]);
 
Post::create($validated);
 
return redirect()->to('/posts');
}
 
public function render()
{
return view('livewire.create-post');
}
}
<form wire:submit="save">
<input type="text" wire:model="title">
<div>@error('title') {{ $message }} @enderror</div>
 
<textarea wire:model="content"></textarea>
<div>@error('content') {{ $message }} @enderror</div>
 
<button type="submit">Save</button>
</form>

如您所见,Livewire 提供了一个 validate() 方法,您可以调用它来验证您的组件属性。它返回经过验证的数据集,然后您可以安全地将其插入数据库。

在前端,您可以使用 Laravel 现有的 Blade 指令向您的用户显示验证消息。

有关更多信息,请参阅 Laravel 关于在 Blade 中呈现验证错误的文档

验证属性

如果您希望将组件的验证规则直接与属性放在一起,则可以使用 Livewire 的 #[Validate] 属性。

通过使用 #[Validate] 将验证规则与属性关联,Livewire 将在每次更新之前自动运行属性验证规则。但是,您仍应在将数据持久化到数据库之前运行 $this->validate(),以便对尚未更新的属性也进行验证。

use Livewire\Attributes\Validate;
use Livewire\Component;
use App\Models\Post;
 
class CreatePost extends Component
{
#[Validate('required|min:3')]
public $title = '';
 
#[Validate('required|min:3')]
public $content = '';
 
public function save()
{
$this->validate();
 
Post::create([
'title' => $this->title,
'content' => $this->content,
]);
 
return redirect()->to('/posts');
}
 
// ...
}
验证属性不支持规则对象

PHP 属性仅限于某些语法,如纯字符串和数组。如果您发现自己想要使用运行时语法,如 Laravel 的规则对象 (Rule::exists(...)),则应改为 在您的组件中定义一个 rules() 方法

在文档中了解更多关于将 Laravel 规则对象与 Livewire 一起使用

如果你希望对何时验证属性有更多控制,可以将 onUpdate: false 参数传递给 #[Validate] 属性。这将禁用任何自动验证,并假定你希望使用 $this->validate() 方法手动验证属性。

use Livewire\Attributes\Validate;
use Livewire\Component;
use App\Models\Post;
 
class CreatePost extends Component
{
#[Validate('required|min:3', onUpdate: false)]
public $title = '';
 
#[Validate('required|min:3', onUpdate: false)]
public $content = '';
 
public function save()
{
$validated = $this->validate();
 
Post::create($validated);
 
return redirect()->to('/posts');
}
 
// ...
}

自定义属性名称

如果你希望自定义注入到验证消息中的属性名称,可以使用 as: 参数。

use Livewire\Attributes\Validate;
 
#[Validate('required', as: 'date of birth')]
public $dob;

当在上述代码段中验证失败时,Laravel 将使用“出生日期”而不是“dob”作为验证消息中字段的名称。生成的错误消息将是“出生日期字段是必需的”,而不是“dob 字段是必需的”。

自定义验证消息

要绕过 Laravel 的验证消息并用你自己的消息替换它,可以在 #[Validate] 属性中使用 message: 参数。

use Livewire\Attributes\Validate;
 
#[Validate('required', message: 'Please provide a post title')]
public $title;

现在,当此属性的验证失败时,消息将是“请提供帖子标题”,而不是“标题字段是必需的”。

如果你希望为不同的规则添加不同的消息,可以简单地提供多个 #[Validate] 属性。

#[Validate('required', message: 'Please provide a post title')]
#[Validate('min:3', message: 'This title is too short')]
public $title;

退出本地化

默认情况下,Livewire 规则消息和属性使用 Laravel 的翻译助手:trans() 进行本地化。

你可以通过将 translate: false 参数传递给 #[Validate] 属性来退出本地化。

#[Validate('required', message: 'Please provide a post title', translate: false)]
public $title;

自定义键

当使用 #[Validate] 属性直接将验证规则应用于属性时,Livewire 假定验证键应该是属性本身的名称。但是,有时你可能希望自定义验证键。

例如,你可能希望为数组属性及其子项提供单独的验证规则。在这种情况下,你可以传递一个键值对数组,而不是将验证规则作为第一个参数传递给 #[Validate] 属性。

#[Validate([
'todos' => 'required',
'todos.*' => [
'required',
'min:3',
new Uppercase,
],
])]
public $todos = [];

现在,当用户更新 $todos 或调用 validate() 方法时,将应用这两个验证规则。

表单对象

随着 Livewire 组件添加的属性和验证规则越来越多,它可能会开始显得过于拥挤。为了减轻这种痛苦,并为代码重用提供有用的抽象,您可以使用 Livewire 的表单对象来存储您的属性和验证规则。

以下是相同的 CreatePost 示例,但现在属性和规则已提取到名为 PostForm 的专用表单对象中

<?php
 
namespace App\Livewire\Forms;
 
use Livewire\Attributes\Validate;
use Livewire\Form;
 
class PostForm extends Form
{
#[Validate('required|min:3')]
public $title = '';
 
#[Validate('required|min:3')]
public $content = '';
}

现在可以在 CreatePost 组件上将 PostForm 定义为一个属性

<?php
 
namespace App\Livewire;
 
use App\Livewire\Forms\PostForm;
use Livewire\Component;
use App\Models\Post;
 
class CreatePost extends Component
{
public PostForm $form;
 
public function save()
{
Post::create(
$this->form->all()
);
 
return redirect()->to('/posts');
}
 
// ...
}

如您所见,我们无需单独列出每个属性,而是可以使用表单对象上的 ->all() 方法检索所有属性值。

此外,在模板中引用属性名称时,您必须在每个实例前加上 form.

<form wire:submit="save">
<input type="text" wire:model="form.title">
<div>@error('form.title') {{ $message }} @enderror</div>
 
<textarea wire:model="form.content"></textarea>
<div>@error('form.content') {{ $message }} @enderror</div>
 
<button type="submit">Save</button>
</form>

使用表单对象时,每次更新属性时都会运行 #[Validate] 属性验证。但是,如果您通过在属性上指定 onUpdate: false 来禁用此行为,则可以使用 $this->form->validate() 手动运行表单对象的验证

public function save()
{
Post::create(
$this->form->validate()
);
 
return redirect()->to('/posts');
}

表单对象是对大多数大型数据集的有用抽象,并且具有多种其他功能,使其更加强大。有关更多信息,请查看全面的 表单对象文档

实时验证

实时验证是指在用户填写表单时验证其输入,而不是等到提交表单时再验证。

通过直接在 Livewire 属性上使用 #[Validate] 属性,每当向服务器发送网络请求以更新属性的值时,都会应用提供的验证规则。

这意味着为用户提供特定输入的实时验证体验,无需额外的后端工作。唯一需要的是使用 wire:model.livewire:model.blur 指示 Livewire 在填写字段时触发网络请求。

在下面的示例中,已将 wire:model.blur 添加到文本输入中。现在,当用户在字段中键入内容,然后切换或单击离开字段时,将使用更新的值触发网络请求,并将运行验证规则

<form wire:submit="save">
<input type="text" wire:model.blur="title">
 
<!-- -->
</form>

如果您使用 rules() 方法为属性声明验证规则,而不是使用 #[Validate] 属性,您仍然可以包含一个不带参数的 #[Validate] 属性,以保留实时验证行为

use Livewire\Attributes\Validate;
use Livewire\Component;
use App\Models\Post;
 
class CreatePost extends Component
{
#[Validate]
public $title = '';
 
public $content = '';
 
public function rules()
{
return [
'title' => 'required|min:5',
'content' => 'required|min:5',
];
}
 
public function save()
{
$validated = $this->validate();
 
Post::create($validated);
 
return redirect()->to('/posts');
}

现在,在上面的示例中,即使 #[Validate] 为空,它也会告诉 Livewire 在每次更新属性时运行 rules() 提供的字段验证。

自定义错误消息

开箱即用,Laravel 提供明智的验证消息,例如“标题字段是必需的”,如果 $title 属性附加了 required 规则。

但是,您可能需要自定义这些错误消息的语言,以更好地适应您的应用程序及其用户。

自定义属性名称

有时,您正在验证的属性具有不适合向用户显示的名称。例如,如果您在应用程序中有一个名为 dob 的数据库字段,表示“出生日期”,您希望向用户显示“出生日期字段是必需的”,而不是“dob 字段是必需的”。

Livewire 允许您使用 as: 参数为属性指定备用名称

use Livewire\Attributes\Validate;
 
#[Validate('required', as: 'date of birth')]
public $dob = '';

现在,如果 required 验证规则失败,错误消息将显示“出生日期字段是必需的”,而不是“dob 字段是必需的”。

自定义消息

如果自定义属性名称还不够,您可以使用 message: 参数自定义整个验证消息

use Livewire\Attributes\Validate;
 
#[Validate('required', message: 'Please fill out your date of birth.')]
public $dob = '';

如果您有多个规则要自定义消息,建议您为每个规则使用完全独立的 #[Validate] 属性,如下所示

use Livewire\Attributes\Validate;
 
#[Validate('required', message: 'Please enter a title.')]
#[Validate('min:5', message: 'Your title is too short.')]
public $title = '';

如果您想改用 #[Validate] 属性的数组语法,您可以指定自定义属性和消息,如下所示

use Livewire\Attributes\Validate;
 
#[Validate([
'titles' => 'required',
'titles.*' => 'required|min:5',
], message: [
'required' => 'The :attribute is missing.',
'titles.required' => 'The :attribute are missing.',
'min' => 'The :attribute is too short.',
], attribute: [
'titles.*' => 'title',
])]
public $titles = [];

定义 rules() 方法

作为 Livewire 的 #[Validate] 属性的替代方案,您可以在组件中定义一个名为 rules() 的方法,并返回一个字段列表和相应的验证规则。如果您尝试使用 PHP 属性中不支持的运行时语法,这将很有帮助,例如 Laravel 规则对象,如 Rule::password()

当你在组件内部运行 $this->validate() 时,这些规则将被应用。你还可以定义 messages()validationAttributes() 函数。

示例如下

use Livewire\Component;
use App\Models\Post;
use Illuminate\Validation\Rule as ValidationRule;
 
class CreatePost extends Component
{
public $title = '';
 
public $content = '';
 
public function rules()
{
return [
'title' => ValidationRule::exists('posts', 'title'),
'content' => 'required|min:3',
];
}
 
public function messages()
{
return [
'content.required' => 'The :attribute are missing.',
'content.min' => 'The :attribute is too short.',
];
}
 
public function validationAttributes()
{
return [
'content' => 'description',
];
}
 
public function save()
{
$this->validate();
 
Post::create([
'title' => $this->title,
'content' => $this->content,
]);
 
return redirect()->to('/posts');
}
 
// ...
}
rules() 方法不会在数据更新时验证

当通过 rules() 方法定义规则时,Livewire 将仅在你运行 $this->validate() 时使用这些验证规则来验证属性。这与标准 #[Validate] 属性不同,后者会在每次通过类似 wire:model 的方式更新字段时应用。若要将这些验证规则应用于每次更新的属性,你仍然可以使用 #[Validate],而无需额外参数。

在使用 Livewire 的验证实用程序时,你的组件不应具有 $rules$messages$validationAttributes$validationCustomValues 属性,除非你正在自定义验证过程。否则,这些属性会与 Livewire 的机制冲突。

使用 Laravel 规则对象

Laravel Rule 对象是一种非常强大的方式,可将高级验证行为添加到你的表单中。

以下是如何将规则对象与 Livewire 的 rules() 方法结合使用以实现更复杂验证的示例

<?php
 
namespace App\Livewire;
 
use Illuminate\Validation\Rule;
use App\Models\Post;
use Livewire\Form;
 
class UpdatePost extends Form
{
public ?Post $post;
 
public $title = '';
 
public $content = '';
 
public function rules()
{
return [
'title' => [
'required',
Rule::unique('posts')->ignore($this->post),
],
'content' => 'required|min:5',
];
}
 
public function mount()
{
$this->title = $this->post->title;
$this->content = $this->post->content;
}
 
public function update()
{
$this->validate();
 
$this->post->update($this->all());
 
$this->reset();
}
 
// ...
}

手动控制验证错误

Livewire 的验证实用程序应处理最常见的验证场景;但是,有时你可能希望完全控制组件中的验证消息。

以下是用于操作 Livewire 组件中验证错误的所有可用方法

方法 说明
$this->addError([key], [message]) 手动向错误包中添加验证消息
$this->resetValidation([?key]) 重置所提供键的验证错误,或在未提供键的情况下重置所有错误
$this->getErrorBag() 检索 Livewire 组件中使用的底层 Laravel 错误包
$this->addError() 与表单对象一起使用

当在表单对象内使用 $this->addError 手动添加错误时,键将自动添加父组件中分配给表单的属性名称作为前缀。例如,如果你在组件中将表单分配给名为 $data 的属性,则键将变为 data.key

访问验证器实例

有时你可能希望访问 Livewire 在 validate() 方法中内部使用的验证器实例。这可以通过 withValidator 方法实现。你提供的闭包会收到完全构造的验证器作为参数,允许你在实际评估验证规则之前调用其任何方法。

下面是拦截 Livewire 内部验证器以手动检查条件并添加其他验证消息的示例

use Livewire\Attributes\Validate;
use Livewire\Component;
use App\Models\Post;
 
class CreatePost extends Component
{
#[Validate('required|min:3')]
public $title = '';
 
#[Validate('required|min:3')]
public $content = '';
 
public function boot()
{
$this->withValidator(function ($validator) {
$validator->after(function ($validator) {
if (str($this->title)->startsWith('"')) {
$validator->errors()->add('title', 'Titles cannot start with quotations');
}
});
});
}
 
public function save()
{
Post::create($this->all());
 
return redirect()->to('/posts');
}
 
// ...
}

使用自定义验证器

如果您希望在 Livewire 中使用自己的验证系统,那没问题。Livewire 会捕获组件内部引发的任何 ValidationException 异常,并向视图提供错误,就像您使用 Livewire 自身的 validate() 方法一样。

下面是 CreatePost 组件的示例,但不是使用 Livewire 的验证功能,而是创建并应用完全自定义的验证器到组件属性

use Illuminate\Support\Facades\Validator;
use Livewire\Component;
use App\Models\Post;
 
class CreatePost extends Component
{
public $title = '';
 
public $content = '';
 
public function save()
{
$validated = Validator::make(
// Data to validate...
['title' => $this->title, 'content' => $this->content],
 
// Validation rules to apply...
['title' => 'required|min:3', 'content' => 'required|min:3'],
 
// Custom validation messages...
['required' => 'The :attribute field is required'],
)->validate();
 
Post::create($validated);
 
return redirect()->to('/posts');
}
 
// ...
}

测试验证

Livewire 为验证场景提供了有用的测试实用程序,例如 assertHasErrors() 方法。

下面是一个基本测试用例,它确保如果未为 title 属性设置任何输入,则会引发验证错误

<?php
 
namespace Tests\Feature\Livewire;
 
use App\Livewire\CreatePost;
use Livewire\Livewire;
use Tests\TestCase;
 
class CreatePostTest extends TestCase
{
/** @test */
public function cant_create_post_without_title()
{
Livewire::test(CreatePost::class)
->set('content', 'Sample content...')
->call('save')
->assertHasErrors('title');
}
}

除了测试错误的存在,assertHasErrors 还允许您通过将规则作为方法的第二个参数传递给要断言的规则来缩小断言范围

/** @test */
public function cant_create_post_with_title_shorter_than_3_characters()
{
Livewire::test(CreatePost::class)
->set('title', 'Sa')
->set('content', 'Sample content...')
->call('save')
->assertHasErrors(['title' => ['min:3']]);
}

您还可以同时断言多个属性的验证错误的存在

/** @test */
public function cant_create_post_without_title_and_content()
{
Livewire::test(CreatePost::class)
->call('save')
->assertHasErrors(['title', 'content']);
}

有关 Livewire 提供的其他测试实用程序的更多信息,请查看 测试文档

已弃用的 [#Rule] 属性

当 Livewire v3 首次发布时,它使用术语“规则”而不是“验证”作为其验证属性 (#[Rule])。

由于与 Laravel 规则对象命名冲突,此后已更改为 #[Validate]。Livewire v3 中同时支持这两种方式,但建议您将所有 #[Rule] 替换为 #[Validate] 以保持最新。