Laravel Eloquent Database Relationships

Eloquent Relationships Laravel: Database tables are related to one another. Eloquent manages and work with easy relationships.

It supports some different types of relationship, which are as follows:

  • One to one
  • One to many
  • Many to many
  • Has one through
  • Has many through
  • One to one (polymorphic)
  • One to many (polymorphic)

Defining Eloquent Relationships

Eloquent relationships are specified as a method on our Eloquent model classes.

Eloquent models relationships also serve as powerful query builders, defining relationships as a method, provides powerful method chaining and query capabilities.

Example:

$user->posts()->where(‘active’, 10)->get();

One to One

A one to one relationships is an essential relation. For defining these relationships, we are going to place a phone method on the owner model.

The phone method will call the hasOne method and return its result:

class Phone extends Owner
{
public function phone()  
{  
return $this--->hasOne('App\Phone');
}
}

The hasOne method is the name which is passed as the first argument, it is a related model. The relationship is specified; we retrieve the related record by using Eloquent`s dynamic properties.

Dynamic properties allow us to access relationship methods as if they were properties defined on the model:

$phone = User::find(1)->phone;

Eloquent consider as the foreign key of the relationship, which is based on the model name.

In that case, the Phone model is automatically assumed to have a user_id foreign key.

We pass a second argument to the hasOne method.

return $this->hasOne(‘App\Phone’, ‘foreign_key’);

The foreign key should have a value matching the id column of the parent.

Eloquent will consider the value of the user`s id column in the user_id column.

To use the relationship of a value other than id, we pass the third argument to the hasOne method defining our custom key.  

return $this->hasOne(‘App\Phone’, ‘foreign_key’, ‘local_key’);

The Inverse of the Relationship

We can easily access the Phone model from our Owner.

To define a relationship on the Phone model that will let us access the Owner.

 We can define the inverse of a hasOne relationship by using the belongsTo method:

class Phone extends Owner
{
/**
* Get the owner that owns the phone.
*/
public function owner()
{
return $this->belongsTo('App\Owner');
}
}

In the above example, Eloquent will try to match the user_id from the Phone model to an id on the Owner model.

Eloquent consider as the default foreign key name by the name of the relationship method and the method name with _id.

The foreign key on the Phone model is not user_id, we pass a custom key as the second argument to the belongsTo method:

For Example:

/**
* Get the user that owns the phone.
*/
public function owner()
{
return $this->belongsTo('App\User', 'foreign_key');
}
one to one

Our parent model do not use id (as primary key), the third argument to the belongsTo method by defining our parent table as a custom key: 

public function owner()
{
return $this->belongsTo('App\User', 'foreign_key', 'other_key');
} 

One To Many

One To Many

A one-to-many relationship defines relationships where a single model owns any amount of the other models. One-to-many relationships are defined by placing our Eloquent model

hasMany('App\Comment');
}
} 

Eloquent will automatically decide the proper foreign key column on the Comment model.

Eloquent will assume the foreign key on the Comment model as post_id.

The relationship has been specified; we can enter the collection of the comments by entering the comments correctly.  

Eloquent provides “dynamic properties”, we can enter relationship methods as they defined as the properties on the model

$comments = App\Post::find(1)->comments;
foreach ($comments as $comment)
{
//statement
} 

We can add constraints to the comments by easily call the comments method and continuing the chain conditions onto the query.

$comment = App\Post::find(1)->comments()->where('title', 'foo')->first();

The hasOne method, we also override the foreign and local keys by passing an additional arguments to the hasMany method.

return $this->hasMany('App\Comment', 'foreign_key');
return $this->hasMany('App\Comment', 'foreign_key', 'local_key'); 

Many to Many

Many to Many

Many-to-many relations are complicated than hasOne and hasMany relationships.

For example:-

Many users have the role of “Admin”. To specify the many-to-many relationship, the three database tables which are as follows: users, roles, and role_user.

The role_user table is derived from the alphabetical order of the related model names, and it contains the user_id and role_id columns.

Many-to-many relationships are specified by writing a method which will return the result of the belongsToMany method.

Let`s define the roles method on our User model:

belongsToMany('App\Role');
}

The relationship is specified, we access the user`s roles by using the roles dynamic property:

$user = App\User::find(1);
foreach ($user->roles as $role)
{
//
} 

We call the roles method to continue query constraints onto the relationship

$roles = App\User::find(1)->roles()->orderBy('name')->get();

The table name of the relationship joins table, and Eloquent will join the two related model names in the alphabetical order.

 We are free to override this convention as a second argument to the belongsToMany method:

return $this->belongsToMany(‘App\Role’ , ‘role_user’);

We also customize the column names of the keys on the table by passing additional arguments to the belongsToMany method.

The foreign key name of the model is the third argument, which is defining the relationship. The fourth argument joins the foreign key name of the model.

return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');

Defining Custom Intermediate Table Models

