Languages

Version

Theme

面板构建器 - 资源

新建记录

保存前自定义数据

有时,你需要在保存到数据库之前修改表单数据。你可以定义 mutateFormDataBeforeCreate() 方法,使其接收 $data 数组作为参数,并返回修改过的版本:

protected function mutateFormDataBeforeCreate(array $data): array
{
$data['user_id'] = auth()->id();
 
return $data;
}

此外,如果你是通过模态框 Action 新建记录,请查阅 Action 文档

自定义新建过程

你可以在新建页面类中使用 handleRecordCreation() 方法调整记录创建方式:

use Illuminate\Database\Eloquent\Model;
 
protected function handleRecordCreation(array $data): Model
{
return static::getModel()::create($data);
}

此外,如果你是通过模态框 Action 新建记录,请查阅 Action 文档

自定义重定向

默认情况下,表单保存后,用户会被重定向到资源编辑页,或查看页(当其存在时)。

你可以重写 getRedirectUrl() 自定义表单保存后的跳转页面。

比如,表单可以跳转回列表页

protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('index');
}

如果你希望重定向到上一页,否则重定向到首页:

protected function getRedirectUrl(): string
{
return $this->previousUrl ?? $this->getResource()::getUrl('index');
}

自定义保存通知

当记录创建成功,会派送一个通知给用户,告知操作成功。

要自定义通知标题,在创建页类中定义 getCreatedNotificationTitle() 方法:

protected function getCreatedNotificationTitle(): ?string
{
return 'User registered';
}

另外,如果你是在模态框操作中创建记录,请查看 Action 文档

你可以在创建页类中重写 getCreatedNotification() 方法自定义整个通知:

use Filament\Notifications\Notification;
 
protected function getCreatedNotification(): ?Notification
{
return Notification::make()
->success()
->title('User registered')
->body('The user has been created successfully.');
}

要完全禁用该通知,在新建页的 getCreatedNotification() 方法中返回 null

use Filament\Notifications\Notification;
 
protected function getCreatedNotification(): ?Notification
{
return null;
}

生命周期钩子

钩子可用在页面生命周期的各个节点中执行代码,比如表单数据保存之前。要启用钩子,在页面类中以钩子名新建一个 protected 修饰的方法:

protected function beforeCreate(): void
{
// ...
}

此例中,beforeCreate() 方法中的代码会在表单数据保存到数据库之前被调用。

新建页有一些可用的钩子:

use Filament\Resources\Pages\CreateRecord;
 
class CreateUser extends CreateRecord
{
// ...
 
protected function beforeFill(): void
{
// Runs before the form fields are populated with their default values.
}
 
protected function afterFill(): void
{
// Runs after the form fields are populated with their default values.
}
 
protected function beforeValidate(): void
{
// Runs before the form fields are validated when the form is submitted.
}
 
protected function afterValidate(): void
{
// Runs after the form fields are validated when the form is submitted.
}
 
protected function beforeCreate(): void
{
// Runs before the form fields are saved to the database.
}
 
protected function afterCreate(): void
{
// Runs after the form fields are saved to the database.
}
}

此外,你可以在模态框 Action 中创建记录,请查阅 Action 文档

停止新建处理过程

你可以随时在生命周期钩子内或者 mutation 方法内调用 $this->halt(), 停止整个新建处理过程:

use Filament\Notifications\Actions\Action;
use Filament\Notifications\Notification;
 
protected function beforeCreate(): void
{
if (! auth()->user()->team->subscribed()) {
Notification::make()
->warning()
->title('You don\'t have an active subscription!')
->body('Choose a plan to continue.')
->persistent()
->actions([
Action::make('subscribe')
->button()
->url(route('subscribe'), shouldOpenInNewTab: true),
])
->send();
$this->halt();
}
}

此外,你可以在模态框 Action 中创建记录,请查阅 Action 文档

授权

关于授权,Filament 会监听所有应用中注册的模型策略

如果模型策略的 create() 方法中返回的是 true(),用户可以访问新建页。

Wizards

你可以轻易地将新建过程转换成多步骤向导卡。

在页面类中,添加相应的 HasWizard trait:

use App\Filament\Resources\CategoryResource;
use Filament\Resources\Pages\CreateRecord;
 
class CreateCategory extends CreateRecord
{
use CreateRecord\Concerns\HasWizard;
protected static string $resource = CategoryResource::class;
 
protected function getSteps(): array
{
return [
// ...
];
}
}

getSteps() 数组中,返回 wizard 步骤

use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\Wizard\Step;
 
protected function getSteps(): array
{
return [
Step::make('Name')
->description('Give the category a clear and unique name')
->schema([
TextInput::make('name')
->required()
->live()
->afterStateUpdated(fn ($state, callable $set) => $set('slug', Str::slug($state))),
TextInput::make('slug')
->disabled()
->required()
->unique(Category::class, 'slug', fn ($record) => $record),
]),
Step::make('Description')
->description('Add some extra details')
->schema([
MarkdownEditor::make('description')
->columnSpan('full'),
]),
Step::make('Visibility')
->description('Control who can view it')
->schema([
Toggle::make('is_visible')
->label('Visible to customers.')
->default(true),
]),
];
}

