Languages

Version

Theme

资源

管理关联

选择合适的工具

Filament 提供了多种在应用中管理管理的方法。选择哪个方式取决于你管理的关联类型和你希望的 UI 界面。

关联管理器 - 资源表单下方的交互式表格

NOTE

该方式兼容 HasManyHasManyThroughBelongsToManyMorphManyMorphToMany 关联。

关联管理器是允许管理员在不离开资源的编辑页或查看页的情况下,列出、创建、编辑、删除、关联、取消关联、附加、分离关联记录的互动式表格。

Select & checkbox list - 从现有记录中选择或者创建新记录

NOTE

该方式兼容 BelongsToMorphToBelongsToMany 关联。

使用 Select,用户可以从已有记录清单中进行选择。你页可以添加一个允许用户在模态框中创建新纪录的按钮,而无需离开页面。

当在 Select 中使用 BelongsToMany 关联时,你可以选择多个选项。记录会在你提交表单时,自动添加到中间表中。你也可以使用 Checkbox List替换多选下拉框。这两个组件的工作原理相同。

Repeater - 在表单中 CRUD 多个关联纪律

NOTE

该方式兼容 HasManyMorphMany 关联。

Repeater是标准的表单组件,可以无限渲染一组可重复的字段。它们可以钩入到关联中,因此记录会自动从相关表中读取、创建、更新和删除。它们位于主表单 Schema 中,可以在资源页面中使用,也可以在嵌套到操作模态框中。

就用户体验角度而言,该方案只适合于关联模型中只有少数几个字段。否则,表单可能会变得非常长。

布局表单组件 - 保存表单字段到单个关联中

NOTE

该方式兼容 BelongsToHasOneMorphOne 关联。

所有布局表单组件(GridSectionFieldset等)都由一个 relationship() 方法。当你使用这一方式,所有布局组件类的字段都将保存到关联模型而非所有者(owner)模型中:

use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Fieldset;

Fieldset::make('Metadata')
    ->relationship('metadata')
    ->schema([
        TextInput::make('title'),
        Textarea::make('description'),
        FileUpload::make('image'),
    ])

本例中,titledescriptionimage 自动从 metadata 关联中自动加载,并且在表单提交时再次保存。如果该 metadata 记录不存在,它将自动创建。

该特性在表单文档由更详尽深入的解释。请访问了解更多如何使用的信息。

创建关联管理器

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

php artisan make:filament-relation-manager CategoryResource posts title
  • CategoryResource 是所有者(父级)模型的资源类的名称。
  • posts 是你想要管理的关联的名称。
  • title 是你用以识别文章(post)的属性名。

这将创建一个 CategoryResource/RelationManagers/PostsRelationManager.php 文件。它包含一个你可以定义资源管理器的表单表格的类:

use Filament\Forms;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            Forms\Components\TextInput::make('title')->required(),
            // ...
        ]);
}

public function table(Table $table): Table
{
    return $table
        ->columns([
            Tables\Columns\TextColumn::make('title'),
            // ...
        ]);
}

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

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

当关联管理器定义了表格和表单后,请访问资源的编辑页查看页,以查看其实际操作。

只读模式

关联管理器通常显示在资源的“编辑”或“查看”页面上。在“查看”页面上,Filament 将自动隐藏修改关联的所有操作,如创建、编辑和删除。我们称之为“只读模式”,默认情况下,它保留了“查看”页面的只读行为。但是,你可以通过重写关联管理器类上的 isReadOnly() 方法使之始终返回 false 来禁用此行为:

public function isReadOnly(): bool
{
    return false;
}

此外,如果你不喜欢该功能,你可以在面板配置中一次性禁用所有关联管理器的只读模式:

use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->readOnlyRelationManagersOnResourceViewPagesByDefault(false);
}

非常规的反转关联名

对于未遵循 Laravel 命名规范的反转关联,你可以在表格上使用 inverseRelationship() 方法:

use Filament\Tables;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->columns([
            Tables\Columns\TextColumn::make('title'),
            // ...
        ])
        ->inverseRelationship('section'); // Since the inverse related model is `Category`, this is normally `category`, not `section`.
}

处理软删除

默认情况下,你将无法在关联管理器中与已删除的记录进行交互。如果你想在关联管理器中添加恢复、强制删除和过滤垃圾记录的功能,请在生成关联管理器时使用 --soft deletes 标志:

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

你可以在此处查阅更多软删除的信息。

列出关联记录

