Paulund
2018-10-21 #laravel

Laravel Eager Load Constraints

In a recent project I had to add a constraint to a relationship to make sure it only loads one of a relationship data.

To learn more about Laravel relationships you can read the documentation here

In the documentation it shows how you will use a one-to-many relationship by defining a $this->hasMany() relationship.

Therefore if you have an application with a user where you keep track of all their activities you may have a model like this.

class User extends Authenticatable
{
    public function activities()
    {
        return $this->hasMany('App\Activities');
    }
}

Now when you load the user and want to bring back all of their activities you can eager load the activities by using the following code.

$user = User::with('activities')->find(1);

This will return the user object with a relationship node of all the activities connected to this user.

So what it you want to show the last activity that user performed, maybe you have a dashboard that shows what they last did. You will need to grab the last activity on the user relationship.

$user = User::with('activities')->find(1);
$lastActivity = $user->activities->sortByDesc('created_at')->take(1);

The problem with this code is that it's not very re-useable so if you want to show the last activity in multiple places you will need to copy this in multiple places. For this reason many people will create a new method on the user object.

Because of the one-to-many relationship in the database you may see a solution like this.

class User extends Authenticatable
{
    public function activities()
    {
        return $this->hasMany('App\Activities');
    }

    public function lastActivitiy()
    {
        return $this->hasMany('App\Activities')->orderBy('created_at', 'DESC')->take(1);
    }
}

Now we can get this data by using the following code.

$user = User::with('lastActivitiy')->find(1);
$lastActivity = $user->lastActivitiy;

Because this is still on a one-to-many relationship people think you have to use the hasMany method but you can use the hasOne method to only return one element, changing your lastActivitiy method to this.

class User extends Authenticatable
{
    public function activities()
    {
        return $this->hasMany('App\Activities');
    }

    public function lastActivitiy()
    {
        return $this->hasOne('App\Activities')->orderBy('created_at', 'DESC');
    }
}

This means we no longer have to query all the activities just to bring back the latest activity we just query for the one.