How to get fields from One to One relationship?

I got my migrations sort of setup similar to this laravel daily guide: https://laraveldaily.com/lesson/booking-api-laravel/profile-fields For example in patients migration i got this
Schema::create('patients', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->text('description');
$table->timestamps();
});
Schema::create('patients', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->text('description');
$table->timestamps();
});
Now i can create patients but when i go to edit screen only the patient details (description) shows How do i load all the fields in the edit form? currently its only loading the patient fields.
No description
25 Replies
Dennis Koch
Dennis Kochβ€’2w ago
What does your Form schema look like??
realswagoverlord-revived
public static function form(Form $form): Form
{
return $form
->schema([
...UserCreateForm::get(),
Forms\Components\Textarea::make('description')
->required()
->columnSpanFull(),
]);
}
public static function form(Form $form): Form
{
return $form
->schema([
...UserCreateForm::get(),
Forms\Components\Textarea::make('description')
->required()
->columnSpanFull(),
]);
}
with UserCreateForm looking like
<?php

namespace App\Filament\Traits;

use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;

trait UserCreateForm
{
public static function get(): array
{

return [
TextInput::make('user.first_name')
->required()
->maxLength(255),
TextInput::make('user.last_name')
->required()
->maxLength(255),
DatePicker::make('user.date_of_birth'),
TextInput::make('user.email')
->email()
->required()
->maxLength(255),
TextInput::make('user.phone')
//->tel()
->required()
->maxLength(255),
// Forms\Components\DateTimePicker::make('email_verified_at'),
Select::make('user.gender')
->options(['Male', 'Female'])
->required(),
TextInput::make('user.password')
->password()
->required()
->maxLength(255),
];
}
}
<?php

namespace App\Filament\Traits;

use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;

trait UserCreateForm
{
public static function get(): array
{

return [
TextInput::make('user.first_name')
->required()
->maxLength(255),
TextInput::make('user.last_name')
->required()
->maxLength(255),
DatePicker::make('user.date_of_birth'),
TextInput::make('user.email')
->email()
->required()
->maxLength(255),
TextInput::make('user.phone')
//->tel()
->required()
->maxLength(255),
// Forms\Components\DateTimePicker::make('email_verified_at'),
Select::make('user.gender')
->options(['Male', 'Female'])
->required(),
TextInput::make('user.password')
->password()
->required()
->maxLength(255),
];
}
}
Dennis Koch
Dennis Kochβ€’2w ago
Does the relationship work properly? If you do Patient::find(ID)->user()->toArray() does it output the correct data?
realswagoverlord-revived
i ran this
dd(Patient::find(55)->user());
dd(Patient::find(55)->user());
and i see it gets user but not the attributes :/ here is the user model
<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;


class User extends Authenticatable implements FilamentUser
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable;

/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'first_name',
'last_name',
'email',
'date_of_birth',
'phone',
'filament_user',
'password',
];

function canAccessPanel(Panel $panel): bool
{
return $this->filament_user;
}

/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
];

/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}

public function doctor(): HasOne
{
return $this->hasOne(Doctor::class);
}

public function patient(): HasOne
{
return $this->hasOne(Patient::class);
}

public function contact(): HasOne
{
return $this->hasOne(Contact::class);
}
}
<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;


class User extends Authenticatable implements FilamentUser
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable;

/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'first_name',
'last_name',
'email',
'date_of_birth',
'phone',
'filament_user',
'password',
];

function canAccessPanel(Panel $panel): bool
{
return $this->filament_user;
}

/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
];

/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}

public function doctor(): HasOne
{
return $this->hasOne(Doctor::class);
}

public function patient(): HasOne
{
return $this->hasOne(Patient::class);
}

public function contact(): HasOne
{
return $this->hasOne(Contact::class);
}
}
and here is patient model
<?php

namespace App\Models;

use App\HasNotes;
use App\IsProfile;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Patient extends Model
{
/** @use HasFactory<\Database\Factories\PatientFactory> */
use HasFactory, IsProfile, HasNotes;

protected $guarded = [''];

public function contacts(): HasMany
{
return $this->hasMany(Contact::class);
}
}
<?php

namespace App\Models;

