Skip to content
全部文档

代码质量建议

使用 schema 与 table 类

由于许多 Filament 方法在同一处同时定义应用的 UI 与功能,很容易出现超长方法与文件。即便代码风格干净一致,也可能难以阅读。

Filament 在生成资源时会提供专用的 schema 与 table 类,以缓解这一问题。这些类有接受 $schema$tableconfigure() 方法。之后可在任何需要定义 schema 或 table 的地方调用 configure()

例如,若有如下 app/Filament/Resources/Customers/Schemas/CustomerForm.php 文件:

php
namespace App\Filament\Resources\Customers\Schemas;

use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;

class CustomerForm
{
    public static function configure(Schema $schema): Schema
    {
        return $schema
            ->components([
                TextInput::make('name'),
                // ...
            ]);
    }
}

可在资源的 form() 方法中使用它:

php
use App\Filament\Resources\Customers\Schemas\CustomerForm;
use Filament\Schemas\Schema;

public static function form(Schema $schema): Schema
{
    return CustomerForm::configure($schema);
}

table() 也可同样处理:

php
use App\Filament\Resources\Customers\Schemas\CustomersTable;
use Filament\Tables\Table;

public static function table(Table $table): Table
{
    return CustomersTable::configure($table);
}

或对 infolist()

php
use App\Filament\Resources\Customers\Schemas\CustomerInfolist;
use Filament\Schemas\Schema;

public static function infolist(Schema $schema): Schema
{
    return CustomerInfolist::configure($schema);
}

这些 schema 与 table 类故意默认没有父类或接口。若 Filament 强制 configure() 的方法签名,你将无法向该方法传入自己的配置变量;而在多处复用同一类并稍作调整时,这会很有用。

使用组件类

即便使用 schema 与 table 类 将定义拆到独立文件,configure() 仍可能很长。尤其是 schema 或 table 中组件很多,或组件需要大量配置时。

可通过为每个组件创建专用类来缓解。例如,若有一个配置很多的 TextInput,可为其创建专用类:

php
namespace App\Filament\Resources\Customers\Schemas\Components;

use Filament\Forms\Components\TextInput;

class CustomerNameInput
{
    public static function make(): TextInput
    {
        return TextInput::make('name')
            ->label('Full name')
            ->required()
            ->maxLength(255)
            ->placeholder('Enter your full name')
            ->belowContent('This is the name that will be displayed on your profile.');
    }
}

然后可在 schema 或 table 中使用该类:

php
use App\Filament\Resources\Customers\Schemas\Components\CustomerNameInput;
use Filament\Schemas\Schema;

public static function configure(Schema $schema): Schema
{
    return $schema
        ->components([
            CustomerNameInput::make(),
            // ...
        ]);
}

可对多种类型的组件这样做。组件如何命名、存放在何处没有强制规则,但以下是一些建议:

  • Schema components可放在资源的 Schemas/Components 目录,按所包装的组件命名,例如 CustomerNameInputCustomerCountrySelect
  • Table columns可放在资源的 Tables/Columns 目录,按列名加 Column 后缀命名,例如 CustomerNameColumnCustomerCountryColumn
  • Table filters可放在资源的 Tables/Filters 目录,按筛选器名加 Filter 后缀命名,例如 CustomerCountryFilterCustomerStatusFilter
  • Actions可放在资源的 Actions 目录,按操作名加 ActionBulkAction 后缀命名,例如 EmailCustomerActionUpdateCustomerCountryBulkAction

再举一例,下面是一个可能的 EmailCustomerAction 类:

php
namespace App\Filament\Resources\Customers\Actions;

use App\Models\Customer;
use Filament\Actions\Action;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Support\Icons\Heroicon;

class EmailCustomerAction
{
    public static function make(): Action
    {
        return Action::make('email')
            ->label('Send email')
            ->icon(Heroicon::Envelope)
            ->schema([
                TextInput::make('subject')
                    ->required()
                    ->maxLength(255),
                Textarea::make('body')
                    ->autosize()
                    ->required(),
            ])
            ->action(function (Customer $customer, array $data) {
                // ...
            });
    }
}

并可在页面的 getHeaderActions() 中使用:

php
use App\Filament\Resources\Customers\Actions\EmailCustomerAction;

protected function getHeaderActions(): array
{
    return [
        EmailCustomerAction::make(),
    ];
}

或在表格行上使用:

php
use App\Filament\Resources\Customers\Actions\EmailCustomerAction;
use Filament\Tables\Table;

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