DEV Community

Cover image for Mastering Laravel Eloquent ORM - The Eloquent Journey (PART 2)
Samfield Hawb for XenoX

Posted on

Mastering Laravel Eloquent ORM - The Eloquent Journey (PART 2)

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

Alt Text

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')

Enter fullscreen mode Exit fullscreen mode

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);
  }
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

One To Many

Alt Text

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);
}
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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')
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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;
  }

Enter fullscreen mode Exit fullscreen mode

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'
  ]);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

Many To Many

Alt Text

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
Enter fullscreen mode Exit fullscreen mode

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')
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)