One-to-One Basics0:00
A one-to-one relationship is really easy to understand. For example, a person has one social security number, or a User has one account, or a User has one profile, or a Subscriber has one team they may belong to. Any of those would work. So let's use the idea of a profile. I already have a users table set up, so let's set up a profiles table. And right off the bat, we need a connection between the Profile and the User. So that's what the foreign key is for. The user_id is unsigned, which means it has to be positive, and it cannot be null. OK, so now I know any record here is associated with a specific user_id from the users table.
The user ID is unsigned, which means it has to be positive, and it cannot be null. OK, so now I know any record here is associated with a specific user ID from the users table. Next, we could add anything related to a profile. Maybe the user's website, and that can be null. Maybe their Twitter handle. You get the idea. So now, we could set up a new profile, associate it with a user with an ID of 1. That's a one-to-one relationship. And if you're ever in doubt, speak it out. Does one user have multiple profiles?
And if you're ever in doubt, speak it out. Does one User have multiple Profiles? No, that doesn't make sense. Does one Profile have multiple Users it is associated with? No. But does a User have one Profile? Yes, that is correct. So we know we have a one-to-one relationship when a record from the users table has one Profile, and a record from the profiles table has one User. It's a one-to-one relationship.
Joining Users and Profiles1:37
profile, and a record from the profiles table has one User. It's a one-to-one relationship. Now we could write a query here. Yes, I want our users, and we only have one right now. But let's do an inner join to pull in the profiles table on the condition that the user_id field is equal to the id of the User. Again, that is the connecting tissue. So now we get our User, but if we scroll down to the end, we have information about their profile. And this is where it can get a little bit tricky, because if you think about it, with
profile. And this is where it can get a little bit tricky, because if you think about it, with a one-to-one relationship, you always have the ability to take any of the fields here and move them directly onto the User. Or in other words, rather a new table, your users table could be extended to have a website and a Twitter handle, and anything else you add there. It would still work, because it's effectively the same thing. It's only a one-to-one relationship there. And really, it just kind of comes down to the situation. There are times when you think, I'll just add another column to my users table.
Laravel Model and Migration2:35
And really, it just kind of comes down to the situation. There are times when you think, I'll just add another column to my users table. But in other cases, you'll have a clump of fields or data, and it kind of feels wrong to put it on users. So instead, you'll create a brand new table and then set up a connection back to the original table. And that's what we've done here. So now that you understand a one-to-one relationship, let's review how you can set this up in Laravel. I'm going to delete that profiles table and then start from scratch. Make me a model called Profile.
I'm going to delete that profiles table and then start from scratch. Make me a model called Profile. And as part of that, I want a migration. All right. So let's go to that migration. And we'll start by setting up our foreign key. Now, don't forget, it would be unsignedInteger. But because the primary key in Laravel is a bigInteger, you need to make sure that your foreign key matches that type. So we would do unsignedBigInteger.
your foreign key matches that type. So we would do unsignedBigInteger. OK, next, anything else? You could do the website. You could do the Twitter handle. Finally, we'll set up our constraint. I'll say the user_id references the id column on the users table. And if you were to delete that User, let's cascade and delete the profile as well. And there we go. This is effectively the programmatic version of what we did manually in SQL Pro just a
And there we go. This is effectively the programmatic version of what we did manually in SQL Pro just a few minutes ago. OK, so I'm going to go ahead and migrate my database. And if I switch back, we now have that again exactly as we did before. And you also notice we have a relation set up that we didn't do earlier. Now, the next step is I want to play around with Eloquent. So yes, we could track down that User. But I want to access his profile. But I don't have any relationship like that set up.
Defining Eloquent Relationships4:21
But I want to access his profile. But I don't have any relationship like that set up. So no will be returned. Let's do it now. In my app directory, we have a User. And if I scroll down right here, if I want to access their profile, it is a hasOne relationship. A User has one Profile. But what about the inverse? If I go to the Profile model, if I have an existing Profile and I want to access the User associated with it, that should be available to me.
If I go to the Profile model, if I have an existing Profile and I want to access the User associated with it, that should be available to me. Well, that is a belongsTo relationship. A Profile belongs to a User. Finally, one last thing. By default, Laravel protects against mass assignment. I'm just going to turn it off. I'm not going to guard anything. OK, so let's give this another shot. I will boot up php artisan tinker.
OK, so let's give this another shot. I will boot up php artisan tinker. I will fetch our User. And now if I try to access that user's profile, I'm still going to get null. And that's because, well, there is no profile yet set up. Let's do it now. User::profile->create(), and maybe we'll just provide a website. Aha, but it does fail. Twitter handle does not have default value. OK, so this is something to think about.
Fixing Nullable Columns5:32
Twitter handle does not have default value. OK, so this is something to think about. If I go back to the structure here, you'll notice that we have a website and a Twitter handle, and neither of them can be null. But that doesn't make sense. If you have a profile, we're not going to demand that you give us a website or a Twitter handle. So I think we need to tweak this a little bit. I'm going to switch back to my migration, and I'm going to say both of these are nullable, or optional in other words.
I'm going to switch back to my migration, and I'm going to say both of these are nullable, or optional in other words. So let's exit out of here. I'm going to roll back my last migration and then rerun it. And now if I switch back to SQL Pro and give it a refresh, you'll see that these two records are now optional. All right, I'm ready to try it again, and I think we're all set. So I'm going to say User, then add a profile, and notice that Eloquent automatically adds the foreign key in the process. So if I now take a look here and give it a refresh, there we go.
the foreign key in the process. So if I now take a look here and give it a refresh, there we go. This means if I were to load the profile, there's our information. So I could say user, profile, website, and maybe spit that out in an anchor tag within the user's profile page or around to their avatar or something like that. What if I started with the profile though? All right, let's just grab the first one. And now I can say, all right, I have this profile. Give me the user who is associated with it, and that one works as well. Okay, finally, one last thing I want to show you.
Default Eager Loading6:52
Give me the User who is associated with it, and that one works as well. Okay, finally, one last thing I want to show you. There might be situations where you decide any time you fetch a User, you always want their profile available. Now when you can, I would say rely on eager loading to fetch this. And that way, if in certain areas you don't fetch the profile, you don't pay the cost of loading it. But otherwise, if you do need it for every single request, here's what you can do. On your User model, you can add a with property. Think of this as your way of saying which relationships should automatically be eager
On your User model, you can add a with property. Think of this as your way of saying which relationships should automatically be eager loaded no matter what. So here I could say the profile. All right, now if we give this one more run, if I fetch the User, notice that the profile is automatically eager loaded as part of that query. Now don't go too crazy with this, but it can often be useful, especially when you are converting something to JSON, maybe to pass it to your JavaScript. You could get your User, convert it to an array, and you instantly have access to all the data you require.
You could get your User, convert it to an array, and you instantly have access to all the data you require.