关联记录会在表格中列出。整个关联管理器都是基于此表格,包含创建编辑附加/分离关联/取消关联和删除记录的操作。

你可以使用表格构造器的所有特性来自定义关联管理器。

使用中间表属性罗列

对于 BelongsToManyMorphToMany 关联,你也可以添加中间表属性。比如你的 UserResource 资源有一个 TeamsRelationManager 关联,你想要添加 role 中间表属性到该表格,你可以使用:

use Filament\Tables;

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

请确保所有的中间表属性都在关联及反转关联的 withPivot() 方法中列出。

创建关联记录

使用中间表属性创建关联

对于 BelongsToManyMorphToMany 关联,你也可以添加中间表属性。比如你的 UserResource 资源有一个 TeamsRelationManager 关联,你想要添加 role 中间表属性到新建表单中,你可以使用:

use Filament\Forms;
use Filament\Schemas\Schema;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            Forms\Components\TextInput::make('name')->required(),
            Forms\Components\TextInput::make('role')->required(),
            // ...
        ]);
}

请确保所有的中间表属性都在关联及反转关联的 withPivot() 方法中列出

自定义 CreateAction

要了解如何自定义 CreateAction,包括操纵单数据、修改通知以及添加生命周期钩子,请查阅 Action 文档

编辑关联记录

使用中间表属性编辑

对于 BelongsToManyMorphToMany 关联,你也可以添加中间表属性。比如你的 UserResource 资源有一个 TeamsRelationManager 关联,你想要添加 role 中间表属性到编辑表单中,你可以使用:

use Filament\Forms;
use Filament\Schemas\Schema;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            Forms\Components\TextInput::make('name')->required(),
            Forms\Components\TextInput::make('role')->required(),
            // ...
        ]);
}

请确保所有的中间表属性都在关联及反转关联的 withPivot() 方法中列出。

自定义 EditAction

要了解如何自定义 EditAction,包括操纵单数据、修改通知以及添加生命周期钩子,请查阅 Action 文档

附加和分离记录

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

生成关联管理器时,你可以传入 --attach 标志,以同时添加 AttachActionDetachActionDetachBulkAction 操作到表格中:

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

另外,如果你已经生成了资源,你可以只添加这些操作到 $table 中:

use Filament\Actions\AttachAction;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DetachAction;
use Filament\Actions\DetachBulkAction;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->columns([
            // ...
        ])
        ->headerActions([
            // ...
            AttachAction::make(),
        ])
        ->recordActions([
            // ...
            DetachAction::make(),
        ])
        ->toolbarActions([
            BulkActionGroup::make([
                // ...
                DetachBulkAction::make(),
            ]),
        ]);
}

预加载附加模态框选择选项

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

use Filament\Actions\AttachAction;

AttachAction::make()
    ->preloadRecordSelect()

附加中间属性

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

use Filament\Actions\AttachAction;
use Filament\Forms;

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

此例中,$action->getRecordSelect() 返回 Select 字段以选择要附加的记录。然后,role 文本输入框将保存到中间表的 role 列中。

请确保所有的中间表属性都在关联及反转关联的 withPivot() 方法中列出

限定附加的选项查询范围:

你可能想要对 AttachAction 的选项限定查询范围:

use Filament\Actions\AttachAction;
use Illuminate\Database\Eloquent\Builder;

AttachAction::make()
    ->recordSelectOptionsQuery(fn (Builder $query) => $query->whereBelongsTo(auth()->user()))

跨越多列搜索要附加的选项

默认情况下,要附加的 AttachAction 的选项会在表格的 recordTitleAttribute() 中进行搜索。如果你希望搜索多个字段,可以使用 recordSelectSearchColumns() 方法:

use Filament\Actions\AttachAction;

AttachAction::make()
    ->recordSelectSearchColumns(['title', 'description'])

附加多个记录

AttachAction 组件的 multiple() 方法允许你选择多个值:

use Filament\Actions\AttachAction;

AttachAction::make()
    ->multiple()

自定义附加模态框中的 Select 字段

你可以通过将函数传递给 recordSelect() 方法来自定义附加过程中使用的 Select 字段对象:

use Filament\Actions\AttachAction;
use Filament\Forms\Components\Select;

AttachAction::make()
    ->recordSelect(
        fn (Select $select) => $select->placeholder('Select a post'),
    )

处理重复项

默认情况下,你不允许多次附加同一条记录。这是因为你必须在中间表上设置一个主键 id 列才能使此功能生效。

请确保 id 属性在关联 反向关联的 withPivot() 方法中列出。

