面板构建器 - 资源
新建记录
保存前自定义数据
有时,你需要在保存到数据库之前修改表单数据。你可以定义 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