概述
简介
Resource 是用于为 Eloquent 模型构建 CRUD 界面的静态类。它们描述管理员应如何通过表格与表单与应用中的数据交互。


创建资源
要为 App\Models\Customer 模型创建资源:
php artisan make:filament-resource Customer这会在 app/Filament/Resources 目录中创建若干文件:
.
+-- Customers
| +-- CustomerResource.php
| +-- Pages
| | +-- CreateCustomer.php
| | +-- EditCustomer.php
| | +-- ListCustomers.php
| +-- Schemas
| | +-- CustomerForm.php
| +-- Tables
| | +-- CustomersTable.php新的资源类位于 CustomerResource.php。
Pages 目录中的类用于自定义与资源交互的应用页面。它们都是完整页面的 Livewire 组件,可按需任意自定义。
TIP
已经创建了资源,但导航菜单中没有出现?若有 模型策略,请确保 viewAny() 方法返回 true。
简单(模态)资源
有时模型足够简单,你只想在一个页面上管理记录,并用模态创建、编辑和删除。要生成带模态的简单资源:
php artisan make:filament-resource Customer --simple资源会有一个「Manage」页面,即带模态的列表页。
此外,简单资源没有 getRelations() 方法,因为 关联管理器 只显示在编辑页与查看页,而简单资源没有这些页面。其余部分相同。