最后,请将 allowDuplicates() 方法添加到表中:

public function table(Table $table): Table
{
    return $table
        ->allowDuplicates();
}

提升批量分离操作的性能

默认情况下,DetachBulkAction 会将所有 Eloquent 记录加载到内存中,然后循环遍历并逐条分离。

如果你要分离大量记录,建议你使用 chunkSelectedRecords() 方法一次性提取少量记录。这将减少应用的内存占用:

use Filament\Actions\DetachBulkAction;

DetachBulkAction::make()
    ->chunkSelectedRecords(250)

Filament 在分离 Eloquent 记录之前会将其加载到内存中,原因有二:

  • 允许在分离之前使用模型策略对集合中的单个记录进行授权(比如,使用 authorizeIndividualRecords('delete'))。
  • 确保在分离记录时运行模型事件,例如模型观察器中的 deletingdeleted 事件。

如果你不需要单个记录策略授权和模型事件,你可以使用 fetchSelectedRecords(false) 方法,该方法不会在分离记录之前将记录加载到内存中,而是在单个查询中分离它们:

use Filament\Actions\DetachBulkAction;

DetachBulkAction::make()
    ->fetchSelectedRecords(false)

关联和解除关联记录

Filament 能够关联和解除关联 HasManyMorphMany 关系的记录。

生成关联管理器时,你可以传递 --associate 标志,以便将 AssociateActionDissociateActionDissociateBulkAction 添加到表中:

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

或者,如果你已经生成了资源,则只需将操作(Action)添加到 $table 数组中:

use Filament\Actions\AssociateAction;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DissociateAction;
use Filament\Actions\DissociateBulkAction;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->columns([
            // ...
        ])
        ->headerActions([
            // ...
            AssociateAction::make(),
        ])
        ->recordActions([
            // ...
            DissociateAction::make(),
        ])
        ->toolbarActions([
            BulkActionGroup::make([
                // ...
                DissociateBulkAction::make(),
            ]),
        ]);
}

预加载关联模态框 Select 选项

默认情况下,当你索要关联的记录时,选项将通过 AJAX 从数据库加载。如果你希望在表单首次加载时预加载这些选项,可以使用 AssociateActionpreloadRecordSelect() 方法:

use Filament\Actions\AssociateAction;

AssociateAction::make()
    ->preloadRecordSelect()

限定关联选项查询范围:

你可能想要对 AssociateAction 的选项限定查询范围:

use Filament\Actions\AssociateAction;
use Illuminate\Database\Eloquent\Builder;

AssociateAction::make()
    ->recordSelectOptionsQuery(fn (Builder $query) => $query->whereBelongsTo(auth()->user()))

搜索选项跨列关联

默认情况下,AssociateAction 可用的选项将在表格的 recordTitleAttribute() 中搜索。如果你希望跨多列搜索,可以使用 recordSelectSearchColumns() 方法:

use Filament\Actions\AssociateAction;

AssociateAction::make()
    ->recordSelectSearchColumns(['title', 'description'])

关联多个记录

AssociateAction 组件上的 multiple() 方法允许你选择多个值:

use Filament\Actions\AssociateAction;

AssociateAction::make()
    ->multiple()

自定义关联模态框中的 Select 字段

你可以通过将函数传递给 recordSelect() 方法来自定义关联过程中使用的 Select 字段对象:

use Filament\Actions\AssociateAction;
use Filament\Forms\Components\Select;

AssociateAction::make()
    ->recordSelect(
        fn (Select $select) => $select->placeholder('Select a post'),
    )

、、、

提升批量解除关联操作的性能

默认情况下,DissociateBulkAction 会将所有 Eloquent 记录加载到内存中,然后循环遍历并逐一解除关联。

如果你要解除大量记录,建议使用 chunkSelectedRecords() 方法一次性获取较少数量的记录。这将减少应用的内存占用:

use Filament\Actions\DissociateBulkAction;

DissociateBulkAction::make()
    ->chunkSelectedRecords(250)

Filament 在解除关联之前会将 Eloquent 记录加载到内存中,原因有二:

  • 允许在解除关联之前使用模型策略对集合中的单个记录进行授权(例如,使用 authorizeIndividualRecords('update'))。
  • 确保在解除关联记录时运行模型事件,例如模型观察器中的 updatingupdated 事件。

如果你不需要单个记录策略授权和模型事件,可以使用 fetchSelectedRecords(false) 方法,该方法不会在解除关联之前将记录加载到内存中,而是在单个查询中解除关联:

