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
Requires
- php: ^8.2
- illuminate/contracts: ^11.0||^12.0
- illuminate/database: ^11.0||^12.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^10.0.0||^9.0.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- spatie/laravel-ray: ^1.35
This package is auto-updated.
Last update: 2025-12-25 02:07:55 UTC
README
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.*(oralias.*) from the relation eager-loads and loads those relations on the pivot models. This avoidsRelationNotFoundExceptionon 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(extendsIlluminate\Database\Eloquent\Relations\BelongsToMany)LaravelPivotRelationsEagerLoading\Relations\MorphToMany(extendsIlluminate\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.