Laravel Eloquent: Eager Load Pivot Relations

In Laravel, we can create our custom pivot models. Our pivot model can also contain relations and we can access them in the pivot property. By using the package ajcastro/eager-load-pivot-relations, we can eager load the relations in our pivot model.

For example, in a procurement application, we have the following:

Tables:

items
- id
- name
units
- id
- name (pc, box, etc...)
plans (annual procurement plan)
- id
plan_item (pivot for plans and items)
- id
- plan_id
- item_id
- unit_id

Models:

class Unit extends \Eloquent {
protected $fillable = [];
}
class Item extends \Eloquent
{
protected $fillable = [];
    public function plans()
{
return $this->belongsToMany('Plan', 'plan_item');
}
}
class Plan extends \Eloquent
{
protected $fillable = [];
    public function items()
{
return $this->belongsToMany('Item', 'plan_item')
->using('PlanItem')
// make sure to include the necessary foreign key in this case the `unit_id`
->withPivot('unit_id', 'qty', 'price');
}
}

// Pivot model
class PlanItem extends \Illuminate\Database\Eloquent\Relations\Pivot
{
protected $table = 'plan_item';
    public function unit()
{
return $this->belongsTo('Unit');
}
}

We can access unit relation from the pivot model PlanItem by doing something like this:

$plan = Plan::with('items')->find($id);
foreach ($plan->items as $item) {
$unit = $item->pivot->unit;
echo $unit->name;
}

However, this will produce N+1 query because it accesses the unit model one-by-one. We can solve that by eager loading the relations in the pivot model.

So we need to install and use our package to do that:

composer require ajcastro/eager-load-pivot-relations

Then let’s use the AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait in the belongsToMany relation model which is the Item model.

use AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait;
class Item extends \Eloquent
{
// Use the trait here to override eloquent builder.
// It is used in this model because it is the relation model
// defined in Plan::items() relation.
use EagerLoadPivotTrait;
}

Voila! We can now eager load the pivot relations. Use keyword pivot in eager loading pivot models. So from the example above, we can do it by doing like this:

$plan = Plan::with('items.pivot.unit')->find($id);
// or
$plans = Plan::with('items.pivot.unit')->get();

Our json structure will look like this:

You can also add more relations in the pivot model if necessary and you can also chain more relations in eager loading.

return Plan::with([
'items.pivot.unit',
'items.pivot.unit.someRelation',
'items.pivot.anotherRelation',
// It is also possible to eager load nested pivot models
'items.pivot.unit.someBelongsToManyRelation.pivot.anotherRelationFromAnotherPivot',
])->get();

This way, we can easily work with any BelongsToMany relations which include more than one related model without changing our main belongsToMany data structure.

Related SO Post: https://stackoverflow.com/a/55807381/5191738

Happy Coding!!! :-)