开始
概述
面板是 Filament 中的顶级容器,它允许你构建功能丰富的管理面板,其中包括页面、资源、表单、表格、通知、Action、信息列表和 Widget。所有面板都有一个默认的仪表盘,其中包含统计、图表、表格等多种 Widget。
前置要求
使用 Filament 之前,你需要先熟悉 Laravel。Filament 是基于许多 Laravel 核心概念构建的,特别是数据库迁移和 Eloquent ORM。如果你此前 未曾用过 Laravel,或者需要复习,建议你跟着 Laravel Bootcamp 去创建一个小应用。那个教程涵盖了创建 Laravel 应用的基础知识。
Demo 项目
本教程介绍使用 Filament 为兽医诊所建立一个简单的患者管理系统。它将支持添加新患者(猫、狗或兔子),将他们分配给主人(owners),并记录他们接受的治疗(treatments)。该系统将有一个仪表板,上面有患者类型的统计数据,还有一张显示过去一年治疗次数的图表。
设置数据库和模型
这个项目中需要 3 个模型 - Owner
、Patient
和 Treatment
。使用以下 artisan 命令创建:
php artisan make:model Owner -m
php artisan make:model Patient -m
php artisan make:model Treatment -m
定义迁移
数据库迁移请使用如下 schema:
// create_owners_table
Schema::create('owners', function (Blueprint $table) {
$table->id();
$table->string('email');
$table->string('name');
$table->string('phone');
$table->timestamps();
});
// create_patients_table
Schema::create('patients', function (Blueprint $table) {
$table->id();
$table->date('date_of_birth');
$table->string('name');
$table->foreignId('owner_id')->constrained('owners')->cascadeOnDelete();
$table->string('type');
$table->timestamps();
});
// create_treatments_table
Schema::create('treatments', function (Blueprint $table) {
$table->id();
$table->string('description');
$table->text('notes')->nullable();
$table->foreignId('patient_id')->constrained('patients')->cascadeOnDelete();
$table->unsignedInteger('price')->nullable();
$table->timestamps();
});
使用 php artisan migrate
运行迁移文件。
解除所有模型的防护
为了本教程的简洁,我们将禁用 Laravel 的批量赋值保护。Filament 通过只将有效数据存入到模型中,因此模型可以安全地解除防护。要一次性解除所有模型的防护,只需在 app/Providers/AppServiceProvider.php
的 boot()
方法中添加 Model::unguard()
:
use Illuminate\Database\Eloquent\Model;
public function boot(): void
{
Model::unguard();
}
设置模型之间的关联
让我们来设置模型之间的关联。在此系统中,宠物的主人可以拥有多个宠物(患者),而患者可能有多个治疗:
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Owner extends Model
{
public function patients(): HasMany
{
return $this->hasMany(Patient::class);
}
}
class Patient extends Model
{
public function owner(): BelongsTo
{
return $this->belongsTo(Owner::class);
}
public function treatments(): HasMany
{
return $this->hasMany(Treatment::class);
}
}
class Treatment extends Model
{
public function patient(): BelongsTo
{
return $this->belongsTo(Patient::class);
}
}
介绍资源
在 Filament 中,资源是用于为你的 Eloquent 模型创建 CRUD 接口的静态类。他们描述了后台管理员应该如何在面板中和数据交互 - 通过表格和表单。
因为患者(宠物)是这个系统的核心实体。我们就从创建患者资源开始,该资源将帮助我们构建新建、查看、更新及删除患者的页面
使用如下 artisan 命令为 Patient
模型创建一个新的 Filament 资源:
php artisan make:filament-resource Patient
这将在 app/Filament/Resources
目录下创建多个文件:
.
+-- PatientResource.php
+-- PatientResource
| +-- Pages
| | +-- CreatePatient.php
| | +-- EditPatient.php
| | +-- ListPatients.php
在浏览器中访问 /admin/patients
,可以发现一个新的链接(Patients)已经被添加到侧边栏了。点击此链接将会展示一个空表格。让我们来添加表单以创建新患者吧。
设置资源表单
如果你打开 PatientResource.php
文件,你会看到一个 form()
方法,其中有一个空的 schema([...])
数组。添加表单字段到该 schema,构建一个用于新建及编辑患者的表单。
"Name" 文本输入框
Filament 捆绑了大量表单字段。让我们从最简单的文本输入框入手:
use Filament\Forms;
use Filament\Forms\Form;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name'),
]);
}
访问 /admin/patients/create
(或者点击 "New patient" 按钮),可以看到一个患者名称的表单字段已经被添加进来了。
由于该字段是数据库中必须的,且有 255 字符的最大长度限制。让我们添加两个验证规则到该字段:
use Filament\Forms;
Forms\Components\TextInput::make('name')
->required()
->maxLength(255)
尝试不输入名字提交表单,就会发现出现一条信息提示,告诉你 name 字段是必须的。
"Type" select
让我们来添加第二个字段,患者的类型 - 可以是猫、狗或者兔子。因为它是一组固定的选项供选择,使用 Select 字段是不错的选择:
use Filament\Forms;
use Filament\Forms\Form;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
Forms\Components\Select::make('type')
->options([
'cat' => 'Cat',
'dog' => 'Dog',
'rabbit' => 'Rabbit',
]),
]);
}
Select 字段的 options()
方法接收了一个选项数组,使用户可以从中选择。数组的键应该匹配数据库,数组值将用作表单标签。你可以按照你的需求添加尽可能多的宠物类型 到该数组中。
由于该字段也是数据库必须的字段,因此我们需要加上 required()
验证规则方法:
use Filament\Forms;
Forms\Components\Select::make('type')
->options([
'cat' => 'Cat',
'dog' => 'Dog',
'rabbit' => 'Rabbit',
])
->required()
"生日" 选择器
让我们添加一个日期选择器字段用于 date_of_birth
列,同时添加验证规则(生日为必须的,日期不应该迟于今天)。
use Filament\Forms;
use Filament\Forms\Form;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
Forms\Components\Select::make('type')
->options([
'cat' => 'Cat',
'dog' => 'Dog',
'rabbit' => 'Rabbit',
])
->required(),
Forms\Components\DatePicker::make('date_of_birth')
->required()
->maxDate(now()),
]);
}
"Owner" select
我们应该在创建新患者(Patient)的同时,添加其主人(owner)。因为我们在患者模型中添加了一个 BelongsTo
关联(关联到相应的 Owner
模型),我们可以在 Select 字段中使用 relationship()
来加载主人列表,以供选择:
use Filament\Forms;
use Filament\Forms\Form;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
Forms\Components\Select::make('type')
->options([
'cat' => 'Cat',
'dog' => 'Dog',
'rabbit' => 'Rabbit',
])
->required(),
Forms\Components\DatePicker::make('date_of_birth')
->required()
->maxDate(now()),
Forms\Components\Select::make('owner_id')
->relationship('owner', 'name')
->required(),
]);
}
relationship()
方法的首个参数是要模型中定义关联的函数名(用于加载 Select 选项) —— 即本例的 owner
。而第二个参数是关联表的字段名,如本例中的 name
。
我同时让主人是可搜索的(searchable()
),且预加载(preload()
)前 50 个主人到这个可搜索的列表中(以防列表太长):
use Filament\Forms;
Forms\Components\Select::make('owner_id')
->relationship('owner', 'name')
->searchable()
->preload()
->required()
不离开页面新建 Owner
此刻,数据库中没有 Owner。不去创建单独的 Filament 主人资源,让我们提供给用户一个便捷的方式:通过模型表单添加主人(可通过 Select 字段旁边的 +
按钮访问)。使用 createOptionForm()
方法 来嵌入一个模态框,模态框中添加用于主人名称、邮箱及电话的 TextInput
字段:
use Filament\Forms;
Forms\Components\Select::make('owner_id')
->relationship('owner', 'name')
->searchable()
->preload()
->createOptionForm([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
Forms\Components\TextInput::make('email')
->label('Email address')
->email()
->required()
->maxLength(255),
Forms\Components\TextInput::make('phone')
->label('Phone number')
->tel()
->required(),
])
->required()
本例中使用了一些 TextInput 新方法:
label()
覆盖每个字段自动生成的标签。本例中我们将Email
字段的标签设为Email address
,Phone
字段的标签设置为Phone number
。email()
确保只有有效的邮箱地址可以输入到该字段。同时它会改变移动端的键盘布局。tel()
确保只有有效的电话号码可以输入到该字段中。同时会改变移动端的键盘布局。
这个表单应该已经生效了!你可以尝试创建新患者及它们的Owner。创建完成后,页面会跳转到编辑页,你可以在此更新详情。