You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Filament自定义页面Repeater关联数据填充与保存问题

Laravel Filament自定义页面关联数据保存错误解决

问题描述

在Laravel Filament自定义页面中填充并保存User模型关联的UserProfessionalExperience数据时,出现错误:

Call to a member function UserProfessionalExperience() on null

在mount()方法中执行dd(auth()->user()->UserProfessionalExperience)能正确返回数据,但Repeater组件中使用relationship()方法无法获取关联数据。

错误原因

  1. 表单绑定问题:Repeater的relationship()方法需要表单绑定到具体的模型实例,当前表单使用statePath('data')绑定到数组,导致无法找到关联的User模型实例,触发null错误。
  2. 关联更新逻辑错误:保存方法中直接对hasMany关联调用update()方法,不符合Laravel关联更新的逻辑,hasMany关联需要用批量创建/更新的方式处理。
  3. 命名规范问题:模型关联方法名首字母大写,不符合Laravel小驼峰命名约定,可能引发潜在的识别问题。

解决方案

1. 修正表单与模型绑定

移除statePath('data'),将表单直接绑定到当前认证用户的模型实例,让relationship()能正确识别关联关系。

2. 调整mount方法填充逻辑

直接使用模型实例填充表单,无需手动转换为数组。

3. 修正关联保存逻辑

针对hasMany关联特性,采用先清理旧数据、再批量保存新数据的方式,确保数据同步。

4. 统一命名规范

将模型关联方法名改为小驼峰复数形式,符合Laravel约定。


修改后的代码

自定义页面代码(EditProfessionalExperience.php)

<?php

namespace App\Filament\Candidato\Pages;

use Filament\Pages\Page;
use Filament\Support\Exceptions\Halt;
use Filament\Notifications\Notification;
use Filament\Actions\Action;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Form;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Repeater;
use App\Models\User;

class EditProfessionalExperience extends Page implements HasForms
{
    use InteractsWithForms;

    public ?User $record = null;

    protected static ?string $navigationIcon = 'heroicon-o-document-text';
    protected static string $view = 'filament.candidato.pages.edit-professional-experience';
    protected static ?string $title = 'Experiência Profissional';
    protected static ?string $navigationLabel = 'Experiência Profissional';
    protected static ?string $slug = 'experiencia-profissional';

    public function mount(): void 
    {
        $this->record = auth()->user();
        $this->form->fill($this->record->attributesToArray());
    }

    public function form(Form $form): Form
    {
        return $form
            ->model($this->record)
            ->schema([
                Section::make('Experiência Profissional')
                    ->description('Nesta seção, você pode listar suas experiências profissionais passadas. Isso inclui cargos, empresas e suas principais responsabilidades. Adicione quantas experiências quiser.')
                    ->schema([
                        Repeater::make('userProfessionalExperiences')
                            ->relationship()
                            ->columns(2)
                            ->schema([
                                TextInput::make('company_name')
                                    ->label('Nome da empresa')
                                    ->required(),
                            ])
                            ->mutateRelationshipDataBeforeCreateUsing(function (array $data): array {
                                $data['user_id'] = auth()->id();
                                return $data;
                            })
                    ])
            ]);
    }

    protected function getFormActions(): array
    {
        return [
            Action::make('save')
                ->label(__('filament-panels::resources/pages/edit-record.form.actions.save.label'))
                ->submit('save'),
        ];
    }

    public function save(): void
    {
        try {
            $data = $this->form->getState();

            $this->record->userProfessionalExperiences()->delete();
            if (!empty($data['userProfessionalExperiences'])) {
                $this->record->userProfessionalExperiences()->saveMany(
                    collect($data['userProfessionalExperiences'])->map(function ($item) {
                        return new \App\Models\UserProfessionalExperience($item);
                    })
                );
            }
        } catch (Halt $exception) {
            return;
        }

        Notification::make() 
            ->success()
            ->title(__('filament-panels::resources/pages/edit-record.notifications.saved.title'))
            ->send();
    }
}

User模型关联方法修改

public function userProfessionalExperiences()
{
    return $this->hasMany(\App\Models\UserProfessionalExperience::class, 'user_id');
}

内容的提问来源于stack exchange,提问作者user2950020

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 15:15:11