关联管理器

Resources

开始

在 Filament 中,“关联管理器(Relation managers)” 允许管理员可以在不离开资源编辑页面的情况下,展示列表、新建、编辑、删除、附加和取消附加、关联和取消关联相关记录。资源类包含了一个静态的 getRelations() 方法,用于为资源注册关联管理器。

要新建关联管理器,你可以使用 make:filament-relation-manager 命令:

php artisan make:filament-relation-manager CategoryResource posts title
  • CategoryResource 是对应父级模型的资源类名。
  • posts 是你想要管理的关联名。
  • title 是用来识别 posts 唯一性的属性名。

这个命令将会创建 CategoryResource/RelationManagers/PostsRelationManager.php 文件。它包含了一个类,让你可以为你的关联管理器定义表单表格

use Filament\Forms;
use Filament\Resources\Form;
use Filament\Resources\Table;
use Filament\Tables;
 
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('title')->required(),
Forms\Components\MarkdownEditor::make('content'),
// ...
]);
}
 
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('title'),
// ...
]);
}

你必须在资源的 getRelations() 方法中注册这些新的模型关联管理器:

public static function getRelations(): array
{
return [
RelationManagers\PostsRelationManager::class,
];
}

对于使用非常规命名规范的关联,你可以在关联管理器中使用 $inverseRelationship 属性中:

protected static ?string $inverseRelationship = 'section'; // 反转关联的模型是 `Category`,所以一般情况下这里是 `category` 而非 `section`。

如果关联管理器中定义了表格和表单,可以通过操作(action)访问编辑页或者查看页

处理软删除

默认情况下,你不能在关联管理器中和已删除的数据进行交互。如果你想要在关联管理器中添加恢复数据、强制删除和过滤垃圾数据等功能,可以在生成关联管理器的时候使用 --soft-deletes 标志:

php artisan make:filament-relation-manager CategoryResource posts title --soft-deletes

记录列表

相关记录会在一个表格中展示。整个关联管理器都是基于这个表格,包括新建编辑附加/分离记录关联/取消关联和删除记录等操作。

按照列表页中的文档,你可以在关联管理器类中使用所有的自定义功能:

此外,你页可以使用表格构造器的其他所有特性。

使用中间属性展示列表

对于 BelongsToManyMorphToMany 关联(relationship),你也可以添加中间表属性。比如,如果你的资源 UserResource 有一个关联管理器 TeamsRelationManager,而且你想要将 role 中间属性添加到表格,你可以:

use Filament\Forms;
use Filament\Resources\Form;
use Filament\Tables;
 
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name'),
Tables\Columns\TextColumn::make('role'),
]);
}

请确保所有的中间属性都在关联反向关联的 withPivot() 方法中罗列出来。

创建记录

使用中间属性新建记录

对于 BelongsToManyMorphToMany 关联(relationship),你也可以添加中间表属性。比如,如果你的资源 UserResource 有一个关联管理器 TeamsRelationManager,你想要在新建表单中添加关联属性,你可以:

use Filament\Forms;
use Filament\Resources\Form;
use Filament\Tables;
 
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')->required(),
Forms\Components\TextInput::make('role')->required(),
// ...
]);
}

请确保所有的中间属性都在关联反向关联的 withPivot() 方法中罗列出来。

保存前自定义数据

有时,你可能需要在最终存入数据库前修改表单数据。此时可以使用 mutateFromDataUsing() 方法,该方法接收一个 $data 数组,返回修改后的数据:

use Filament\Tables\Actions\CreateAction;
 
CreateAction::make()
->mutateFormDataUsing(function (array $data): array {
$data['user_id'] = auth()->id();
 
return $data;
})

自定义新建处理过程

你可以使用 process() 方法微调记录的创建过程:

use Filament\Tables\Actions\CreateAction;
use Illuminate\Database\Eloquent\Model;
 
CreateAction::make()
->process(function (array $data): Model {
return static::getModel()::create($data);
})

自定义保存通知

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

要自定义通知内容:

use Filament\Tables\Actions\CreateAction;
 
CreateAction::make()
->successNotificationMessage('User registered')

要完全禁用通知:

use Filament\Tables\Actions\CreateAction;
 