To define a custom model for representing the intermediate table of our relationship, we call the using method when defining the relationship.

Custom many-to-many pivot model extends the Illuminate\Database\Eloquent\Relations\Pivot class, for custom polymorphic many-to-many pivot models extend the Illuminate\Database\Eloquent\Relations\MorphPivot class. 

Example: - we define a Role that uses a custom RoleUser pivot model:

belongsToMany('App\User')->using('App\RoleUser');
}
} 

To define the RoleUser model, we extend the Pivot class:

We combine using with Pivot to retrieve columns from the intermediate table.

For example:-

 We retrieve the created_by and update_by columns by the RoleUser pivot table by passing the column names to the withPivot method:

belongsToMany('App\User')
->using('App\RoleUser')
->withPivot([
'created_by',
'updated_by'
]);
}
} 

Note: Pivot models do not use the SoftDeletes. If we need to delete pivot records consider as converting our pivot model to an actual Eloquent model.

Has One Through

The “has-one-through” relationship model links across a single intermediate relation.

For Example:- 

Each supplier has one user, and each user is associated with one user record, then the supplier model access the user`s history through the user.

The database tables necessary, which defines this relationship:

users
id - integer
supplier_id - integer
suppliers
id - integer
history
id - integer
user_id – integer 

The history table does not contain supplier_id columns; the hasOneThrough relation provides access to the owner`s history to the supplier model.

Let`s define it on the Supplier model:

class Supplier extends Model
{
public function ownerHistory()
{
return $this--->hasOneThrough('App\History', 'App\User');
}
} 

The first argument that is passed to the hasOneThrough method is the name of the final model that we will access, and the second argument is the name of the intermediate model.

Has Many Through

Has Many Through

The “has-many-through” provides a simple shortcut for accessing distant relations with an intermediate relation.

Let`s look at the tables requirement for defining relationship:

countries
id - integer
name - string
users
id - integer
country_id - integer
name - string
posts
id - integer
user_id - integer
title - string 

The posts do not contain a country_id column; the hasManyThrough relation provides access to a country`s posts with $country->posts.

Eloquent go through the country_id to the intermediate of the users table.

After finding the matching user IDs, it will used to query the posts table.

Let`s define it on the Country model:

The first argument which is passed to the hasManyThrough method is the name of the final model for access, while the second argument is the name of the intermediate model.

Polymorphic Relationships

A polymorphic relationship allows the target model that belongs to more than one type of model by using a single association.

One to One (Polymorphic)

Table structure

A one-to-one polymorphic relation is similar to a simple one-to-one relation; the target model belongs to more than one type of model on a single association.

posts
id - integer
name - string
users
id - integer
name - string
images
id - integer
url - string
imageable_id - integer
imageable_type - string 

The imageable_id column will contain the ID value of the user; the imageable_type column will contain the class name of the parent model. The imagebale_type column is used by Eloquent to determine the “type” of parent model for return when accessing the imageable relation.

Model Structure

The model definitions needed to build the relationship:

morphTo();
}
}
class Post extends Model
{
public function image()
{
return $this->morphOne('App\Image', 'imageable');
}
}
class User extends Model
{
public function image()
{
return $this->morphOne('App\Image', 'imageable');
}
} 

Retrieving the Relationship

Once the database table and models are defined, we can access the relationships with the models.

For example: - for retrieve the image for a post, we use the image dynamic property:

$post = App\Post::find(1);
$image = $post->image; 

We also retrieve the parent from the polymorphic model by easily accessing the name of the method that performs the call to morphTo.

The imageable method on the Image model will access that method as a dynamic property:

$image = App\Image::find(1);
$imageable = $image->imageable; 

The imageable relation on the Image model will return Post or User instance, it depends on which type of model owns the image. 

One to Many (Polymorphic)

A one-to-many polymorphic relation is the same as a simple one-to-many relation.

In this, the target model belongs to more than one type of model on a single association.

By using polymorphic relationships, we use a single comments table for both.

Table Structure

posts
id - integer
title - string
body - text
videos
id - integer
title - string
url - string
comments
id - integer
body - text
commentable_id - integer
commentable_type - string 

Model Structure

namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
    public function commentable()
    {
        return $this--->morphTo();
    }
}
class Post extends Model
{
    public function comments()
    {
        return $this->morphMany('App\Comment', 'commentable');
    }
}
class Video extends Model
{
    public function comments()
    {
        return $this->morphMany('App\Comment', 'commentable');
    }
} 

Retrieving the Relationship

Once the database table and models are defined, we access the relationships with our models.

$post = App\Post::find(1);
foreach ($post->comments as $comment) {
//
} 

We can also retrieve the owner from the polymorphic model by allowing the name of the method, which performs the call to morphTo.

The commentable method on the Comment model will access that method as a dynamic property:

$comment = App\Comment::find(1);
$commentable = $comment->commentable; 

The comment-able relation of the Comment model returns a Post or Video depends on the type of model that owns the comment.