Understanding Eloquent Relationships
Welcome once again. In this post I will be diving into Laravel Eloquent Relationships, if you missed the previous article, the link can be found at the bottom of this post.
As we all know that databases tables are often related to one another, let take for instance in a blogging platform, the users' table will be related to the posts, comments and replies tables, the comments table will be rated to the posts table, replies related to the comments table. Eloquent comes packed with the underlying structure to enable us to manage the relations between our database tables, thereby making queries between our tables simple and flexible.
Eloquent supports many types of relationships, which includes:
- One To One
- One To Many
- Many To Many
- Has One Through
- Has Many Through
- One To One (Polymorphic)
- One To Many (Polymorphic)
- Many To Many (Polymorphic)
Eloquent relationships are defined as methods in our model classes. The method names are decided by you, but make sure to give a name that can explain your relationship.
One To One
The One to One relationship is a type of relationship whereby a model is related to another model by a single data. let's say we have Profile Model that will hold the profile information about a user in our database. We will expect our users to have only one profile and a profile should belong to a single user. This kind of relationship is a one to one relationship
, and to achieve this relationship, we will expect our profiles table to have a connection to our users' table using the foreign key
constraint by adding a column to create this connection.
Sample Profile table
id | user_id | address |
---|---|---|
1 | 1 | 20 Markson St. |
$table->unsignedInteger('user_id')
$table->foriegnKey('user_id')->references('id')->on('users')->onDelete('cascade')
adding the above to our profile table migration, laravel now uses this to create our relationship between our models.
we can now define our relationship between our models. since the foreign key is on the Profile model, we can now use the eloquent hasOne()
method to let eloquent bind our User model to the profile model that a user in our users' table has a profile by
/**
*Returns an Eloquent relationship
**/
public function profile()
{
return $this->hasOne(Profile::class);
}
Here eloquent expect that we have a user_id
column existing in the profile table, but in suituation you have a different column name for our foriegn key representing our users table,
id | custom_user_id |
address |
---|---|---|
1 | 1 | 20 Markson St. |
we can tell Eloquent by providing the second parameter to our hasOne()
method
return $this->hasOne(Profile::class, 'custom_user_id');
Eloquent also expect that on our user table the primary key is id
, but in cases we have a different primary key other that id
,
Sample User Table
user_id |
name |
---|---|
1 | Samfield Hawb |
we can pass the third parameter
return $this->hasOne(Profile::class, 'custom_user_id','user_id');
with this we have a relationship between the User model and Profile model. Now let create a reverse of the relationship using the Eloquent belongsTo()
method. we will define the reverse now in our Profile Model class;
/**
*Returns an Eloquent Relationship
*/
public function user()
{
return $this->belongsTo(User::class);
}
Also here eloquent will try to match user_id
on the profiles table with an id on the users' table, and in situation you have a different column name for our foreign key on our profile table,
id | custom_user_id |
address |
---|---|---|
1 | 1 | 20 Markson St. |
we can tell Eloquent by providing the second parameter to our belongsTo()
method
return $this->belongsTo(User::class, 'custom_user_id');
Eloquent also expect that on our user table the primary key is id
, but in cases we have a different primary key other than id
,
user_id |
name |
---|---|
1 | Samfield Hawb |
we can pass a third parameter
return $this->belongsTo(User::class, 'custom_user_id','user_id');
With this set up, we can now use this relationship to perform a query between this two models
$user = \App\User::find(1);
$user->profile;//the profile can now be gotten by
//likewise in the opposite direction
$profile = \App\Profile::find(1);
$profile->user; //gets the user that owns the profile
$profile->user->name; //returns the name of the user
One To Many
This is a relationship whereby a model is related to another model by many records, for instance, A user in a blogging application can have many blog posts, comments, as well as replies, likewise a comment, post, or replies can belong to a user in the users' table. Eloquent provides us with hasMany()
method to create this kind of relationship between our models. So let's define this kind of relationship between a User model and a Post Model, in a User model we add;
Sample Posts Table
id | title | content | user_id |
---|---|---|---|
1 | Mastering laravel Eloquent ORM | content | 1 |
public function posts()
{
return $this->hasMany(Post::class);
}
here Eloquent expect a foriegn key column user_id
in our posts table, but i situation we have a different name,
id | title | content | custom_user_id |
---|---|---|---|
1 | Mastering laravel Eloquent ORM | content | 1 |
a second parameter can be pass to the hasMany()
method,
return $this->hasMany(Post::class,'custom_user_id');
likewise if we have a diffent primary key for the parent model User
from the id
column which Eloquent expect, we can also pass in a third parameter to the hasMany()
method
return $this->hasMany(Post::class,'custom_user_id','user_id')
we have created a relationship for our User model to the Post model. Now let create the reverse of the relationship, Post model to the User model, this can be achieve also with the Eloquent belongsTo()
method ;
public function user()
{
return $this->belongsTo(User::class);
}
here eloquent will still try to match user_id
on the posts table with an id on the users' table, in situation you have a different column name for our foreign key on our posts table, we can tell Eloquent by providing the second parameter to our belongsTo()
method
return $this->belongsTo(User::class, 'custom_user_id');
Eloquent still expect that on our user table the primary key is id
, but in cases we had a define primary key name other that id
, we can pass a third paramater to the belongsTo()
method;
return $this->belongsTo(User::class, 'custom_user_id','user_id');
with this set up now, we can now make use of eloquent to query data between the models. Lets get all the posts made by a user with id
of 1 from the database;
$user = \App\User::findOrFail(1); //we retrieve the user
//lets print out the title for all the post made
foreach ($user->posts as $post)
{
echo $post->title;
}
we have seen how easy eloquent has made retrieving the post here, with this relationship, we can create a post that binds to a particular user;
$user = \App\User::find(1);
$user->posts()->create([
//we supply all keys representing the column name and the value in
// 'key' => 'value'
]);
with the above code snippet, Eloquent automatically extracts the user_id
from the $user object to create a blog post. likewise, using the createMany()
method on the relationship can allow you to store many blog posts at a time to a user. We will come to this later.
Let's say we want to get the name of a user that owns a post, we can easily achieve this too from the relationship;
$post = \App\Post::find(1);
echo $post->user->name;
Many To Many
At times when building a web application, we want to related values in a table with other values in another, for instance, if we want to introduce a role system into our blog, a user can have multiple roles, also a role can belong to multiple users. Laravel Eloquent provides us with the many to many relationships, to achieve this, we will need to create another table using the laravel migration that will store up this relationship, create_role_user_table
,
$ php artisan make:migration create_role_user_table --table=role_user
in the up method of our generated migration file, we can add
$table->unsignedInteger('user_id');
$table->unsignedInteger('role_id');
//foriegn key
$table->foriegnKey('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foriegnKey('role_id')->references('id')->on('roles')->onDelete('cascade')
here, eloquent uses these two columns to fetch our data when needed.
Sample role_user table with data
user_id | role_id |
---|---|
1 | 1 |
1 | 4 |
1 | 3 |
2 | 4 |
We can see how this user with id 1
has 3 roles with ids 1, 4, 3
.
Now on our User model we can now define our relationship using the belongsToMany()
method provided for use by Eloquent Model class
public function roles()
{
return $this->belongsToMany(Role::class);
}
Eloquent seeing this relationship will try to determine the table for we created above by joining the two related models in alphabetical other separated by an underscore role_user
. In situations we declared a name other than this, we can pass a second parameter to our belongsToMany
method to tell Eloquent where to find the relationship.
return $this->belongsToMany(Role::class,'custom_role_user');
Also, if we had custom keys for the table other than the expected value, we can pass the third parameter as a foreign key for the model we are defining the relationship and a fourth parameter for the foreign key to the relating model
return $this->belongsToMany(Role::class,'custom_role_user','custom_user_id','custom_role_id');
we can then define the inverse of the relationship on our role model too, which will enable use query all users that is tied to a particular role.
public function users()
{
return $this->belongsToMany(User::class);
}
With the relationships define, we can then fetch our data from the database using eloquent ORM;
$user = \App\User::find(1);
foreach ($user->roles as $role)
{
echo $role->name
}
$role = \App\Role::find(1);
foreach($role->users as $user)
{
echo $user->name;
}
we can assign a role to a user using the relationship and the attach()
method from the Model class
$user = \App\User::find(1);
$user->roles()->attach(1); //assigned role with id 1 to the user
$user->roles()->attach([2,3,4]); //assigned roles with ids 2,3,4 to the user
also roles can be remove from users using the eloquent detach()
method;
$user = \App\User::find(1);
$user->roles()->detach(1); //remove role with id 1 to the user
$user->roles()->detach([2,3,4]); //remove roles with ids 2,3,4 to the user
Conclusion
So far we have covered the One to One
, One To Many
, and Many To Many
relationship types made available by eloquent, in the next article we will look into the remaining types. Thank you for following this far.
Links to Previous articles:
Top comments (0)