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() 方法中列出

Scoping the options to attach

You may want to scope the options available to AttachAction:

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

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

Searching the options to attach across multiple columns

By default, the options available to AttachAction will be searched in the recordTitleAttribute() of the table. If you wish to search across multiple columns, you can use the recordSelectSearchColumns() method:

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()

Scoping the options to associate

You may want to scope the options available to 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()

However, if you’re inside a static method like form() or table(), $this isn’t accessible. So, you may use a callback to access the $livewire instance:

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();
                }),
            // ...
        ]);
}

All methods in Filament accept a callback which you can access $livewire->ownerRecord in.

关联管理器分组

你可以将所有关联管理器分组到一个标签页中。为此,你可以使用标签将多个管理器包装到一个 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
删除记录