use Filament\Actions\DissociateBulkAction;

DissociateBulkAction::make()
    ->fetchSelectedRecords(false)

查看关联记录

生成关联管理器时,你可以传递 --view 标志来向表格中添加 ViewAction

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

或者,如果你已经生成了关联管理器,则只需将 ViewAction 添加到 $table->recordActions() 数组中:

use Filament\Actions\ViewAction;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->columns([
            // ...
        ])
        ->recordActions([
            ViewAction::make(),
            // ...
        ]);
}

删除关联记录

默认情况下,你将无法在关联管理器中与已删除的记录进行交互。如果你想在关联管理器中添加恢复、强制删除和过滤已删除记录的功能,请在生成关联管理器时使用 --soft-deletes 标志:

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

或者,你也可以添加软删除功能到现有的关联管理器中:

use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\ForceDeleteAction;
use Filament\Actions\ForceDeleteBulkAction;
use Filament\Actions\RestoreAction;
use Filament\Actions\RestoreBulkAction;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;

public function table(Table $table): Table
{
    return $table
        ->modifyQueryUsing(fn (Builder $query) => $query->withoutGlobalScopes([
            SoftDeletingScope::class,
        ]))
        ->columns([
            // ...
        ])
        ->filters([
            TrashedFilter::make(),
            // ...
        ])
        ->recordActions([
            DeleteAction::make(),
            ForceDeleteAction::make(),
            RestoreAction::make(),
            // ...
        ])
        ->toolbarActions([
            BulkActionGroup::make([
                DeleteBulkAction::make(),
                ForceDeleteBulkAction::make(),
                RestoreBulkAction::make(),
                // ...
            ]),
        ]);
}

自定义 DeleteAction

要了解如何自定义 DeleteAction,包括修改通知和添加生命周期钩子,请查看 Action 文档

导入关联记录

可以将 ImportAction 添加到关联管理器的标题中,以导入记录。在这种情况下,你可能需要告知导入器这些新记录属于哪个所有者。你可以使用 导入选项 传递所有者记录的 ID:

ImportAction::make()
    ->importer(ProductImporter::class)
    ->options(['categoryId' => $this->getOwnerRecord()->getKey()])

现在,在导入器类中,你可以将所有者与导入的记录建立一对多关联:

public function resolveRecord(): ?Product
{
    $product = Product::firstOrNew([
        'sku' => $this->data['sku'],
    ]);
    
    $product->category()->associate($this->options['categoryId']);
    
    return $product;
}

或者,你可以使用导入器的 afterSave() 钩子将记录附加到多对多关联中:

protected function afterSave(): void
{
    $this->record->categories()->syncWithoutDetaching([$this->options['categoryId']]);
}

访问关联的所有者记录

关联管理器是 Livewire 组件。首次加载时,所有者记录(作为父级的 Eloquent 记录 - 主资源模型)会保存到一个属性中。你可以使用以下方式读取此属性:

$this->getOwnerRecord()

不过,如果你在 static 静态方法(比如,form() 或者 table())中,$this 无法访问。因此,你可能会使用回调来访问 $livewire 实例:

use Filament\Forms;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Schemas\Schema;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            Forms\Components\Select::make('store_id')
                ->options(function (RelationManager $livewire): array {
                    return $livewire->getOwnerRecord()->stores()
                        ->pluck('name', 'id')
                        ->toArray();
                }),
            // ...
        ]);
}

Filament 中的所有方法都接受回调,在其中你可以访问 $livewire->ownerRecord

关联管理器分组

你可以将所有关联管理器分组到一个标签页中。为此,你可以使用标签将多个管理器包装到一个 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, string $pageClass): bool
{
    return $ownerRecord->status === Status::Draft;
}

将关联管理器选项卡与表单合并

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

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

自定义内容标签页

在编辑或查看页面类中,重写 getContentTabComponent() 方法,并使用任何 Tab 自定义方法:

use Filament\Schemas\Components\Tabs\Tab;

public function getContentTabComponent(): Tab
{
    return Tab::make('Settings')
        ->icon('heroicon-m-cog');
}

设置表单标签页位置

默认情况下,表单选项卡会在关联选项卡之前渲染。如果要在关联选项卡之后渲染,你可以重写编辑或查看页面类中的 getContentTabPosition() 方法:

use Filament\Resources\Pages\Enums\ContentTabPosition;

public function getContentTabPosition(): ?ContentTabPosition
{
    return ContentTabPosition::After;
}

