26

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)

rap-2-h
  • 30,204
  • 37
  • 167
  • 263
  • Check this answer, it might help you: http://stackoverflow.com/a/20764237/5122070 – Mihkel Allorg Sep 10 '15 at 09:39
  • Thanks, but I'm not sure it really helps for this particular problem. My problem is more specific. It's about saving (creating or updating) directly in relation – rap-2-h Sep 10 '15 at 09:46
  • @rap-2-h Mihkel Allorgs reference was correct. One can use the `updateOrCreate` method also on relationships. This is the best way to do it. See my answer https://stackoverflow.com/a/56002200/2311074 – Adam Jun 22 '19 at 08:21

3 Answers3

40

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.

PaePae
  • 1,064
  • 10
  • 12
  • 1
    Ok thanks. "Note that hasOne() does not guarantee that you will have one-to-one relationship, it just telling Eloquent how to create query" -> Very helpful, It's clear enough now. – rap-2-h Sep 10 '15 at 10:10
30
$user = User::findOrFail(1);
$company = $user->company ?: new Company;
$company->name = 'Test';
$user->company()->save($company);
Mustafa ASAN
  • 3,747
  • 2
  • 23
  • 34
16

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.

Adam
  • 25,960
  • 22
  • 158
  • 247