自动生成表单与表格
php artisan make:filament-resource Customer --generate处理软删除
默认情况下,你无法在应用中操作已删除的记录。若希望在资源中恢复、强制删除并筛选已删除记录,生成资源时请使用 --soft-deletes 标志:
php artisan make:filament-resource Customer --soft-deletes可在 此处 了解更多软删除相关内容。
生成查看页
默认只为资源生成列表、创建与编辑页。若还需要 查看页,请使用 --view 标志:
php artisan make:filament-resource Customer --view指定自定义模型命名空间
默认情况下,Filament 假定模型位于 App\Models 目录。可用 --model-namespace 标志传入不同的模型命名空间:
php artisan make:filament-resource Customer --model-namespace=Custom\\Path\\Models在此例中,模型应位于 Custom\Path\Models\Customer。请注意命令中需要的双反斜杠 \\。
这样在 生成资源 时,Filament 就能定位模型并读取数据库结构。
同时生成模型、迁移与工厂
若希望在搭建资源时节省时间,Filament 也可同时用任意组合的 --model、--migration 与 --factory 标志,为新资源生成模型、迁移与工厂:
php artisan make:filament-resource Customer --model --migration --factory记录标题
可为资源设置 $recordTitleAttribute,即模型上可用于与其他记录区分的列名。
例如,可以是博客文章的 title,或客户的 name:
protected static ?string $recordTitleAttribute = 'name';这是 全局搜索 等功能正常工作所必需的。
TIP
若单列不足以标识记录,可指定 Eloquent 访问器 的名称。
资源表单
默认情况下,Filament 会创建 form schema 文件,并在 form() 方法中引用。这是为了保持资源类整洁有序,否则它会变得很大:
use App\Filament\Resources\Customers\Schemas\CustomerForm;
use Filament\Schemas\Schema;
public static function form(Schema $schema): Schema
{
return CustomerForm::configure($schema);
}在 CustomerForm 类中,可定义表单的字段与布局:
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')->required(),
TextInput::make('email')->email()->required(),
// ...
]);
}请参阅 Forms 文档中的 指南,了解如何用 Filament 构建表单。
TIP
若更希望直接在资源类中定义表单,也可以这样做,并完全删除 form schema 类:
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
public static function form(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')->required(),
TextInput::make('email')->email()->required(),
// ...
]);
}根据当前操作隐藏组件
表单组件的 hiddenOn() 方法允许你根据当前页面或操作动态隐藏字段。
在此例中,我们在 edit 页面隐藏 password 字段:
use Filament\Forms\Components\TextInput;
use Filament\Support\Enums\Operation;
TextInput::make('password')
->password()
->required()
->hiddenOn(Operation::Edit),或者,可用 visibleOn() 快捷方法,仅在某一页面或操作上显示字段:
use Filament\Forms\Components\TextInput;
use Filament\Support\Enums\Operation;
TextInput::make('password')
->password()
->required()
->visibleOn(Operation::Create),资源表格
资源类包含 table() 方法,用于构建 列表页 上的表格。
默认情况下,Filament 会创建 table 文件,并在 table() 方法中引用。这是为了保持资源类整洁有序,否则它会变得很大:
use App\Filament\Resources\Customers\Tables\CustomersTable;
use Filament\Tables\Table;
public static function table(Table $table): Table
{
return CustomersTable::configure($table);
}在 CustomersTable 类中,可定义表格的列、筛选器与操作:
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name'),
TextColumn::make('email'),
// ...
])
->filters([
Filter::make('verified')
->query(fn (Builder $query): Builder => $query->whereNotNull('email_verified_at')),
// ...
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}请参阅 表格 文档,了解如何添加表格列、筛选器、操作等。
TIP
若更希望直接在资源类中定义表格,也可以这样做,并完全删除 table 类:
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name'),
TextColumn::make('email'),
// ...
])
->filters([
Filter::make('verified')
->query(fn (Builder $query): Builder => $query->whereNotNull('email_verified_at')),
// ...
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}自定义模型标签
每个资源都有一个从模型名自动生成的「模型标签」。例如,App\Models\Customer 模型的标签为 customer。
该标签用于 UI 的多处,可用 $modelLabel 属性自定义:
protected static ?string $modelLabel = 'cliente';或者,可用 getModelLabel() 定义动态标签:
public static function getModelLabel(): string
{
return __('filament/resources/customer.label');
}自定义复数模型标签
资源还有一个从模型标签自动生成的「复数模型标签」。例如,customer 标签会复数化为 customers。
可用 $pluralModelLabel 属性自定义复数标签:
protected static ?string $pluralModelLabel = 'clientes';或者,可在 getPluralModelLabel() 方法中设置动态复数标签:
public static function getPluralModelLabel(): string
{
return __('filament/resources/customer.plural_label');
}自动大写模型标签
默认情况下,Filament 会在部分 UI(例如页面标题、导航菜单与面包屑)中自动将模型标签的每个单词首字母大写。
若要为某个资源禁用此行为,可在资源中设置 $hasTitleCaseModelLabel:
protected static bool $hasTitleCaseModelLabel = false;资源导航项
Filament 会使用 复数标签 自动为资源生成导航菜单项。
若想自定义导航项标签,可使用 $navigationLabel 属性:
protected static ?string $navigationLabel = 'Mis Clientes';或者,可在 getNavigationLabel() 方法中设置动态导航标签:
public static function getNavigationLabel(): string
{
return __('filament/resources/customer.navigation_label');
}设置资源导航图标
$navigationIcon 属性支持任意 Blade 组件名称。默认已安装 Heroicons。不过,你也可以创建自定义图标组件,或安装其他图标库。
use BackedEnum;
protected static string | BackedEnum | null $navigationIcon = 'heroicon-o-user-group';或者,可在 getNavigationIcon() 方法中设置动态导航图标:
use BackedEnum;
use Illuminate\Contracts\Support\Htmlable;
public static function getNavigationIcon(): string | BackedEnum | Htmlable | null
{
return 'heroicon-o-user-group';
}排序资源导航项
$navigationSort 属性允许你指定导航项的列出顺序:
protected static ?int $navigationSort = 2;或者,可在 getNavigationSort() 方法中设置动态导航项顺序:
public static function getNavigationSort(): ?int
{
return 2;
}分组资源导航项
可通过指定 $navigationGroup 属性对导航项分组:
use UnitEnum;
protected static string | UnitEnum | null $navigationGroup = 'Shop';或者,可用 getNavigationGroup() 方法设置动态分组标签:
public static function getNavigationGroup(): ?string
{
return __('filament/navigation.groups.shop');
}将资源导航项归入其他项之下
可通过设置 $navigationParentItem 属性,将导航项作为其他项的子项。可通过父项的页面或资源类,或通过其标签来引用父项:
use App\Filament\Resources\Products\ProductsResource;
use UnitEnum;
protected static ?string $navigationParentItem = ProductsResource::class;
protected static string | UnitEnum | null $navigationGroup = 'Shop';或者,可通过标签引用父项:
use UnitEnum;
protected static ?string $navigationParentItem = 'Products';
protected static string | UnitEnum | null $navigationGroup = 'Shop';也可使用 getNavigationParentItem() 方法动态确定父项:
use App\Filament\Resources\Products\ProductsResource;
public static function getNavigationParentItem(): ?string
{
return ProductsResource::class;
}或者,可返回父项的标签:
public static function getNavigationParentItem(): ?string
{
return __('filament/navigation.groups.shop.items.products');
}父项与子项必须属于同一导航分组。若父项有导航分组,子项也必须定义该分组,否则无法正确识别父项。无论通过类还是标签引用父项,都适用此规则。
TIP
若需要这样的第三级导航,应考虑改用 集群(clusters)。集群是资源与 自定义页面 的逻辑分组,可共享独立的导航。
生成资源页面的 URL
Filament 在资源类上提供静态方法 getUrl(),用于生成资源及其内部特定页面的 URL。传统上你需要手动拼接 URL 或使用 Laravel 的 route() 辅助函数,但这些方式依赖于资源的 slug 或路由命名约定。
不带参数的 getUrl() 会生成指向资源 列表页 的 URL:
use App\Filament\Resources\Customers\CustomerResource;
CustomerResource::getUrl(); // /admin/customers也可生成指向资源内特定页面的 URL。每个页面的名称是资源 getPages() 数组中的键。例如,生成指向 创建页 的 URL:
use App\Filament\Resources\Customers\CustomerResource;
CustomerResource::getUrl('create'); // /admin/customers/creategetPages() 中的某些页面使用如 record 这样的 URL 参数。要生成这些页面的 URL 并传入记录,应使用第二个参数:
use App\Filament\Resources\Customers\CustomerResource;
CustomerResource::getUrl('edit', ['record' => $customer]); // /admin/customers/edit/1在此例中,$customer 可以是 Eloquent 模型对象,或 ID。
生成资源模态的 URL
若使用只有一个页面的 简单资源,这会特别有用。
要为资源表格中的操作生成 URL,应将 tableAction 与 tableActionRecord 作为 URL 参数传入:
use App\Filament\Resources\Customers\CustomerResource;
use Filament\Actions\EditAction;
CustomerResource::getUrl(parameters: [
'tableAction' => EditAction::getDefaultName(),
'tableActionRecord' => $customer,
]); // /admin/customers?tableAction=edit&tableActionRecord=1或者,若要为页面上的操作(例如页眉中的 CreateAction)生成 URL,可将其传入 action 参数:
use App\Filament\Resources\Customers\CustomerResource;
use Filament\Actions\CreateAction;
CustomerResource::getUrl(parameters: [
'action' => CreateAction::getDefaultName(),
]); // /admin/customers?action=create生成其他面板中资源的 URL
若应用中有多个面板,getUrl() 会在当前面板内生成 URL。也可通过向 panel 参数传入面板 ID,指明资源所属的面板:
use App\Filament\Resources\Customers\CustomerResource;
CustomerResource::getUrl(panel: 'marketing');自定义资源 Eloquent 查询
在 Filament 中,对资源模型的每次查询都会从 getEloquentQuery() 方法开始。
因此,很容易应用影响整个资源的自定义查询约束或 模型作用域:
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()->where('is_active', true);
}禁用全局作用域
默认情况下,Filament 会遵循模型上注册的所有全局作用域。不过,若希望访问例如已软删除的记录,这可能并不理想。
为此,可覆盖 Filament 使用的 getEloquentQuery() 方法:
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()->withoutGlobalScopes();
}或者,可移除特定的全局作用域:
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()->withoutGlobalScopes([ActiveScope::class]);
}关于移除全局作用域的更多信息,请参阅 Laravel 文档。
自定义资源 URL
默认情况下,Filament 会根据资源名称生成 URL。可通过在资源上设置 $slug 属性自定义:
protected static ?string $slug = 'pending-orders';资源子导航
子导航允许用户在资源内的不同页面之间导航。通常,子导航中的所有页面都与资源中的同一条记录相关。例如,在 Customer 资源中,你可能有如下子导航页面:
- 查看客户:[`ViewRecord` 页面](/5.x/resources/viewing-records),只读展示客户详情。
- 编辑客户:[`EditRecord` 页面](/5.x/resources/editing-records),允许用户编辑客户详情。
- 编辑客户联系方式:[`EditRecord` 页面](/5.x/resources/editing-records),允许用户编辑客户联系方式。可 [了解如何创建多个编辑页](/5.x/resources/editing-records#creating-another-edit-page)。
- 管理地址:[`ManageRelatedRecords` 页面](/5.x/resources/managing-relationships#relation-pages),允许用户管理客户地址。
- 管理付款:[`ManageRelatedRecords` 页面](/5.x/resources/managing-relationships#relation-pages),允许用户管理客户付款。
要为资源中每个「单条记录」页面添加子导航,可在资源类上添加 getRecordSubNavigation() 方法:
use Filament\Resources\Pages\Page;
public static function getRecordSubNavigation(Page $page): array
{
return $page->generateNavigationItems([
ViewCustomer::class,
EditCustomer::class,
EditCustomerContact::class,
ManageCustomerAddresses::class,
ManageCustomerPayments::class,
]);
}子导航中的每一项都可用 与普通页面相同的导航方法 自定义。


TIP
若希望添加子导航以便在整个资源与 自定义页面 之间 切换,你可能需要的是 集群(clusters),用于将它们分组。getRecordSubNavigation() 用于构建资源 内部、与某条特定记录相关的页面之间的导航。
设置资源的子导航位置
子导航默认渲染在页面起始位置。可通过在资源上设置 $subNavigationPosition,更改该资源所有页面的位置。取值可为 SubNavigationPosition::Start、SubNavigationPosition::End,或 SubNavigationPosition::Top(以标签页形式渲染子导航):
use Filament\Pages\Enums\SubNavigationPosition;
protected static ?SubNavigationPosition $subNavigationPosition = SubNavigationPosition::End;

SubNavigationPosition::Top 选项会将子导航渲染为页面内容上方的标签页:


删除资源页面
若要从资源中删除某个页面,只需删除资源 Pages 目录中的页面文件,以及 getPages() 方法中的对应条目。
例如,你可能有一个不允许任何人创建记录的资源。删除 Create 页面文件,再从 getPages() 中移除它:
public static function getPages(): array
{
return [
'index' => ListCustomers::route('/'),
'edit' => EditCustomer::route('/{record}/edit'),
];
}删除页面不会删除链接到该页面的操作。这些操作会打开模态,而不是将用户送到不存在的页面。例如,列表页上的 CreateAction、表格或查看页上的 EditAction,或表格或编辑页上的 ViewAction。若要移除这些按钮,也必须删除这些操作。
安全
授权
对于授权,Filament 会遵循应用中已注册的任意 模型策略。使用以下方法:
viewAny()用于从导航菜单中完全隐藏资源,并阻止用户访问任何页面。create()用于控制 创建新记录。update()用于控制 编辑记录。view()用于控制 查看记录。delete()用于阻止删除单条记录。deleteAny()用于阻止批量删除。Filament 使用deleteAny(),因为逐条检查delete()策略性能不佳。使用DeleteBulkAction时,若仍想对每条记录调用delete(),应使用DeleteBulkAction::make()->authorizeIndividualRecords()。未通过授权检查的记录不会被处理。forceDelete()用于阻止强制删除单条已软删除记录。forceDeleteAny()用于阻止批量强制删除。Filament 使用forceDeleteAny(),因为逐条检查forceDelete()策略性能不佳。使用ForceDeleteBulkAction时,若仍想对每条记录调用forceDelete(),应使用ForceDeleteBulkAction::make()->authorizeIndividualRecords()。未通过授权检查的记录不会被处理。restore()用于阻止恢复单条已软删除记录。restoreAny()用于阻止批量恢复。Filament 使用restoreAny(),因为逐条检查restore()策略性能不佳。使用RestoreBulkAction时,若仍想对每条记录调用restore(),应使用RestoreBulkAction::make()->authorizeIndividualRecords()。未通过授权检查的记录不会被处理。reorder()用于控制 在表格中重排记录。
跳过授权
若希望为资源跳过授权,可将 $shouldSkipAuthorization 属性设为 true:
protected static bool $shouldSkipAuthorization = true;保护模型属性
Filament 会将所有模型属性暴露给 JavaScript,除非它们在模型上被设为 $hidden。这是 Livewire 模型绑定的行为。我们保留此功能,以便在初始加载后动态增删表单字段,同时保留字段可能需要的数据。
DANGER
尽管属性可能在 JavaScript 中可见,但只有带表单字段的属性才真正可由用户编辑。这与批量赋值无关。
要在编辑页与查看页上将某些属性从 JavaScript 中移除,可覆盖 mutateFormDataBeforeFill() 方法:
protected function mutateFormDataBeforeFill(array $data): array
{
unset($data['is_admin']);
return $data;
}在此例中,我们将 is_admin 属性从 JavaScript 中移除,因为表单未使用它。
WARNING
当列包含非有效 UTF-8 的二进制数据(例如 geometry、point 或 blob 列)时,将其加入 $hidden 是必须的,而不仅是建议。由于 Filament 会将模型属性暴露给 JavaScript,这些值会作为 Livewire 请求的一部分发送到浏览器,但无法序列化为 JSON。这会导致页面加载失败,常见表现为空白页,且 Laravel 日志中没有错误。
将这些列加入模型的 $hidden 数组,可使其从数组与 JSON 表示中排除,从而解决问题:
protected $hidden = ['location'];若需要使用该值,请通过 访问器 暴露,而不是原始列。