abdelhamiderrahmouni/laravel-pivot-relations-eager-loading

A Laravel package that enables eager loading of relationships on pivot tables for BelongsToMany and MorphToMany relationships.

Fund package maintenance!
AbdelhamidErrahmouni

Installs: 2

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 1

pkg:composer/abdelhamiderrahmouni/laravel-pivot-relations-eager-loading

v1.0.0 2025-12-22 19:21 UTC

This package is auto-updated.

Last update: 2025-12-25 02:07:55 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

A Laravel package that enables eager loading of relationships on pivot tables for BelongsToMany and MorphToMany relationships.

Problem

Laravel doesn't natively support eager loading relationships defined on custom pivot models. When you try to eager load pivot relationships using with('roles.pivot.assignedBy'), you get:

Illuminate\Database\Eloquent\RelationNotFoundException: Call to undefined relationship [pivot] on model [App\Models\Role].

Solution

This package provides custom relationship classes that extend Laravel's BelongsToMany and MorphToMany relationships, adding support for eager loading pivot relationships natively using ->with('roles.pivot.createdBy') as well as via a withPivotRelations('createdBy') method.

This package supports the get(), lazy(), cursor(), and chunk() methods.

Installation

composer require abdelhamiderrahmouni/laravel-pivot-relations-eager-loading

Usage

1. Create a Custom Pivot Model

Make sure to define your relationships on your custom pivot model:

<?php

declare(strict_types=1);

namespace App\Models;

use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\Pivot;

class UserSkill extends Pivot
{
    protected $table = 'user_skill';

    public function scale(): BelongsTo
    {
        return $this->belongsTo(Scale::class);
    }
}

2. Add the Trait to Your Models

<?php

declare(strict_types=1);

namespace App\Models;

use LaravelPivotRelationsEagerLoading\Concerns\WithPivotRelationsLoading;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use WithPivotRelationsLoading;

    public function skills(): BelongsToMany
    {
        return $this->belongsToMany(Skill::class, 'user_skill')
            ->using(UserSkill::class)
            ->withTimestamps()
            ->withPivot(['scale_id']);
    }
}
$users = User::query()->with('skills.pivot.scale')->get();

foreach ($users as $user) {
    foreach ($user->skills as $skill) {
        // The scale relationship is already loaded - no N+1 queries!
        $scale = $skill->pivot->scale;
    }
}

If you prefer to always eager load a pivot relationship with your relationship definition, you can use the withPivotRelations() method:

<?php

declare(strict_types=1);

namespace App\Models;

use LaravelPivotRelationsEagerLoading\Concerns\WithPivotRelationsLoading;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use WithPivotRelationsLoading;

    public function skills(): BelongsToMany
    {
        return $this->belongsToMany(Skill::class, 'user_skill')
            ->using(UserSkill::class)
            ->withTimestamps()
            ->withPivot(['scale_id'])
            ->withPivotRelations('scale');
    }
}

3. Query with Eager Loading

$users = User::query()->with('skills')->get();

foreach ($users as $user) {
    foreach ($user->skills as $skill) {
        // The scale relationship is already loaded - no N+1 queries!
        $scale = $skill->pivot->scale;
    }
}

Polymorphic Relationships

The package also supports MorphToMany relationships:

<?php

declare(strict_types=1);

namespace App\Models;

use LaravelPivotRelationsEagerLoading\Concerns\WithPivotRelationsLoading;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use WithPivotRelationsLoading;

    public function tags(): MorphToMany
    {
        return $this->morphToMany(Tag::class, 'taggable')
            ->using(Taggable::class)
            ->withPivotRelations('creator');
    }
}

For inverse polymorphic relationships, use morphedByMany():

public function posts(): MorphToMany
{
    return $this->morphedByMany(Post::class, 'taggable')
        ->using(Taggable::class)
        ->withPivot('added_by')
        ->withPivotRelations('addedBy');
}

Notes:

  • The package automatically detects and strips pivot.* (or alias.*) from the relation eager-loads and loads those relations on the pivot models. This avoids RelationNotFoundException on the related model.
  • You can use withPivotRelations([...]) if you prefer an explicit API; both forms are supported and can be combined.

Available Classes

This package provides two classes that simply extend Laravel's native relations:

  • LaravelPivotRelationsEagerLoading\Relations\BelongsToMany (extends Illuminate\Database\Eloquent\Relations\BelongsToMany)
  • LaravelPivotRelationsEagerLoading\Relations\MorphToMany (extends Illuminate\Database\Eloquent\Relations\MorphToMany)

Using them is optional; the trait works fine with the native Illuminate types shown in the examples above.

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Credits

License

The MIT License (MIT). Please see License File for more information.