此外,你可以在模态框 Action 中创建记录,请查阅 Action 文档

接下来,新建一条记录看看 Widget 向导的运行情况。编辑仍然使用资源类中定义的表单。

如果你想要允许自由导航,使所有步骤都可以跳过,重写 hasSkippableSteps() 方法:

public function hasSkippableSteps(): bool
{
return true;
}

资源表单和向导中共用字段

如果你想减少资源表单和向导步骤之间的重复工作量,可以为表单字段提取出公共的静态资源方法,这样就能简单地从中找到资源或者向导需要字段实例:

use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
 
class CategoryResource extends Resource
{
public static function form(Form $form): Form
{
return $form
->schema([
static::getNameFormField(),
static::getSlugFormField(),
// ...
]);
}
public static function getNameFormField(): Forms\Components\TextInput
{
return TextInput::make('name')
->required()
->live()
->afterStateUpdated(fn ($state, callable $set) => $set('slug', Str::slug($state)));
}
public static function getSlugFormField(): Forms\Components\TextInput
{
return TextInput::make('slug')
->disabled()
->required()
->unique(Category::class, 'slug', fn ($record) => $record);
}
}
use App\Filament\Resources\CategoryResource;
use Filament\Resources\Pages\CreateRecord;
 
class CreateCategory extends CreateRecord
{
use CreateRecord\Concerns\HasWizard;
protected static string $resource = CategoryResource::class;
 
protected function getSteps(): array
{
return [
Step::make('Name')
->description('Give the category a clear and unique name')
->schema([
CategoryResource::getNameFormField(),
CategoryResource::getSlugFormField(),
]),
// ...
];
}
}

导入资源记录

Filament 引入了 ImportAction,你可以将其添加到列表页getHeaderActions() 中。它允许用户上传 CSV 数据将其导入到资源中:

use App\Filament\Imports\ProductImporter;
use Filament\Actions;
 
protected function getHeaderActions(): array
{
return [
Actions\ImportAction::make()
->importer(ProductImporter::class),
Actions\CreateAction::make(),
];
}

需要创建导入类,以告知 Filament 如何导入 CSV 的每个行。你可以在 Action 文档中了解 ImportAction 的更多详情。

自定义 Action

"Actions" 是显示在页面上的按钮,允许用户在页面上运行 Livewire 方法或者访问 URL。

在资源页面中,Action 通常处于两个地方:页面的右上角以及表单下面。

比如,你可以在创建页面的头部添加新的按钮 Action:

use App\Filament\Imports\UserImporter;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
 
class CreateUser extends CreateRecord
{
// ...
 
protected function getHeaderActions(): array
{
return [
Actions\ImportAction::make()
->importer(UserImporter::class),
];
}
}

或者,在表单的"新建"按钮旁边添加新按钮:

use Filament\Actions\Action;
use Filament\Resources\Pages\CreateRecord;
 
class CreateUser extends CreateRecord
{
// ...
 
protected function getFormActions(): array
{
return [
...parent::getFormActions(),
Action::make('close')->action('createAndClose'),
];
}
 
public function createAndClose(): void
{
// ...
}
}

要查看整个 Action API,请参考页面章节

添加新建 Action 按钮到头部

通过重写 getHeaderActions() 并使用 getCreateFormAction(),可以将新建按钮移动到页面的头部。你需要将 formId() 传递给该 Action,以指定该 Action 要提交的表单对应的 form 的 ID,也就是页面视图中使用的 <form> ID:

protected function getHeaderActions(): array
{
return [
$this->getCreateFormAction()
->formId('form'),
];
}

重写 getFormActions() 方法,使之返回空数组,可以移除表单中的所有 Action:

protected function getFormActions(): array
{
return [];
}

自定义视图

要进一步自定义,你可以重写页面类的静态 $view 属性:

protected static string $view = 'filament.resources.users.pages.create-user';

上面的代码假定已经创建了一个视图 ——— resources/views/filament/resources/users/pages/create-user.blade.php

下例是一个视图简单示例,显示视图中可能包含的内容:

<x-filament-panels::page>
<x-filament-panels::form wire:submit="create">
{{ $this->form }}
 
<x-filament-panels::form.actions
:actions="$this->getCachedFormActions()"
:full-width="$this->hasFullWidthFormActions()"
/>
</x-filament-panels::form>
</x-filament-panels::page>

要查看默认视图都包含了哪些东西,可以查看在项目中的 vendor/filament/filament/resources/views/resources/pages/create-record.blade.php 文件。

Edit on GitHub

Still need help? Join our Discord community or open a GitHub discussion