自定义关联管理器标签页

要自定义关联管理器的标签页,请重写 getTabComponent() 方法,并使用 [Tab(../schemas/tabs)] 的自定义方法:

use Filament\Schemas\Components\Tabs\Tab;
use Illuminate\Database\Eloquent\Model;

public static function getTabComponent(Model $ownerRecord, string $pageClass): Tab
{
    return Tab::make('Blog posts')
        ->badge($ownerRecord->posts()->count())
        ->badgeColor('info')
        ->badgeTooltip('The number of posts in this category')
        ->icon('heroicon-m-document-text');
}

如果你正在使用关联分组,你可以使用 tab() 方法:

use Filament\Resources\RelationManagers\RelationGroup;
use Filament\Schemas\Components\Tabs\Tab;
use Illuminate\Database\Eloquent\Model;

RelationGroup::make('Contacts', [
    // ...
])
    ->tab(fn (Model $ownerRecord): Tab => Tab::make('Blog posts')
        ->badge($ownerRecord->posts()->count())
        ->badgeColor('info')
        ->badgeTooltip('The number of posts in this category')
        ->icon('heroicon-m-document-text'));

与关联管理器共享资源的表单和表格

你可能希望资源的表单和表格与关联管理器的完全相同,并希望重用之前编写的代码。这很简单,只需从关联管理器中调用资源的 form()table() 方法即可:

use App\Filament\Resources\Blog\Posts\PostResource;
use Filament\Schemas\Schema;
use Filament\Tables\Table;

public function form(Schema $schema): Schema
{
    return PostResource::form($schema);
}

public function table(Table $table): Table
{
    return PostResource::table($table);
}

隐藏关联管理器上的共享表单组件

如果你要与关联管理器共享资源中的表单组件,你可能需要在关联管理器上隐藏它。如果你想在关联管理器中隐藏所有者记录的 Select 字段,此功能尤其有用,因为 Filament 无论如何都会为你处理此问题。为此,你可以使用 hiddenOn() 方法,并传递关联管理器的名称:

use App\Filament\Resources\Blog\Posts\PostResource\RelationManagers\CommentsRelationManager;
use Filament\Forms\Components\Select;

Select::make('post_id')
    ->relationship('post', 'title')
    ->hiddenOn(CommentsRelationManager::class)

隐藏关联管理器的共享表格列

如果你与关联管理器共享资源中的某个表格列,你可能需要在关联管理器中隐藏该列。如果你想在关联管理器中隐藏所有者记录的那一列,则此功能尤其有用,因为当所有者记录已在关联管理器上方列出时,显示该列并不合适。为此,你可以使用 hiddenOn() 方法,并传递关联管理器的名称:

use App\Filament\Resources\Blog\Posts\PostResource\RelationManagers\CommentsRelationManager;
use Filament\Tables\Columns\TextColumn;

TextColumn::make('post.title')
    ->hiddenOn(CommentsRelationManager::class)

隐藏关联管理器的共享表格过滤器

如果你与关联管理器共享资源中的某个表格过滤器,你可能需要在关联管理器上隐藏它。如果你想在关联管理器中隐藏所有者记录的过滤器,这尤其有用,因为表格已被所有者记录过滤时,显示该过滤器便不合适。为此,你可以使用 hiddenOn() 方法,并传递关联管理器的名称:

use App\Filament\Resources\Blog\Posts\PostResource\RelationManagers\CommentsRelationManager;
use Filament\Tables\Filters\SelectFilter;

SelectFilter::make('post')
    ->relationship('post', 'title')
    ->hiddenOn(CommentsRelationManager::class)

重写关联管理器上的共享配置

你在资源内部进行的任何配置都可以在关联管理器上被重写。例如,如果你想禁用关联管理器继承表上的分页功能,但不禁用资源本身的分页功能:

use App\Filament\Resources\Blog\Posts\PostResource;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return PostResource::table($table)
        ->paginated(false);
}

如果你想在关联管理器中为 创建附加关联 记录添加 Header 操作,那么在关联管理器上提供额外的配置可能也很有用:

use App\Filament\Resources\Blog\Posts\PostResource;
use Filament\Actions\AttachAction;
use Filament\Actions\CreateAction;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return PostResource::table($table)
        ->headerActions([
            CreateAction::make(),
            AttachAction::make(),
        ]);
}

自定义关联管理器的 Eloquent 查询

你可以应用自己的查询约束或模型查询范围,它们会影响整个关联管理器。为此,你可以将一个函数传递给表格的 modifyQueryUsing() 方法,在其中你可以自定义查询:

