rap-2-h
rap-2-h

Reputation: 31948

Saving one to one relation in Laravel

A User has one (or zero) Company, and a Company belongs to one and only one User. I try to save a company for a user but it adds a new entry in database every time I re-trigger the save method. It's a one to one relation, so I though save method on User.

So Company has one method user():

public function user() {
    return $this->belongsTo(User::class, 'user_id');
}

And User has one method company():

public function company() {
    return $this->hasOne(Company::class, 'user_id');
}

I'm trying to save (so create or update) a user's company like this (in a Controller):

$company = new Company();
$company->name = 'Test';
User::findOrFail(1)->company()->save($company);

First time I run this code it creates the entry in database (OK), but second time it adds a new entry for the same user (Not OK). I thought it will only update the database entry.

Is it a glitch (or something I don't understand in one to one relation) in Laravel or am I doing something wrong? (I think and hope it's the second purpose)

Upvotes: 26

Views: 45719

Answers (3)

Adam
Adam

Reputation: 29019

I'm trying to save (so create or update) a user's company

You can do exactly that with the updateOrCreate method:

User::findOrFail(1)->company()->updateOrCreate([],['name' => 'xyz']);

The first parameter of updateOrCreate is an empty array, because the companies id is determined by the hasOne relationship $user->company().

And by the way, I would recommend not using an auto-increment id field in a hasOne relationship. If you set user_id as primary in your company table, its technically not possible to create duplicate company rows for one user.

Upvotes: 18

Mustafa ASAN
Mustafa ASAN

Reputation: 3825

$user = User::findOrFail(1);
$company = $user->company ?: new Company;
$company->name = 'Test';
$user->company()->save($company);

Upvotes: 31

PaePae
PaePae

Reputation: 1074

Creating and updating need to treat differently. So check the existence of company attribute first.

$user = User::with('company')->findOrFail(1);
if ($user->company === null)
{
    $company = new Company(['name' => 'Test']);
    $user->company()->save($company);
}
else
{
    $user->company->update(['name' => 'Test']);
}

Note that hasOne() does not guarantee that you will have one-to-one relationship, it just telling Eloquent how to create query. It works even you have multiple Company refer to same User, in such case when you call $user->company you will get first Company in the result data set from database.

Upvotes: 41

Related Questions