CreateAction::make()
->successNotificationMessage(null)

生命周期钩子

钩子可用于操作生命周期的各个结点中执行代码。

use Filament\Tables\Actions\CreateAction;
 
CreateAction::make()
->beforeFormFilled(function () {
// Runs before the form fields are populated with their default values.
})
->afterFormFilled(function () {
// Runs after the form fields are populated with their default values.
})
->beforeFormValidated(function () {
// Runs before the form fields are validated when the form is submitted.
})
->afterFormValidated(function () {
// Runs after the form fields are validated when the form is submitted.
})
->before(function () {
// Runs before the form fields are saved to the database.
})
->after(function () {
// Runs after the form fields are saved to the database.
})

编辑记录

使用中间属性编辑记录

对于 BelongsToManyMorphToMany 关联(relationship),你也可以编辑中间表属性。比如,如果你的资源 UserResource 有一个关联管理器 TeamsRelationManager,你想要在编辑表单中添加关联属性,你可以:

use Filament\Forms;
use Filament\Resources\Form;
use Filament\Tables;
 
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')->required(),
Forms\Components\TextInput::make('role')->required(),
// ...
]);
}

请确保所有的中间(pivot)属性都在关联反向关联的 withPivot() 方法中罗列出来。

表单填充前自定义数据

你可能需要在数据填充到表单之前修改数据。你可以使用 mutateRecordDataUsing() 方法修改 $data 数组,在填充到表单之前返回修改后的数据:

use Filament\Tables\Actions\EditAction;
 
EditAction::make()
->mutateRecordDataUsing(function (array $data): array {
$data['user_id'] = auth()->id();
 
return $data;
})

保存前自定义数据

有时,你可能希望在保存到数据库之前修改表单数据。可以使用 mutateFormDataUsing() 方法,该方法解释 $data 作为数组,返回修改后的版本:

use Filament\Tables\Actions\EditAction;
 
EditAction::make()
->mutateFormDataUsing(function (array $data): array {
$data['last_edited_by_id'] = auth()->id();
 
return $data;
})

自定义保存处理过程

你可以使用 process() 方法微调记录的更新过程:

use Filament\Tables\Actions\EditAction;
use Illuminate\Database\Eloquent\Model;
 
EditAction::make()
->process(function (Model $record, array $data): Model {
$record->update($data);
 
return $record;
})

自定义保存通知

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

要自定义通知内容:

use Filament\Tables\Actions\EditAction;
 
EditAction::make()
->successNotificationMessage('User updated')

如果要完全禁用通知:

use Filament\Tables\Actions\EditAction;
 
EditAction::make()
->successNotificationMessage(null)

生命周期钩子

钩子可以在操作生命周期的各个结点用于执行代码。

use Filament\Tables\Actions\EditAction;
 
EditAction::make()
->beforeFormFilled(function () {
// Runs before the form fields are populated from the database.
})
->afterFormFilled(function () {
// Runs after the form fields are populated from the database.
})
->beforeFormValidated(function () {
// Runs before the form fields are validated when the form is saved.
})
->afterFormValidated(function () {
// Runs after the form fields are validated when the form is saved.
})
->before(function () {
// Runs before the form fields are saved to the database.
})
->after(function () {
// Runs after the form fields are saved to the database.
})

附加和分离记录

Filament 可以为 BelongsToManyMorphToMany 关联(relationship)附加和分离记录。

在生成关联管理器时,你可以传入 --attach 标志,用来在表格中同时添加 AttachAction, DetachActionDetachBulkAction :

php artisan make:filament-relation-manager CategoryResource posts title --attach

此外,如果你已经生成了资源,你可以在 $table 数组中添加这些 Action:

use Filament\Resources\Table;
use Filament\Tables;
 
public static function table(Table $table): Table
{
return $table
->columns([
// ...
])
->headerActions([
// ...
Tables\Actions\AttachAction::make(),
])
->actions([
// ...
Tables\Actions\DetachAction::make(),
])
->bulkActions([
// ...
Tables\Actions\DetachBulkAction::make(),
]);
}

预加载关联模态框下拉列表选项

默认情况下,当你搜索记录附加时,选项会通过 AJAX 从数据库中加载。如果你希望表单加载时就直接预载这些选项,你可以使用 AttachActionpreloadRecordSelect() 方法:

