资源并非在 Filament 面板中与 Eloquent 记录交互的唯一方式。尽管资源可能解决了你的许多需求,但资源的“索引”(根) 页面包含一个表格,其中列出了该资源中的记录。
有时,资源中不需要列出记录的表格。只有一个用户与之交互的记录。如果用户访问页面时它尚不存在,那么当用户首次提交表单以保存它时,它就会被创建。如果记录已存在,则在页面首次加载时将其载入表单,并在表单提交时进行更新。
例如,一个CMS可能有一个 Page Eloquent 模型和一个 PageResource,但您可能也希望在 PageResource 之外创建一个独立的页面来编辑网站的“主页”。这允许用户直接编辑主页,而无需导航到 PageResource 并从表格中找到主页记录。
这方面的其他例子包括一个“设置”页面,或者一个供当前登录用户使用的“个人资料”页面。然而,对于这些用例,我们建议您使用Spatie Settings 插件以及 Filament 的个人资料功能,它们需要更少的代码来实现。
尽管 Filament 中没有特定的“单一资源”功能,但它是一种备受需求的行为,并且可以使用一个 [自定义页面](../navigation/custom-pages) 配合一个 [表单](../forms) 相当简单地实现。本指南将解释如何实现这一点。
首先,创建一个自定义页面:
php artisan make:filament-page ManageHomepage此命令将创建两个文件 - 一个页面类,位于/Filament/Pages您的资源目录下的目录中,以及一个 Blade 视图,位于/filament/pages资源视图目录下的目录中。
页面类应包含以下元素:
$data 属性,用于存储表单的当前状态。mount() 方法,它将从数据库加载当前记录并用其数据填充表单。如果记录不存在,null 将被传递给表单的 fill() 方法,该方法会将任何默认值赋给表单字段。form() 方法,用于定义表单的模式。该表单包含 components() 方法中的字段。应该使用 record() 方法来指定表单应从中加载关系数据的记录。应该使用 statePath() 方法来指定属性 ($data) 的名称,表单的状态应该存储在该属性中。save() 方法,它会将表单数据保存到数据库。 getState() 方法运行表单验证并返回有效的表单数据。此方法应检查记录是否已存在,如果不存在,则创建一个新记录。模型的 wasRecentlyCreated 属性可用于确定记录是否刚刚创建,如果是,则任何关联关系也应保存。会向用户发送通知以确认记录已保存。getRecord() 方法,虽然不是严格必需的,但拥有它是一个好主意。此方法将返回表单正在编辑的 Eloquent 记录。它可以跨其他方法使用,以避免代码重复。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 array<string, 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(['mod+s']),
]),
]),
])
->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();
}
}页面的 Blade 视图应渲染表单:
<x-filament::page>
{{ $this->form }}
</x-filament::page>