三天能做完,但前提是第一天必须定死权限、关联预加载和资源拆分结构;filament v4/v5 强制拆分为 userform.php、userstable.php 等独立文件,否则 live() 等特性失效;textcolumn 嵌套字段会触发 n+1,须显式预加载并用 getstateusing 避免动态查询。

三天能做完,但前提是第一天必须把权限、关联预加载和资源拆分结构定死,否则第二天开始全是救火。
Filament v4/v5 资源类别必须拆开,别堆在 UserResource.php 里
很多人卡在第二天,是因为从 v3 升上来还习惯把表单、表格、动作全塞进一个文件。v4/v5 默认生成的是独立文件:UserForm.php、UsersTable.php、UserActions.php。这不是可选项,是强制结构——否则 live()、hiddenJs() 这些新特性根本不会生效。
- 运行
php artisan make:filament-resource User后,立刻检查app/Filament/Resources/UserResource.php是否只剩骨架:仅定义模型、label、navigation,其余逻辑全部外移 - 表单字段改在
app/Filament/Resources/UserResource/Pages/CreateUser.php的form()里写;表格列改在app/Filament/Resources/UserResource/Tables/UsersTable.php的columns()里配 - 如果硬要合并,得手动删掉生成的子类,并重写
getPages()和getTableColumns(),但会失去自动类型推导和 IDE 支持
TextColumn::make('department.name') 会触发 N+1,必须显式预加载
第三天页面变慢、数据库连接数飙升,八成出在这儿。Filament 表格默认不自动 with() 关联,点一下就查一次部门名,100 行 = 100 次查询。
- 在资源类里重写
getTableQuery():return parent::getTableQuery()->with(['department', 'profile']); - 列定义改用
TextColumn::make('department.name')->getStateUsing(fn ($record) => $record->department?->name),确保取值不走访问器 - 千万别在
TextColumn里用点号嵌套字段做显示,那是 v3 的写法,v4/v5 下等同于裸写$record->department->name,没 null 安全也没预加载
权限不是装完 Filament Shield 就自动生效的
第二天下午发现“编辑按钮还在,但点进去 403”,问题不在 Shield,而在你没关掉 Filament 默认的 gate 检查链。
- Shield 默认只控制菜单可见性和资源入口,
canView()、canEdit()这些方法仍由 Laravel Gate 驱动,必须确认你的App\Providers\AuthServiceProvider里注册了对应 policy - 若用自定义管理员模型(如
AdminUser),需在config/filament-shield.php中明确设置'auth_provider_model' => 'App\Models\AdminUser',否则 Shield 读不到角色关系 - 开发阶段先关掉全局守卫:
config/filament.php中把'middleware' => ['web']改成['web', 'auth'],避免中间件栈混入 session 冲突
真正卡住进度的从来不是功能怎么写,而是预加载漏了一层、权限策略没绑定、或者资源结构没按 v4/v5 规范拆——这些地方不报错,但会在第二天晚上部署后突然崩。