use Filament\Tables\Actions\AttachAction;
 
AttachAction::make()->preloadRecordSelect()

使用中间属性附加记录

当你使用 附加(Attach) 按钮来附加记录时,你可能希望使用自定义表单来将中间属性添加到关联中:

use Filament\Forms;
use Filament\Tables\Actions\AttachAction;
 
AttachAction::make()
->form(fn (AttachAction $action): array => [
$action->getRecordSelect(),
Forms\Components\TextInput::make('role')->required(),
])

本例中,$action->getRecordSelect() 输出了下拉列表,用来选择记录附加。role 的文本输入被保存到中间表的 role 字段中。

请确保所有中间表的字段都在 关联 反向关联 的 withPivot 方法中罗列出来。

处理重复数据

默认情况下,你不能多次附加同一个记录。要使之可行,你需要先在中间表设置一个主键 id 字段。

同时,要确保 关联 反向关联 的 withPivot() 方法中使用了 id 属性。

最后,在关联管理器中添加 $allowsDuplicates 属性:

protected bool $allowsDuplicates = true;

关联和取消关联记录

Filament 可以为 HasManyHasManyThroughMorphMany 关系(relationship)关联和取消关联记录。

在生成关联管理器时,你可以传入 --associate 标志,将 AssociateAction, DissociateActionDissociateBulkAction 同时添加到表格中:

php artisan make:filament-relation-manager CategoryResource posts title --associate

此外,如果你已经生成了资源,你可以在 $table 数组中添加这些 Action:

use Filament\Resources\Table;
use Filament\Tables;
 
public static function table(Table $table): Table
{
return $table
->columns([
// ...
])
->headerActions([
// ...
Tables\Actions\AssociateAction::make(),
])
->actions([
// ...
Tables\Actions\DissociateAction::make(),
])
->bulkActions([
// ...
Tables\Actions\DissociateBulkAction::make(),
]);
}

预加载关联模态框下拉列表选项

默认情况下,由于你通过搜索记录关联,会通过 AJAX 从数据库中加载选项。如果你希望在表单加载时就预加载这些选项,可以使用 AssociateActionpreloadRecordSelect() 方法:

use Filament\Tables\Actions\AssociateAction;
 
AssociateAction::make()->preloadRecordSelect()

查看记录

在生成关联管理器时,可以输入 --view 标志,同时在表格中添加 ViewAction:

php artisan make:filament-relation-manager CategoryResource posts title --view

此外,如果你已经生成了关联管理器,可以将 ViewAction 添加到 $table->actions() 数组中:

use Filament\Resources\Table;
use Filament\Tables;
 
public static function table(Table $table): Table
{
return $table
->columns([
// ...
])
->actions([
Tables\Actions\ViewAction::make(),
// ...
]);
}

关联管理器分组

你可以将关联管理器分组到一个标签页中。在 RelationGroup 对象中带上标签包裹多个关联管理器可以实现分组:

use Filament\Resources\RelationManagers\RelationGroup;
 
public static function getRelations(): array
{
return [
// ...
RelationGroup::make('Contacts', [
RelationManagers\IndividualsRelationManager::class,
RelationManagers\OrganizationsRelationManager::class,
]),
// ...
];
}

条件性可见

默认情况下,如果相关模型策略的 viewAny() 方法返回的是 true,关联管理器将为可见。

你可以使用 canViewForRecord() 方法,决定关联管理器是否应该让特定的所有者记录可见:

use Illuminate\Database\Eloquent\Model;
 
public static function canViewForRecord(Model $ownerRecord): bool
{
return $ownerRecord->status === Status::Draft
}

将资源表单移动到标签页

在编辑或者查看页面类中,重写 hasCombinedRelationManagerTabsWithForm() 方法:

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

需要帮助? 加入论坛 或者打开 GitHub讨论

喜欢Filament?

Filament 中文文档由 laravel-filament.cn 翻译整理。站长用爱发电,希望为英文阅读不畅的朋友提供快速掌握Filament框架的途径。文档的翻译,社区的运营维护都需要时间精力上的付出。如果文档社区使你受益,如果你想支持站长...

打赏