Skip to content
全部文档

在 Blade 视图中渲染表单

WARNING

继续之前,请确认项目中已安装 filament/forms。可通过运行以下命令检查:

bash
composer show filament/forms

若尚未安装,请参阅安装指南,并按说明配置独立组件

设置 Livewire 组件

首先,生成一个新的 Livewire 组件:

bash
php artisan make:livewire CreatePost

然后,在页面上渲染该 Livewire 组件:

blade
@livewire('create-post')

或者,你也可以使用整页 Livewire 组件:

php
use App\Livewire\CreatePost;
use Illuminate\Support\Facades\Route;

Route::get('posts/create', CreatePost::class);

添加表单

WARNING

继续之前,请确保项目中已安装 Forms 包。请参阅安装指南,并按说明配置独立组件

向 Livewire 组件类添加表单时有 5 项主要任务,每一项都很关键:

  1. 实现 `HasSchemas` 接口并使用 `InteractsWithSchemas` trait。
  2. 定义一个公共 Livewire 属性来存储表单数据。本例中我们称之为 `$data`,你也可以使用任意名称。
  3. 添加 `form()` 方法,在此配置表单。[添加表单的 schema](/5.x/forms/overview#form-schemas),并告诉 Filament 将表单数据存储在 `$data` 属性中(使用 `statePath('data')`)。
  4. 在 `mount()` 中用 `$this->form->fill()` 初始化表单。你构建的每个表单都必须这样做,即使没有任何初始数据。
  5. 定义一个处理表单提交的方法。本例中我们称之为 `create()`,你也可以使用任意名称。在该方法中,可用 `$this->form->getState()` 验证并获取表单数据。务必使用此方法,而不是直接访问 `$this->data` 属性,因为表单数据需要先验证并转换为有用格式再返回。
php
<?php

namespace App\Livewire;

use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Concerns\InteractsWithSchemas;
use Filament\Schemas\Concerns\RestrictsFileUploadsToSchemaComponents;
use Filament\Schemas\Contracts\HasSchemas;
use Illuminate\Contracts\View\View;
use Filament\Schemas\Schema;
use Livewire\Component;

class CreatePost extends Component implements HasSchemas
{
    use InteractsWithSchemas;
    use RestrictsFileUploadsToSchemaComponents;
    
    public ?array $data = [];
    
    public function mount(): void
    {
        $this->form->fill();
    }
    
    public function form(Schema $schema): Schema
    {
        return $schema
            ->components([
                TextInput::make('title')
                    ->required(),
                MarkdownEditor::make('content'),
                // ...
            ])
            ->statePath('data');
    }
    
    public function create(): void
    {
        dd($this->form->getState());
    }
    
    public function render(): View
    {
        return view('livewire.create-post');
    }
}

最后,在 Livewire 组件的视图中渲染表单:

blade
<div>
    <form wire:submit="create">
        {{ $this->form }}
        
        <button type="submit">
            Submit
        </button>
    </form>
    
    <x-filament-actions::modals />
</div>

INFO

<x-filament-actions::modals /> 用于渲染表单组件的操作模态框。该代码可放在 <form> 元素外的任意位置,只要仍在 Livewire 组件内即可。

在浏览器中访问你的 Livewire 组件,应该能看到 components() 中的表单组件:

提交带数据的表单后,你会看到表单数据被 dump 到屏幕上。你也可以将数据保存到模型,而不是 dump:

php
use App\Models\Post;

public function create(): void
{
    Post::create($this->form->getState());
}

INFO

filament/forms 还包含以下包:

  • filament/actions
  • filament/schemas
  • filament/support

这些包允许你在 Livewire 组件中使用它们的组件。 例如,若你的表单使用了 Actions,请记得在 Livewire 组件类上实现 HasActions 接口并使用 InteractsWithActions trait。

若在表单中使用了其他 Filament 组件,请务必一并安装并集成对应的包。

用数据初始化表单

要用数据填充表单,只需将该数据传给 $this->form->fill() 方法。例如,若正在编辑已有帖子,可以这样做:

php
use App\Models\Post;

public function mount(Post $post): void
{
    $this->form->fill($post->attributesToArray());
}

务必使用 $this->form->fill() 方法,而不是直接将数据赋给 $this->data 属性。因为帖子数据需要在内部转换为有用格式后再存储。

WARNING

传给 fill() 的数据会作为 Livewire 请求的一部分暴露给 JavaScript。若模型中有包含非有效 UTF-8 二进制数据的列,例如 geometrypointblob 列,则无法序列化为 JSON,页面会加载失败,通常表现为空白屏,且 Laravel 日志中没有错误。

要解决此问题,请将该列加入模型的 $hidden 数组,使其从 attributesToArray() 中排除:

php
protected $hidden = ['location'];

设置表单模型

$form 能访问模型有几个好处:

  • 允许表单中的字段从该模型加载信息。例如,select 字段可以自动[从数据库加载选项](/5.x/forms/select#integrating-with-an-eloquent-relationship)。
  • 表单可以自动加载并保存模型的关系数据。例如,你有一个 Edit Post 表单,其中有一个管理该帖子关联评论的 [Repeater](/5.x/forms/repeater#integrating-with-an-eloquent-relationship)。当你调用 `$this->form->fill([...])` 时,Filament 会自动加载该帖子的评论;调用 `$this->form->getState()` 时会将它们保存回关系。
  • 像 `exists()` 和 `unique()` 这样的验证规则可以自动从模型获取数据库表名。

建议在有模型时始终将其传给表单。如前所述,这会解锁 Filament 表单系统的许多新能力。

要将模型传给表单,请使用 $form->model() 方法:

php
use Filament\Schemas\Schema;

public Post $post;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            // ...
        ])
        ->statePath('data')
        ->model($this->post);
}

