filament
filament copied to clipboard
Unable to Create Entity When Using HasOne Relationship
Package
filament/filament
Package Version
v2.13.24
Laravel Version
v9.19.0
Livewire Version
v2.10.6
PHP Version
PHP 8.0.19
Bug description
I followed the instructions at https://filamentphp.com/docs/2.x/forms/layout#saving-data-to-relationships to create the following form schema which should save user data while creating the employee and creating the relationship:
class EmployeeResource extends Resource
{
protected static ?string $model = Employee::class;
protected static ?string $navigationIcon = 'heroicon-o-collection';
public static function form(Form $form): Form
{
return $form
->schema([
Fieldset::make('Employee Data')
->schema([
TextInput::make('employee_code')->required(),
]),
Fieldset::make('User')
->relationship('user')
->schema([
TextInput::make('name')->required(),
TextInput::make('email')->email()->required(),
TextInput::make('password')->password()->required(),
])
]);
}
But I keep getting this error:
SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value
insert into `employees` (`employee_code`, `updated_at`, `created_at`) values (TEST, 2022-07-08 20:49:42, 2022-07-08 20:49:42)

Any ideas on what I am doing wrong here?
Steps to reproduce
- Create a model named
Employee
withhasOne
relationship withUser
model - Create
EmployeeResource
using make:filament-resource - Add the following form schema to
EmployeeResource
as per https://filamentphp.com/docs/2.x/forms/layout#saving-data-to-relationships
public static function form(Form $form): Form
{
return $form
->schema([
Fieldset::make('Employee Data')
->schema([
TextInput::make('employee_code')->required(),
]),
Fieldset::make('User')
->relationship('user')
->schema([
TextInput::make('name')->required(),
TextInput::make('email')->email()->required(),
TextInput::make('password')->password()->required(),
])
]);
}
- Run
php artisan serve
- Go to http://127.0.0.1:8000/admin/employees/create and submit
- Error showing on screen
SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value
insert into `employees` (`employee_code`, `updated_at`, `created_at`) values (TEST, 2022-07-08 20:49:42, 2022-07-08 20:49:42)

Reproduction repository
https://github.com/Uolsen/filament-hasone-bug
Relevant log output
SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value
insert into `employees` (`employee_code`, `updated_at`, `created_at`) values (TEST, 2022-07-08 20:49:42, 2022-07-08 20:49:42)
The error indicates that Employee
belongsTo User
, not the other way around. It should be users
table that has employee_id
in such situation.
employees (hasOne User)
- id
- code
users (belongsTo Employee)
- id
- employee_id [ref: - employees.id]
- email
- password
Filament will first save Employee
and then User
. This leads to chicken and egg situation, because you are trying to save Employee
before User
comes into existence, which can't be done. I'm not sure what will happen if you make user_id
nullable.
I don't know whether Filament detects belongsTo
and inverts saving order or not.
Actually the requirement is to have an employee as a child of a user i.e. employee belongs to user and user hasOne employee. Any suggestions on how this can be done?
Also, I discovered that if the relationship is created in the database directly the Edit/Update works fine and the issue is only with Creation.
The documentation here https://filamentphp.com/docs/2.x/admin/resources/getting-started#belongsto is giving an example similar to the requirements I have but its not very clear

Hi @devadattas , were you able to resolve this issue?
I am struggling with this also.
Same problem. Even through relation manager it is not working. For BelongsTo it's working fine. But for HasOne it's not.
Has anyone actually tried to debug it? It would really help us out, as there are other issues that need our attention too.
So, can anyone provide us a reproduction repository URL?
That would allow us to download it and review your bug much easier, so it can be fixed quicker. Please make sure to give us some instructions on where to find the bug, and include a database seeder with everything we need to set it up quickly.
@zepfietje It has been quite some time and I moved on with another work around. I will try to setup a demo of the exact issue sometime early next week for you to review and replicate.
It would be great if anyone else facing this issue freshly can help with this aswell.
I cannot replicate this issue, it works fine for me. So I really do need that reproduction repo from someone.
Since the OP has managed to work around the issue, @francisakortia, @filip-paral or @Uolsen will need to help provide this.
Okey, in the evening I will try to make a repo with bug.
Closing this issue as we cannot reproduce it.
Feel free to open a new issue with a reproduction repository, and then we'll have another look.
I will pin link also there:
https://github.com/Uolsen/filament-hasone-bug
In my spare time i will try to find bug. But it will be great if someone more acknowledged will look at it.
Fixed by #3524.
Experiencing the same error only on creation. Is there any workaround?
@danharrin @devadattas can you guys advise me on how you solved this issue? Also, let me share some context about my current scenario.
In my case, I create coaches, which need to have a user associated. To create the coach, first, the user should be created, because there is a foreign user_id key on coaches which associates coaches and users in a belongsTo relation. I created only the belongsTo relation on the Coach model, but not the opposite on the user model.
Coaches migration
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('coaches', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
// (more stuff here)
//FK
$table->foreign('user_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('coaches');
}
};
Coach model
class Coach extends Model
{
use HasFactory;
protected $guarded = ['id', 'created_at', 'updated_at'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
Coach Filament resource
//(imports rid of)
class CoachResource extends Resource
{
protected static ?string $model = Coach::class;
public static function form(Form $form): Form
{
return $form->schema([
// (coach entity fields rid of)
Section::make('User profile')
->label('User profile')
->schema([
TextInput::make('email')
->disabled()
->email()
->required()
->maxLength(100),
TextInput::make('password')
->label('Password')
->password()
->minLength(8)
->maxLength(255)
->same('password_confirmation')
->disableAutocomplete()
->dehydrateStateUsing(fn($state) => Hash::make($state))
->dehydrated(fn($state) => filled($state))
->required(fn(string $context): bool => $context === 'create'),
TextInput::make('password_confirmation')
->label('Password confirmation')
->password()
->nullable()
->minLength(8)
->maxLength(255)
->disableAutocomplete(),
])
->relationship('user')
->columns(3)
]);
}
}
Here is the error, the same issue as initial, this leads to the chicken and egg situation as @kamilst96 described. The user should be created first before storing the new coach. The issue only happens on creation, edition works properly.
BTW, Filament is pretty awesome, thanks for creating something like that!
BTW, adding nullable to user_id
in the table structure seems to work as a workaround.
public function up(): void
{
Schema::create('coaches', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->nullable();
//FK
$table->foreign('user_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');
});
}