use Filament\Tables;
use Illuminate\Database\Eloquent\Builder;

public function table(Table $table): Table
{
    return $table
        ->modifyQueryUsing(fn (Builder $query) => $query->where('is_active', true))
        ->columns([
            // ...
        ]);
}

自定义关联管理器标题

要设置关联管理器的标题,你可以使用关联管理器类上的 $title 属性:

protected static ?string $title = 'Posts';

要动态设置关联管理器的标题,你可以重写关联管理器类的 getTitle() 方法:

use Illuminate\Database\Eloquent\Model;

public static function getTitle(Model $ownerRecord, string $pageClass): string
{
    return __('relation-managers.posts.title');
}

标题将反映在表格标题中,以及关联管理器选项卡(如果有多个)中。如果你想单独自定义表格标题,仍然可以使用 $table->heading() 方法:

use Filament\Tables;

public function table(Table $table): Table
{
    return $table
        ->heading('Posts')
        ->columns([
            // ...
        ]);
}

自定义管理管理器的记录标题

关联管理器使用“记录标题属性”的概念来确定应该使用相关模型的哪个属性来标识它。创建关联管理器时,此属性将作为 make:filament-relation-manager 命令的第三个参数传递:

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

上例中,Posttitle 属性用于识别关联管理器的贴文(Post)。

这主要由 Action 类使用。例如,当你附加关联一条记录时,其标题将列在选择字段中。当你编辑查看删除一条记录时,标题将用于模态框的标题中。

在某些情况下,你可能需要将多个属性连接在一起形成一个标题。你可以将 recordTitleAttribute() 配置方法替换为 recordTitle(),并传递一个将模型转换为标题的函数:

use App\Models\Post;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->recordTitle(fn (Post $record): string => "{$record->title} ({$record->id})")
        ->columns([
            // ...
        ]);
}

如果你正在使用 recordTitle(),并且有一个 关联操作附加操作,你还需要为这些操作指定搜索列:

use Filament\Actions\AssociateAction;
use Filament\Actions\AttachAction;

AssociateAction::make()
    ->recordSelectSearchColumns(['title', 'id']);

AttachAction::make()
    ->recordSelectSearchColumns(['title', 'id'])

关联页面

如果你希望将管理关联的功能与编辑或查看所有者记录的功能分离,那么使用 ManageRelatedRecords 页面是使用关联管理器的另一种选择。

如果你正在使用资源子导航,此功能非常适合,因为你可以轻松地在“查看”或“编辑”页面和关联页面之间切换。

要创建关联页面,你应该使用 make:filament-page 命令:

php artisan make:filament-page ManageCustomerAddresses --resource=CustomerResource --type=ManageRelatedRecords

运行此命令时,系统会询问你一系列问题以自定义页面,比如,关联的名称及其标题属性。

你必须在资源的 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'),
        'addresses' => Pages\ManageCustomerAddresses::route('/{record}/addresses'),
    ];
}

NOTE

当使用关联页面时,你不需要使用 make:filament-relation-manager 生成关联管理器,你无需在资源的 getRelations() 方法中注册它。

现在,你可以按照与关联管理器完全相同的方式使用相同的 table()form() 来自定义页面。

添加关联页面到资源子导航

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

use App\Filament\Resources\Customers\Pages;
use Filament\Resources\Pages\Page;

public static function getRecordSubNavigation(Page $page): array
{
    return $page->generateNavigationItems([
        // ...
        Pages\ManageCustomerAddresses::class,
    ]);
}

传递属性到关联管理器

当在资源中注册资源管理器时,你可以使用 make() 方法传入一个 Livewire 属性数组到其中:

use App\Filament\Resources\Blog\Posts\PostResource\RelationManagers\CommentsRelationManager;

public static function getRelations(): array
{
    return [
        CommentsRelationManager::make([
            'status' => 'approved',
        ]),
    ];
}

该属性数组映射到资源管理器类的 public Livewire 属性

use Filament\Resources\RelationManagers\RelationManager;

class CommentsRelationManager extends RelationManager
{
    public string $status;

    // ...
}

现在,你可以在资源管理器类中使用 $this->status 访问 $status

禁用懒加载

默认情况下,关联管理器是延迟加载的。也就是说,只有当其在页面中可见时才会加载。

要禁用此行为,可用重写关联管理器类的 $isLazy 属性:

protected static bool $isLazy = false;
Edit on GitHub

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

Previous
删除记录