Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Arthur Henrique's avatar

Optional One-to-one relationship within the same model

How can I make "nullable" one-to-one relationship in the same model, where I don't store alot of null values inside my table? Let me explain the problem:

I have a User model that may be linked with another User model.

Users Table Migration:

$table->uuid('id')->primary();
$table->string('email')->unique();
$table->string('password');
....

I know that I can add a new column to User's table named user_id which references itself, so I can make a one-to-one relationship. But doing this way, will make alot of users with a "null" value within user_id column.

Knowing this, I tried to make a separated table named user_parents in which I store the User's ID and the Related User's ID.

User Parents Table Migration:

$table->uuid('id')->primary();
$table->foreignUuid('user_id')->constrained();
$table->foreingUuid('parent_id')->constrained('users');
...

Then I created a HasOne relationship within User's, and a User/Parent relation within UserParents

User Model:

public function parent(): HasOne
{
     return $this->hasOne(UserParent::class);
}
...

UserParent Model:

public function parent(): BelongsTo
{
     return $this->belongsTo(UserParent::class, 'parent_id', 'id');
}

public function user(): BelongsTo
{
     return $this->belongsTo(User::class);
}
...

But I to access a User's parent data, I aways have to go thorugh two relations, and this doesn't feel right to me. Is this the intended way, or is there a better way to do it?

Accessing:

echo $user->parent->parent->email;
0 likes
6 replies
Arthur Henrique's avatar

@undeportedmexican I don't think withDefault() solves my problem because it returns a value when a model isn't found (null). But my problem is in how to access the relationship properly.

Anyway, if you have time, can you write a simple example of your solution?

undeportedmexican's avatar

@Arthur Henrique

I'm thinking something like this:

User Model

public function parent(){
	return $this->hasOne(User::class, 'user_id')->withDefault([
		'name'  => 'No parent selected',
	]);
}

So that in the event the user_id is null, you will get an object with the name property set to No parent selected

Again, I haven't experimented with this, but I think it could work on your case.

Arthur Henrique's avatar

@undeportedmexican Thanks for the time. Actually, my problem isn't this one.

I can't do this because I don't have user_id inside User's model. I have within UserParent's model. I didin't put inside the User's model because I don't want to have numerous empty "user_id" value within the table.

Precisely, my question is how to make a relationship that access UserParents.parent_id and returns a user.

With the example I made in the main post, I have to access the data this way:

$user->parent->parent->email;
// We have a user
// Access the User parent relation, to get a UserParent
// Access the UserParent parent relation, to get a User
// Access the wanted data email

I wish that I could retrieve data like this

$user->parent->email;
// We have a user
// Access the User parent relation, to get a User, based on UserParent parent_id
// Access the wanted data email
Tray2's avatar
Tray2
Best Answer
Level 73

I would move that relation into a pivot like table to store the relation just like you tried. I don't know what the relation is that you want but if it's parent child then it's a many to .many you should use.

A parent can have more than one child and a child can have more than one parent,.

Take a look at this post, it might give you some tips

https://tray2.se/posts/database-design

1 like
JeyNia's avatar

Did you find the solution to this? I'm have same problem. I have to do a recursive query to find the parent record. Like model->parent->parent->attribute

Please or to participate in this conversation.