公告: 旧版文档请移步 -> http://v2.laravel-filament.cn/docs

Languages

Version

Theme

面板构建器 - 资源

编辑记录

填充表单前自定义数据

你可能想要在记录填充到表单前修改数据。你可以通过定义编辑页面类中的 mutateFormDataBeforeFill() 方法修改 $data 数组,并在填充到表单前返回修改后的版本:

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

此外,如果你在模态框 Action 中编辑记录,请查看 Action 文档

保存前自定义数据

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

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

此外,如果你在模态框 Action 中编辑记录,请查看 Action 文档

自定义保存过程

你可以使用编辑页面类中 handleRecordUpdate() 方法调整记录更新方式:

use Illuminate\Database\Eloquent\Model;
 
protected function handleRecordUpdate(Model $record, array $data): Model
{
$record->update($data);
 
return $record;
}

此外,如果你在模态框 Action 中编辑记录,请查看 Action 文档

自定义表单重定向

默认情况下,表单保存后,用户不会被重定向到其他页面。

你可以重写编辑页面类中 getRedirectUrl() 方法,自定义表单保存后的跳转页面。

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

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

或者查看页面

protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('view', ['record' => $this->getRecord()]);
}

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

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

自定义保存通知

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

要自定义通知的文本内容,在编辑类中定义 getSavedNotificationTitle 方法:

protected function getSavedNotificationTitle(): ?string
{
return 'User updated';
}

此外,如果你在模态框 Action 中编辑记录,请查看 Action 文档

你可以在编辑页类中重写 getSavedNotification() 方法自定义整个通知:

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

要禁用所有通知,在编辑页类的 getSavedNotification() 方法中返回 null

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

生命周期钩子

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

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

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

编辑页可用的一些钩子有:

use Filament\Resources\Pages\EditRecord;
 
class EditUser extends EditRecord
{
// ...
 
protected function beforeFill(): void
{
// 数据库数据填充到表单之前运行
}
 
protected function afterFill(): void
{
// 数据库数据填充到表单之后运行
}
 
protected function beforeValidate(): void
{
// 保存数据时,表单数据进行验证之前运行
}
 
protected function afterValidate(): void
{
// 保存数据时,表单数据进行验证之后运行
}
 
protected function beforeSave(): void
{
// 表单数据保存到数据库之前运行
}
 
protected function afterSave(): void
{
// 表单数据保存到数据库之后运行
}
}

此外,如果你在模态框操作中编辑记录,请查阅 Action 文档

单独保存表单的一部分

你可能希望允许用户用户独立于表单的其余部分来保存表单的一部分。实现该功能的其中一种方式是,在头部和尾部中使用 Section Action。在 action() 方法中,你可以调用 saveFormComponentOnly(),将你想要保存的 Section 组件传入其中:

use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Section;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
 
Section::make('Rate limiting')
->schema([
// ...
])
->footerActions([
fn (string $operation): Action => Action::make('save')
->action(function (Section $component, EditRecord $livewire) {
$livewire->saveFormComponentOnly($component);
Notification::make()
->title('Rate limiting saved')
->body('The rate limiting settings have been saved successfully.')
->success()
->send();
})
->visible($operation === 'edit'),
])

可以使用 $operation helper,以确保该 Action 只有在表单编辑时可见。

停止保存处理过程

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

use Filament\Notifications\Actions\Action;
use Filament\Notifications\Notification;
 
protected function beforeSave(): void
{
if (! $this->getRecord()->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 文档

授权

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

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

同时如果模型策略的 delete() 方法中返回的是 true(),用户也可以删除记录。

自定义 Action

操作(Actions) 是页面上展示的按钮,用于让用户在页面中运行 Livewire 方法或者访问 URL。

在资源页面中,操作通常位于两个位置: 页面的右上角和表单下面。

比如,你可以在编辑页面的"删除"按钮旁边添加新的操作按钮:

use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
 
class EditUser extends EditRecord
{
// ...
 
protected function getHeaderActions(): array
{
return [
Actions\Action::make('impersonate')
->action(function (): void {
// ...
}),
Actions\DeleteAction::make(),
];
}
}

或者,在表单下的"保存"按钮旁增加一个新按钮:

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

要查看 Action 的整个 API,请访问页面部分

添加保存 Action 按钮到头部

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

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

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

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

创建另一个编辑页面

一个编辑页可能空间不过,无法让用户浏览多个表单字段。你为资源创建任意数量的编辑页。如果你正在使用资源子导航,这一点尤其有用,因为你可以轻松地在不同的编辑页面之间切换。

要创建编辑页,你可以使用 make:filament-page 命令:

php artisan make:filament-page EditCustomerContact --resource=CustomerResource --type=EditRecord

你必须在资源的 getPages() 方法中注册这个新页面:

public static function getPages(): array
{
return [
'index' => Pages\ListCustomers::route('/'),
'create' => Pages\CreateCustomer::route('/create'),
'view' => Pages\ViewCustomer::route('/{record}'),
'edit' => Pages\EditCustomer::route('/{record}/edit'),
'edit-contact' => Pages\EditCustomerContact::route('/{record}/edit/contact'),
];
}

现在,你可以为这个页面定义表单 form(),它可以包含其他所有未在主编辑页中显示的字段:

use Filament\Forms\Form;
 
public function form(Form $form): Form
{
return $form
->schema([
// ...
]);
}

将编辑页添加到资源子导航

如果你使用资源子导航,你可以在该资源的 getRecordSubNavigation() 中注册该页面:

use App\Filament\Resources\CustomerResource\Pages;
use Filament\Resources\Pages\Page;
 
public static function getRecordSubNavigation(Page $page): array
{
return $page->generateNavigationItems([
// ...
Pages\EditCustomerContact::class,
]);
}

自定义视图

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

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

这个操作假定你已经创建了一个视图:resources/views/filament/resources/users/pages/edit-user.blade.php

以下是该视图可能包含的内容的极简示例:

<x-filament-panels::page>
<x-filament-panels::form wire:submit="save">
{{ $this->form }}
 
<x-filament-panels::form.actions
:actions="$this->getCachedFormActions()"
:full-width="$this->hasFullWidthFormActions()"
/>
</x-filament-panels::form>
 
@if (count($relationManagers = $this->getRelationManagers()))
<x-filament-panels::resources.relation-managers
:active-manager="$this->activeRelationManager"
:managers="$relationManagers"
:owner-record="$record"
:page-class="static::class"
/>
@endif
</x-filament-panels::page>

在查看默认视图包含的内容,你可以查阅项目中的 vendor/filament/filament/resources/views/resources/pages/edit-record.blade.php 文件。

Edit on GitHub

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