十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Filament 单条记录编辑页面(Singular Resource)实战:用自定义页面 + 表单实现“首页/设置“式单记录管理

Filament 单条记录编辑页面(Singular Resource)实战:用自定义页面 + 表单实现“首页/设置“式单记录管理 Filament 单条记录编辑页面Singular Resource实战用自定义页面 表单实现首页/设置式单记录管理【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filament本文围绕 Filament 官方文档docs/03-resources/09-singular.md讲解单条资源Singular Resource的实现方式当业务中只需要编辑唯一的一条 Eloquent 记录如网站首页、全局配置时如何用make:filament-page生成的自定义页面配合Schema/Form实现记录不存在则首次提交自动创建、已存在则回填并更新的完整闭环。文中所有代码均可从仓库的官方演示应用docs-assets/app中找到真实对照实现并附源码级原理说明。一、什么场景适合用单条资源资源Resource的索引页默认是一张记录列表表格。但并非所有场景都需要列表有时用户要操作的只有唯一的一条记录典型场景包括CMS 中的首页Homepage编辑页模型Page/WebsitePage可能由资源管理但希望有一个独立页面直接编辑首页无需在资源列表中找到那条记录全局Settings设置页当前登录用户的Profile资料页。单条资源的行为模型是用户访问页面时如果记录尚不存在则什么都不做表单以默认值填充表单首次提交时创建该记录如果记录已存在页面加载时将其数据读入表单提交时执行更新。需要说明的是官方文档明确建议对于Settings和Profile这类通用需求优先使用 Spatie Settings 插件或 Filament 自带的 Profile 功能它们需要的代码更少对应文档docs/07-users/01-overview.md中介绍的认证与用户功能。而首页这类自定义单条记录场景则是本指南的适用对象。二、创建页面骨架Filament 中并没有名为singular resource的独立特性官方文档给出的做法是基于自定义页面 表单组合实现步骤从一条 Artisan 命令开始php artisan make:filament-page ManageHomepage该命令会生成两个文件资源目录下/Filament/Pages中的页面类资源视图目录/filament/pages中的 Blade 视图。三、页面类的核心构成页面类需要包含以下要素与原文档一一对应要素作用$data属性持有表单的当前状态mount()方法从数据库加载当前记录并用其数据填充表单记录不存在时向fill()传null表单字段会落入各自的默认值form()方法定义表单 Schema。字段在components()此处为Form::make([...])中定义用record()指定表单加载关系数据的记录用statePath()指定表单状态存放到哪个属性即$datasave()方法把表单数据写回数据库。getState()会执行表单校验并返回合法数据需自行判断记录是否已存在不存在则创建用模型的wasRecentlyCreated判断是否刚创建是则一并保存关系数据最后发送通知确认保存成功getRecord()方法虽非必需但推荐返回表单正在编辑的 Eloquent 记录供其他方法复用避免重复查询代码完整实现源自官方文档与仓库演示应用 ManageHomepage.php 完全一致namespace App\Filament\Pages; use App\Models\WebsitePage; use Filament\Actions\Action; use Filament\Forms\Components\RichEditor; use Filament\Forms\Components\TextInput; use Filament\Notifications\Notification; use Filament\Pages\Page; use Filament\Schemas\Components\Actions; use Filament\Schemas\Components\Form; use Filament\Schemas\Schema; /** * property-read Schema $form */ class ManageHomepage extends Page { protected string $view filament.pages.manage-homepage; /** * var arraystring, mixed | null */ public ?array $data []; public function mount(): void { $this-form-fill($this-getRecord()?-attributesToArray()); } public function form(Schema $schema): Schema { return $schema -components([ Form::make([ TextInput::make(title) -required() -maxLength(255), RichEditor::make(content), // ... ]) -livewireSubmitHandler(save) -footer([ Actions::make([ Action::make(save) -submit(save) -keyBindings([mods]), ]), ]), ]) -record($this-getRecord()) -statePath(data); } public function save(): void { $data $this-form-getState(); $record $this-getRecord(); if (! $record) { $record new WebsitePage(); $record-is_homepage true; } $record-fill($data); $record-save(); if ($record-wasRecentlyCreated) { $this-form-record($record)-saveRelationships(); } Notification::make() -success() -title(Saved) -send(); } public function getRecord(): ?WebsitePage { return WebsitePage::query() -where(is_homepage, true) -first(); } }3.1 提交链路的源码原理livewireSubmitHandler如何把表单接到save()Form组件在toEmbeddedHtml()中会把提交处理函数渲染为 Livewire 的wire:submit指令即表单一旦以 HTML 提交就会调用页面上的save()方法而按钮通过-submit(save)触发同一处理函数。从源码看Form.php 中的livewireSubmitHandler()只保存处理函数名getLivewireSubmitHandler()会先求值该闭包/字符串再回退到action上的 Livewire Click 处理器public function livewireSubmitHandler(string | Closure | null $handler): static { $this-livewireSubmitHandler $handler; return $this; } public function getLivewireSubmitHandler(): ?string { return $this-evaluate($this-livewireSubmitHandler) ?? $this-action?-getLivewireClickHandler(); }随后在 toEmbeddedHtml() 中该值被合并进组件属性$attributes (new FilamentComponentAttributeBag) -merge([ id $this-getId(), wire:submit $this-getLivewireSubmitHandler(), ], escape: false)这就是为什么页面类中必须存在一个名为save的公共方法且Action::make(save)-submit(save)与livewireSubmitHandler(save)的命名要一致。footer()方法同文件 L83-L88则是把按钮放入表单页脚 Schema 的入口-keyBindings([mods])让 Ctrl/CmdS 也能触发保存。3.2statePath(data)的作用statePath()指定表单状态存放的 Livewire 属性路径。本例中表单各字段的值统一读写public ?array $data属性这也是mount()之后前端输入能够被 Livewire 追踪、并在save()中通过$this-form-getState()拿到校验后数据的前提。其定义见 HasState.php。3.3save()中的先查后建与关系保存$this-form-getState()运行表单校验规则如title的required、maxLength(255)并返回状态数组若getRecord()返回nullnew WebsitePage()并打上is_homepage true标记保证唯一性由查询条件锁定$record-wasRecentlyCreated是 Eloquent 在save()后设置的状态位仅当本次保存是创建时为真——此时才需要$this-form-record($record)-saveRelationships()把belongsToMany/BelongsTo等关系写入更新已有记录时关系由各自的字段如 Select 关系字段自动维护重复调用反而多余。3.4mount()中为何使用attributesToArray()fill()接受数组$this-getRecord()?-attributesToArray()保证传入的是纯属性数组而非模型实例记录不存在时该表达式为null表单字段将落入各自定义的默认值——这正是不存在则留空待创建行为的来源。四、Blade 视图页面视图只需渲染表单x-filament::page会提供页头、内容容器等标准面板布局x-filament::page {{ $this-form }} /x-filament::page五、对照仓库演示应用完整可运行的落地示例仓库内的官方演示应用提供了该文档的完整参照实现包括模型、数据表与页面可直接阅读页面类ManageHomepage.php —— 与上文代码一致并额外设置了导航属性$navigationIcon Heroicon::OutlinedHome与$navigationSort 5让该页面以房屋图标出现在面板侧边导航中模型WebsitePage.php ——is_homepage通过$casts声明为boolean数据表website_pages 迁移 —— 字段为titlestring、contenttext可空、is_homepageboolean默认 false。从截图脚本 schema.js 中可以看到该页面在演示应用中的路由为admin/manage-homepage即页面类ManageHomepage按 Filament 命名规则自动生成了/admin/manage-homepage地址无需手动定义路由。六、落地要点与选型建议命令与文件位置php artisan make:filament-page ManageHomepage之后页面类在app/Filament/Pages视图在resources/views/filament/pages/manage-homepage.blade.php唯一性必须自己保证Filament 不会自动防止多条首页getRecord()中的where(is_homepage, true)-first()是单条记录的定位契约生产环境可考虑在数据库层面加唯一约束保存关系数据如果表单包含Select关系字段务必保留wasRecentlyCreated分支下的saveRelationships()否则首次创建时关系不会被写入替代方案优先纯Settings场景官方推荐使用 Spatie Settings 插件Profile场景推荐使用 Filament 的用户资料功能见 docs/07-users/01-overview.md两者代码量更小权限控制可结合 自定义页面文档 中的canAccess()方法限制该页面在导航中的可见性与直接访问权限。【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filament创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表