在表单提交后传入表单模型

在某些情况下,表单的模型要到表单提交后才可用。例如,在 Create Post 表单中,帖子直到表单提交后才存在。因此,你无法将其传入 $form->model()。不过,你可以改为传入模型类:

php
use App\Models\Post;
use Filament\Schemas\Schema;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            // ...
        ])
        ->statePath('data')
        ->model(Post::class);
}

单独这样做不如传入模型实例强大。例如,创建帖子后关系不会被保存。为此,需要在创建帖子后将其传给表单,并调用 saveRelationships() 将关系保存到它:

php
use App\Models\Post;

public function create(): void
{
    $post = Post::create($this->form->getState());
    
    // Save the relationships from the form to the post after it is created.
    $this->form->model($post)->saveRelationships();
}

将表单数据保存到单独属性

在之前的所有示例中,我们将表单数据保存到 Livewire 组件上的公共 $data 属性。不过,你也可以将数据保存到单独属性。例如,若表单有 title 字段,可将表单数据保存到 $title 属性。为此,完全不要向表单传入 statePath()。确保所有字段在类上都有各自的公共属性。

php
use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;

public ?string $title = null;

public ?string $content = null;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            TextInput::make('title')
                ->required(),
            MarkdownEditor::make('content'),
            // ...
        ]);
}

使用多个表单

可使用 InteractsWithSchemas trait 定义多个表单。每个表单应使用同名方法:

php
use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;

public ?array $postData = [];

public ?array $commentData = [];

public function editPostForm(Schema $schema): Schema
{
    return $schema
        ->components([
            TextInput::make('title')
                ->required(),
            MarkdownEditor::make('content'),
            // ...
        ])
        ->statePath('postData')
        ->model($this->post);
}

public function createCommentForm(Schema $schema): Schema
{
    return $schema
        ->components([
            TextInput::make('name')
                ->required(),
            TextInput::make('email')
                ->email()
                ->required(),
            MarkdownEditor::make('content')
                ->required(),
            // ...
        ])
        ->statePath('commentData')
        ->model(Comment::class);
}

现在,每个表单可通过其名称而不是 form 来访问。例如,要填充帖子表单,可使用 $this->editPostForm->fill([...]);要从评论表单获取数据,可使用 $this->createCommentForm->getState()

你会注意到每个表单都有自己唯一的 statePath()。每个表单会将状态写入 Livewire 组件上的不同数组,因此本例中必须定义公共属性 $postData$commentData

重置表单数据

可随时调用 $this->form->fill() 将表单重置为默认数据。例如,你可能希望每次提交后清空表单内容:

php
use App\Models\Comment;

public function createComment(): void
{
    Comment::create($this->form->getState());

    // Reinitialize the form to clear its data.
    $this->form->fill();
}

使用 CLI 生成表单 Livewire 组件

建议先学习如何手动用表单设置 Livewire 组件;熟练后,可使用 CLI 为你生成表单。

bash
php artisan make:filament-livewire-form RegistrationForm

这会生成新的 app/Livewire/RegistrationForm.php 组件,你可以自行定制。

为 Eloquent 模型生成表单

Filament 还能为特定 Eloquent 模型生成表单。这类表单更强大,因为它们会自动为你保存表单数据,并确保表单字段正确配置以访问该模型。

使用 make:livewire-form 命令生成表单时,会询问模型名称:

bash
php artisan make:filament-livewire-form Products/CreateProduct

为 Eloquent 记录生成编辑表单

默认情况下,向 make:livewire-form 命令传入模型会生成在数据库中创建新记录的表单。若向命令传入 --edit 标志,则会为特定记录生成编辑表单。这会自动用该记录的数据填充表单,并在提交时将数据保存回模型。

bash
php artisan make:filament-livewire-form Products/EditProduct --edit

自动生成表单 Schema

Filament 还能根据模型的数据库列猜测你想要的表单字段。生成表单时可使用 --generate 标志:

bash
php artisan make:filament-livewire-form Products/CreateProduct --generate

文件上传的安全注意事项

InteractsWithSchemas trait 会在每个使用它的组件上暴露 Livewire 的文件上传 RPC 方法——无论表单是否包含上传字段。若你的 Livewire 组件可被你不希望其上传任意文件的用户访问,请添加 RestrictsFileUploadsToSchemaComponents trait。详情见将 Livewire 文件上传限制到 schema 组件