编程

Filament: 如何在表格操作触发后刷新插件

571 2023-04-03 03:09:00

介绍

本文将介绍如何使用 Filament 插件(Widget)创建统计卡片,用来展示用户统计信息。我们将展示如何使用 Livewire 生命周期 hook 和事件,在用户表修改时刷新插件。

安装

首先,安装一个名为 filament-widget-examples 的 Laravel 应用:

laravel new filament-widget-examples

然后使用命令安装 Filament:

cd filament-widget-examples
composer require filament/filament

Filament 推荐添加以下内容到 composer.json 的 post-update-cmd:

"post-update-cmd": [
    // ...
    "@php artisan filament:upgrade"
]

编辑用户 Migration 文件:

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->boolean('is_admin');
    $table->boolean('is_active');
    $table->rememberToken();
    $table->timestamps();
});

编辑用户工厂 definition 方法:

//database\factories\UserFactory.php
public function definition()
{
    return [
        'name' => fake()->name(),
        'email' => fake()->unique()->safeEmail(),
        'email_verified_at' => now(),
        'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
        'remember_token' => Str::random(10),
        'is_admin' => fake()->boolean(),
        'is_active' => fake()->boolean(),
    ];
}

编辑 DatabaseSeeder 的 run 方法:

//database\seeders\DatabaseSeeder.php
public function run()
{
    \App\Models\User::factory(100)->create();
}

编辑用户模型:

//app/Models/User.php
protected $fillable = [
    'name',
    'email',
    'password',
    'is_active',
    'is_admin'
];

运行 migrate 命令:

php artisan migrate --seed

用户资源 User Resource

添加 User Resource 和插件 Widget:

php artisan make:filament-resource User --simple
php artisan make:filament-widget UserOverview --resource=UserResource --stats-overview

编辑用户资源文件:

表单:

//app/Filament/Resources/UserResource.php
public static function form(Form $form): Form
{
    return $form
        ->schema([
            Forms\Components\TextInput::make('name')
                ->required()
                ->maxLength(255),
            Forms\Components\TextInput::make('email')
                ->email()
                ->required()
                ->maxLength(255),
            Forms\Components\Toggle::make('is_admin'),
            Forms\Components\Toggle::make('is_active'),
        ]);
}

表格:

//app/Filament/Resources/UserResource.php
public static function table(Table $table): Table
{
    return $table
        ->columns([
            Tables\Columns\TextColumn::make('name'),
            Tables\Columns\TextColumn::make('email'),
            Tables\Columns\IconColumn::make('is_admin')
                ->boolean(),
            Tables\Columns\IconColumn::make('is_active')
                ->boolean(),
            Tables\Columns\TextColumn::make('created_at')
                ->date(),
            Tables\Columns\TextColumn::make('updated_at')
                ->date(),
        ])
        ->filters([
            Tables\Filters\TernaryFilter::make('is_admin'),
            Tables\Filters\TernaryFilter::make('is_active'),
        ])
        ->actions([
            Tables\Actions\EditAction::make(),
            Tables\Actions\DeleteAction::make(),
        ])
        ->bulkActions([
            Tables\Actions\DeleteBulkAction::make(),
        ]);
}

引入插件

添加 getWidgets 方法:

//app/Filament/Resources/UserResource.php
use App\Filament\Resources\UserResource\Widgets\UserOverview;
public static function getWidgets(): array
{
    return [
        UserOverview::class,
    ];
}

添加 getHeaderWidgets 方法:

//app/Filament/Resources/UserResource/Pages/ManageUsers.php
protected function getHeaderWidgets(): array
{
    return [
        UserOverview::class,
    ];
}

插件卡片

你可以使用插件卡,在一个插件内展示许多许多不同的统计。编辑用户概览插件:

//app/Filament/Resources/UserResource/Widgets/UserOverview.php
class UserOverview extends BaseWidget
{
    protected static ?string $pollingInterval = null;
 
    protected function getCards(): array
    {
        $usersCount = User::selectRaw('
            COUNT(*) as total,
            SUM(CASE WHEN is_admin THEN 1 ELSE 0 END) AS admin,
            SUM(CASE WHEN is_active THEN 1 ELSE 0 END) AS active
        ')->first();
 
        return [
            Card::make('Total', $usersCount->total)
                ->color('primary')
                ->description('Total users'),
 
            Card::make('Admin', $usersCount->admin)
                ->color('danger')
                ->description('Admin users'),
 
            Card::make('Active', $usersCount->active)
                ->color('success')
                ->description('Active users'),
        ];
    }
}

到浏览器中查看用户资源。其中有三个头部插件:Total users, Admin users 及 Active users.

你可以在用户表中删除用户,表格里的数据更新了,但是这些插件里的信息不会更新。你需要手动刷新才能更新插件。

自动刷新插件

Livewire 生命周期

每个 Livewire 组件都有生命周期。生命周期狗子让你可以在组件生命周期的任意一个地方运行代码。我们可以使用 Updated 钩子,在 Livewire 组件更新后运行。

Livewire 事件监听器

监听器是 key->value 键值对,key 是为监听的事件,值是组件上调用的方法。

我们可以使用 $refresh 魔术操作重新渲染组件。

在 UserOverviewWidget 文件中添加一个监听器:

//app/Filament/Resources/UserResource/Widgets/UserOverview.php
protected $listeners = ['updateUserOverview' => '$refresh'];

updated 钩子方法提供了两个属性:

  • $name: 触发的操作的名称。
  • $value: 触发的操作的值。

我们将使用 $name 属性监听两个表格事件:

  • mountedTableAction: 单个删除操作点击后执行。
  • mountedTableBulkAction: 批量删除操作点击后执行。

然后,我们可以在 updated 方法使用这些名字以及触发 updateUserOverview 事件:

//app/Filament/Resources/UserResource/Pages/ManageUsers.php
public function updated($name)
{
    if (Str::of($name)->contains(['mountedTableAction', 'mountedTableBulkAction'])) {
        $this->emit('updateUserOverview');
    }
}

现在,每次删除操作点击后都会更新插件。

你可以检查表格事件,比如:

//text input in the top right of the table
if (Str::of($name)->contains('tableSearchQuery')) {
    ...
}
 
//the table filter form
if (Str::of($name)->contains('tableFilters')) {
    ...
}