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
- nameunits
- id
- name (pc, box, etc...)plans (annual procurement plan)
- idplan_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
If you find this post helpful to you, you might want to buy me just a little coffee. Thanks! 😉
Happy Coding!!! 😊😊