“Laravel eloquent one to one relationship with example”: A one-to-one relationship is a very basic, fundamental Laravel eloquent relationship.
Following our complete guide to Laravel relationships, it simply relates one entity to another.
For instance, in our voting application, a User is associated with one Vote.
If we were to describe this relationship, we could say:
“Each user has one vote”.
Before we dive into the article, subscribe to get access to our free laravel tips that will improve your productivity.
Defining a one-to-one relationship
In order to define this relationship, we call the hasOne
method on the entity that owns the relationship.
Here’s a code snippet defining the relationship.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get's this user's vote
*/
public function vote()
{
return $this->hasOne(App\Models\Vote::class);
}
}
What happens here is, we pass the name of the related model (the ::class
property returns the full name of the class).
Once we’ve defined this relationship, we can always easily get the vote associated with any user in our database using Eloquent’s dynamic properties.
Querying one-to-one Relationship
Eloquent’s dynamic properties allow us to query relationships and get the values as if they are properties defined on the object.
We could do something like this:
<?php
namespace App\Http\Controllers;
use App\Models\User;
class RandomController extends Controller {
public function getUserVote(){
$user = User::find(1); // Get a User Instance
$vote = $user->vote; // Get the Vote that this User has
// Do whatever with it
return response(['vote' => $vote], 200);
}
}
As you can see we can get this user’s vote as if it were a property of this user object.
What actually happens under the hood by default is:
When we access the vote property, Eloquent makes a database query to the votes table using the foreign key that points to the current user’s primary key on the user’s table.
That’s why it’s called a dynamic property; because its values are not predefined, rather it’s gotten on the fly by a database call.
Laravel Naming
Now you may ask?
How does Eloquent know the correct name of the primary/local key on the user’s table?
And how does it know where to get that key (the foreign key) on the votes table?
Well, let’s answer these questions.
First of all, the primary key of Laravel tables is called ID
. It is possible to change this in the Model class.
Laravel uses this primary key as the local key.
Eloquent also has a convention for naming the foreign key on the votes table: we always append _id
to the name of the model that owns the relationship.
In our example, the votes table would have a column called user_id
. This user_id
would always point to the ID
of the user that owns that vote.
You may also think at this point:
Laravel Custom Keys
This is fun and all, but what if I don’t want to use this convention? Or what if I have a different column I want to use as the foreign key or local key?
Eloquent provides a convention for this too, and it’s like this:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get's this user's vote
*/
public function vote()
{
return $this->hasOne(App\Models\Vote::class, 'foreign_key', 'local_key');
}
}
Looking at the snippet, we see that the hasOne
method can accept up to three parameters.
The first parameter is required, and it provides the full name of the Eloquent model that forms the relationship.
The second argument is optional, and it specifies the name of the foreign key.
The foreign key is the column that Eloquent checks for when we call the dynamic property.
What this means is if we actually wrote this method, Eloquent would look for the vote by checking for the column foreign_key
on the votes, table to see if the value is the same on the local_key
column of the user’s table.
Did you get it? Please read it again if you didn’t.
The third argument is optional, and it defines the local key of the entity that has the relationship.
So in our snippet, if we didn’t put the third argument to be local_key
, whenever Eloquent is checking for votes, it would check the default ID
column.
Note: If you want to omit the second argument, but provide a value for the third one, simply put null as the second argument, meaning your code will look like this:
return $this->hasOne(App\Models\Vote::class, null, 'local_key);
Take a break and subscribe to get access to our free laravel tips that will improve your productivity.
Defining the Inverse of One to One Relationships
In Laravel “one to one relationship” with an example, defining an inverse relationship is also made very easy and straightforward.
Well, it’s fun to find the vote of each user.
But what if we had a vote and we wanted to find the user that vote belongs to?
Eloquent provides a convenient means of defining the inverse of One-to-One relationships.
If we want to define the relationship that states: “Each vote belongs to a user”, we use the belongsTo
method like this:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Vote extends Model {
/**
* Get's this vote's owner
*/
public function user() {
return $this->belongsTo(App\Models\User::class);
}
}
Once this is defined, we can get our user just like we showed earlier by using the dynamic property.
We would be able to call the user property on a vote instance as it existed.
In a similar fashion, Eloquent would run a database query behind the scenes that checks for the user_id
column on the votes table and see if it matches a record with the same ID
on the user’s table.
If you don’t want this convention, you can also define different foreign and local keys like we did above.
So this snippet would look like this:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Vote extends Model {
/**
* Get's this vote's user
*/
public function user() {
return $this->belongsTo(App\Models\User::class, 'foreign_key', 'local_key');
}
}
Just as explained earlier, with this we can set the foreign key (on the user’s table ) or the local key (on the vote’s table) to a different column by using the optional second and third parameters of the belongsTo
method.
Retrieving a One to One Relationship
Once we’ve defined our relationship, it’s easy to get the values and start having fun with it.
To get the value of the relationship, we simply use the dynamic property to get it.
So, if we wanted to get our vote given a user, we would do:
<?php
use App\Models\User;
class RandomClass {
public function randomFunction(){
$user = User::find(1); // Gets a User Instance
$vote = $user->vote; // Gets the User's Vote
// Do whatever with it
print_r($vote);
}
}
In addition to using dynamic properties to get the values of relationships, you can go further down the relationship to get the relationship of your relationship.
So if we wanted to get the party our user voted for, and we already defined Laravel One-to-One relationships between Vote
and PoliticalParty
models, we can do this:
<?php
use App\Models\User;
class RandomClass {
public function randomFunction(){
$user = User::find(1); // Gets a User Instance
$vote = $user->vote->politicalParty; // Gets the party the user voted for
// Do whatever with it
print_r($vote);
}
}
You can get an in-depth article on “Laravel one to many relationships with example” that explain everything from creating the relationship, the inverse method of creating it, and how to retrieve the data.
Getting Started with Laravel One to One CRUD Example (Word Matching Game)
In order to better illustrate one-to-one relationships, we’ve prepared a repository you can clone that shows one-to-one relationships in action.
In this repository, we build a simple game where you pick the best word or words from the select box on the right that matches the word on the left.
Feel free to clone the repository so we can get started.
Before we dive into the article, subscribe to get access to our free laravel tips that will improve your productivity.
In order to run the application, you’d have install composer dependencies with:
composer install
Then you’d have to run the migrations (after creating a database and setting credentials in your .env
file of course:
php artisan migrate
Finally, we’d have to seed the database:
php artisan db:seed
The application stores two entities, Word and Match and they have a One to One relationship.
Every word has a match, and every match belongs to a word.
We define this relationship in app/Models/Word.php
and app/Models/Match.php
respectively:
<?php
// app/Models/Word.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Word extends Model
{
use HasFactory;
// Define the One to One Relationship
public function match() {
return $this->hasOne(Match::class);
}
}
<?php
// app/Models/Word.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Match extends Model
{
use HasFactory;
// Define the inverse of the relationship
public function word()
{
return $this->belongsTo(Word::class);
}
}
Finally, we use the relationship in the controller that the homepage’s form submits to, we use the inverse relationship to loop through the submitted values and increment the score (we could have used the default relationship too).
<?php
namespace App\Http\Controllers;
use App\Models\Match;
use App\Models\Word;
use Illuminate\Http\Request;
class WordMatcher extends Controller
{
public function submit(Request $request)
{
$matches = $request->input('match');
// Gets all words as a collection in the same order they are shown on the page
$words = Word::orderBy('value', 'asc')->get();
$total = $words->count();
$score = 0;
foreach ($matches as $key => $match) {
// Loop through the submitted words and use the inverse relationship to check if they are related.
if (Match::find($match)->word->id === $words[$key]->id)
$score += 1;
// The check could also be achieved by using the actual One to One relationship like this:
// if($words[$key]->match->id == $match)
// $score += 1;
/******************************
*
* N.B
*
* Using strict equality (===) in the commented if statemen with the actual relationship
* won't work because $match is a string while -> id returns an integer,
* and the types are not the same
*
*****************************/
}
$percent = floor(($score / $total) * 100);
session()->flash("score_status", "success");
session()->flash("score_status_title", "Here's your Score");
session()->flash('score_status_message', "You got $percent% and matched $score out of $total words correctly.");
return back();
}
}
The rest of the code in the repository are frontend code, and the code to render the words and matches on the frontend.
What’s Next?
You can get an in-depth article on “Laravel one to many relationships with example” that explain everything from creating the relationship, the inverse method of creating it, and how to retrieve the data.
Conclusion
In this article, we had an in-depth look at Laravel’s “One to One relationships”, as well as an application implementing the relationship to solve a problem.
One to One relationships are basic and help in writing applications in a more fluent way.
Feel free to check out our other articles where we similarly go in-depth to explain other Laravel relationships.
Feel free to let us know if you have any questions and we’d love to help.