面板构建器 - 资源
新建记录
保存前自定义数据
有时,你需要在保存到数据库之前修改表单数据。你可以定义 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
文件。
Still need help? Join our Discord community or open a GitHub discussion