use App\HasNotes;
use App\IsProfile;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Patient extends Model
{
/** @use HasFactory<\Database\Factories\PatientFactory> */
use HasFactory, IsProfile, HasNotes;

protected $guarded = [''];

public function contacts(): HasMany
{
return $this->hasMany(Contact::class);
}
}
IsProfile is this <?php namespace App; use App\Models\User; use Illuminate\Database\Eloquent\Relations\BelongsTo; trait IsProfile { //Delete connected user when profile is deleted public static function booted() { static::deleting(function ($entity) { // Delete the associated user $entity->user()->delete(); }); } public function user(): BelongsTo { return $this->belongsTo(User::class); } } however when i go to phpmyadmin i do the record correctly and the user id column does link to user table
Matthew
Matthewβ€’2w ago
$entity->user->delete();
Merdin
Merdinβ€’2w ago
What do you mean by "I see it gets user but not the attributes?" Also, I do not know if you can retrieve the user form like you mention with:
UserCreateForm::get()
UserCreateForm::get()
I use in my personal project:
UserResource::form($schema)->record($course)->getFlatComponents(withAbsoluteKeys: true)
UserResource::form($schema)->record($course)->getFlatComponents(withAbsoluteKeys: true)
Maybe you can try something similar If you can not figure it out. Publish your project to GitHub so we can help you further.
realswagoverlord-revived
im doing a work around so far trying this
public static function form(Form $form): Form
{
$attributes = $form->model->attributesToArray();
$patient = Patient::where('id', $attributes['id'])->first();
$user = User::where('id', $patient->user_id)->first();
dd($form->model);
// dd($attributes['id']);
return $form
->schema([
...UserCreateForm::get(),
Forms\Components\Textarea::make('description')
->required()
->columnSpanFull(),
]);
}
public static function form(Form $form): Form
{
$attributes = $form->model->attributesToArray();
$patient = Patient::where('id', $attributes['id'])->first();
$user = User::where('id', $patient->user_id)->first();
dd($form->model);
// dd($attributes['id']);
return $form
->schema([
...UserCreateForm::get(),
Forms\Components\Textarea::make('description')
->required()
->columnSpanFull(),
]);
}
just need to assign the values to the $form object and should be sweet Actually never mind because this borks the create form Considering just giving up and making edit forms manually because this functionality is out of scope for Filament.
realswagoverlord-revived
thanks πŸ™‚ thats working (i switched to section because i see it does the same thing but both work). Just one little boo boo, the enum value isnt getting loaded into the select drop down. also now it only works for edit, i can not create anymore. form looks like this public static function form(Form $form): Form { return $form ->schema([ Section::make('User Information') ->relationship('user') ->schema( UserCreateForm::get(), Forms\Components\Textarea::make('description') ->required() ->columnSpanFull(), ) ->columns(2), ]); } and the usercreateform class <?php namespace App\Filament\Traits; use Filament\Forms\Components\DatePicker; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; trait UserCreateForm { public static function get(): array { return [ TextInput::make('first_name') ->required() ->maxLength(255), TextInput::make('last_name') ->required() ->maxLength(255), DatePicker::make('date_of_birth'), TextInput::make('email') ->email() ->required() ->maxLength(255), TextInput::make('phone') //->tel() ->required() ->maxLength(255), // Forms\Components\DateTimePicker::make('email_verified_at'), Select::make('gender') ->options(['Male', 'Female']) ->required(), TextInput::make('password') ->password() ->required() ->maxLength(255), ]; } } i had to remove 'user' at the start for the fields to show in edit form
Dennis Koch
Dennis Kochβ€’2w ago
Try this πŸ˜‰ Select::make()->enum(Gender::class)
realswagoverlord-revived
Unfortunately now there is another problem
<?php

namespace App\Filament\Traits;

use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Gender;

trait UserCreateForm
{
public static function get(): array
{

return [
TextInput::make('first_name')
->required()
->maxLength(255),
TextInput::make('last_name')
->required()
->maxLength(255),
DatePicker::make('date_of_birth'),
TextInput::make('email')
->email()
->required()
->maxLength(255),
TextInput::make('phone')
//->tel()
->required()
->maxLength(255),
// Forms\Components\DateTimePicker::make('email_verified_at'),
Select::make('gender')
->enum(Gender::class)
->required(),
TextInput::make('password')
->password()
->required()
->maxLength(255),
];
}
}
<?php

namespace App\Filament\Traits;

use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Gender;

trait UserCreateForm
{
public static function get(): array
{

return [
TextInput::make('first_name')
->required()
->maxLength(255),
TextInput::make('last_name')
->required()
->maxLength(255),
DatePicker::make('date_of_birth'),
TextInput::make('email')
->email()
->required()
->maxLength(255),
TextInput::make('phone')
//->tel()
->required()
->maxLength(255),
// Forms\Components\DateTimePicker::make('email_verified_at'),
Select::make('gender')
->enum(Gender::class)
->required(),
TextInput::make('password')
->password()
->required()
->maxLength(255),
];
}
}
Without the user. before the fields i can edit records, however i am unable to create any.
SQLSTATE[HY000]: General error: 1364 Field 'first_name' doesn't have a default value (Connection: mysql, SQL: insert into `users` (`name`, `updated_at`, `created_at`) values (, 2025-11-10 16:44:32, 2025-11-10 16:44:32))
SQLSTATE[HY000]: General error: 1364 Field 'first_name' doesn't have a default value (Connection: mysql, SQL: insert into `users` (`name`, `updated_at`, `created_at`) values (, 2025-11-10 16:44:32, 2025-11-10 16:44:32))
I have added this before to make the relations work when creating new patient
<?php

namespace App\Filament\Traits;

use App\Models\User;

trait UserMutateCreateRecord
{
protected function mutateFormDataBeforeCreate(array $data): array
{

$userData = $data['user'] ?? [];

$userData['name'] = ($userData['first_name'] ?? '') . ($userData['last_name'] ?? '');

$user = User::create($userData);

$data['user_id'] = $user->id;

unset($data['user']);

return $data;
}

protected function mutateFormDataBeforeSave(array $data): array
{
$userData = $data['user'] ?? [];

if ($this->record->user) {
$this->record->user->update($userData);
}

unset($data['user']);

return $data;
}
}
<?php

namespace App\Filament\Traits;

use App\Models\User;

trait UserMutateCreateRecord
{
protected function mutateFormDataBeforeCreate(array $data): array
{

$userData = $data['user'] ?? [];

$userData['name'] = ($userData['first_name'] ?? '') . ($userData['last_name'] ?? '');

$user = User::create($userData);

$data['user_id'] = $user->id;

unset($data['user']);

return $data;
}

protected function mutateFormDataBeforeSave(array $data): array
{
$userData = $data['user'] ?? [];

if ($this->record->user) {
$this->record->user->update($userData);
}

unset($data['user']);

return $data;
}
}
Dennis Koch
Dennis Kochβ€’2w ago
I think the User is created first and then filled. So the fields need to be nullable. That shouldn't be needed
realswagoverlord-revived
when i remove it i get this when creating new patient
SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value (Connection: mysql, SQL: insert into `patients` (`updated_at`, `created_at`) values (2025-11-10 16:49:48, 2025-11-10 16:49:48))
SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value (Connection: mysql, SQL: insert into `patients` (`updated_at`, `created_at`) values (2025-11-10 16:49:48, 2025-11-10 16:49:48))
how can i make sure the user_id is passed when user is created first?
Dennis Koch
Dennis Kochβ€’2w ago
I think your db schema follows a BelongsTo relationship. Not a HasOne
Dennis Koch
Dennis Kochβ€’2w ago
There should be a patient_id on the users table. Not the other way. https://laravel.com/docs/master/eloquent-relationships#one-to-one
Eloquent determines the foreign key of the relationship based on the parent model name. In this case, the Phone model is automatically assumed to have a user_id foreign key. If you wish to override this convention, you may pass a second argument to the hasOne method:
Eloquent: Relationships - Laravel Upcoming - The PHP Framework For ...
Laravel is a PHP web application framework with expressive, elegant syntax. We’ve already laid the foundation β€” freeing you to create without sweating the small things.
realswagoverlord-revived
i got it setup differently. My web app is a patient management system and there are doctors, patients and contact profiles. They are all on a BelongsTo relationship to the user model. i did it like this instead of just using roles because they will have different fields
Dennis Koch
Dennis Kochβ€’2w ago
i got it setup differently.
Yes. But you set it up wrong. You shared a model with a HasOne relationship before, though. It's actually a BelongsTo.
realswagoverlord-revived
On user model it has HasOne for each profile doctor() patient() and the profile models all have the user() belongs to function The HasOne was in the user model, all profile models have belong to functions
Dennis Koch
Dennis Kochβ€’2w ago
Oh, that's right πŸ™ˆ
realswagoverlord-revived
All good πŸ™‚ this is my first "real" project so if i made a few boo boos i won’t be surprised πŸ˜„ I mainly do ASP.NET
Dennis Koch
Dennis Kochβ€’2w ago
Okay, so what's probably is the issue then: Filament saves your model Patient first, then saves the User. So you need to allow user_id to be nullable.
realswagoverlord-revived
Ah aight ill try that tried this and i can edit the patients but still cant create any πŸ˜†
realswagoverlord-revived
i tried adding this trait again
<?php

namespace App\Filament\Traits;

use App\Models\User;

trait UserMutateCreateRecord
{
protected function mutateFormDataBeforeCreate(array $data): array
{

$userData = $data['user'] ?? [];


$userData['name'] = ($userData['first_name'] ?? '') . ($userData['last_name'] ?? '');
dd($data, $userData);

// $user = User::create($userData);

// $data['user_id'] = $user->id;

// unset($data['user']);

return $data;
}

protected function mutateFormDataBeforeSave(array $data): array
{
$userData = $data['user'] ?? [];

if ($this->record->user) {
$this->record->user->update($userData);
}

unset($data['user']);

return $data;
}
}
<?php

namespace App\Filament\Traits;

use App\Models\User;

trait UserMutateCreateRecord
{
protected function mutateFormDataBeforeCreate(array $data): array
{

$userData = $data['user'] ?? [];


$userData['name'] = ($userData['first_name'] ?? '') . ($userData['last_name'] ?? '');
dd($data, $userData);

// $user = User::create($userData);

// $data['user_id'] = $user->id;

// unset($data['user']);

return $data;
}

protected function mutateFormDataBeforeSave(array $data): array
{
$userData = $data['user'] ?? [];

if ($this->record->user) {
$this->record->user->update($userData);
}

unset($data['user']);

return $data;
}
}
However on the dd line i see this
No description

Did you find this page helpful?