Courses

Laravel 12 Eloquent: Expert Level

Advanced Polymorphic: Many-to-Many

Summary of this lesson:
- Implementing complex polymorphic relationships
- Setting up pivot tables for polymorphic relations
- Managing many-to-many polymorphic queries
- Understanding relationship directionality

Now, let's look at the polymorphic relation, which is a bit more complex: a many-to-many polymorphic relation.

Suppose we look at the photos table from a previous lesson example. What if you want the same photo to belong to both a task and a user, or maybe to more models like the posts? This sounds like a many-to-many relationship, doesn't it?


Structure

So, what do we do for the polymorphic photos table? We remove the morph fields and create a separate pivot table called photoables.

Schema::create('photos', function (Blueprint $table) {
$table->id();
$table->string('filename');
$table->morphs('photoable');
$table->timestamps();
});

The photoables pivot table will have a foreign key column to the photos table and the same two morph columns ID and type.

Schema::create('photoables', function (Blueprint $table) {
$table->foreignId('photo_id')->constrained();
$table->morphs('photoable');
});

Then, in the Photo Model, we don't need the photoable morph relation. Instead, we must define each Model's morphedByMany relation.

app/Models/Photo.php:

use Illuminate\Database\Eloquent\Relations\MorphToMany;
 
class Photo extends Model
{
public function photoable(): MorphTo
{
return $this->morphTo();
}
 
public function users(): MorphToMany
{
return $this->morphedByMany(User::class, 'photoable');
}
 
public function tasks(): MorphToMany
{
return $this->morphedByMany(Task::class, 'photoable');
}
}

And, instead of the morphMany relation, we must use morphToMany in other Models.

app/Models/Task.php:

use Illuminate\Database\Eloquent\Relations\MorphToMany;
 
class Task extends Model
{
public function photos(): MorphMany
{
return $this->morphMany(Photo::class, 'photoable');
}
 
public function photos(): MorphToMany
{
return $this->morphToMany(Photo::class, 'photoable');
}
}

app/Models/User.php:

use Illuminate\Database\Eloquent\Relations\MorphToMany;
 
class User extends Authenticatable
{
// ...
 
public function photos(): MorphMany
{
return $this->morphMany(Photo::class, 'photoable');
}
 
public function photos(): MorphToMany
{
return $this->morphToMany(Photo::class, 'photoable');
}
}

In a typical many-to-many relationship, it doesn't matter who the parent or the child is. They both belong to many. In this case, the relationship matters.

I kept everything the same when showing the result, only re-seeding the database.

This is a more complex polymorphic relation, but still with the same idea that you have two morph columns that define the polymorphism.


Code for this lesson can be found on GitHub.

Previous: Polymorphic Relations: Explained with Example
avatar
Francisco Ferreira Roque Júnior

WOW, that lesson was amazing too, thanks

avatar
You can use Markdown
avatar

Hi Can you please share the seeders, factories classes for this entier chapter (Advanced Eloquent Relations) ? I think for beginners it is bit difficult to stay on the tutorial. becasuse they have to spend some additional time on searching how to add seeders to polymorphic relations. if you add those , they will learn how to create seeders,factories for these kind of relationships. Thank you

avatar

Hi! The idea here was to showcase how methods are used, rather how factories work. So that is why there is no repository attached to this (and factories/seeders). Sorry.

avatar

Hi how can we get the idea if we can't run and test this in a locally set up environment ? i don't think you encourge people to just read and understand the concept. can you please explain how to understand then ? i think when we buy a course we expect the course is fully ready with all the meterials it needs. no need to teach how factories works. at least if you can provide those code examples in repository, that would be really helpful.

avatar

To be honest, that is part of learning. Getting your hands dirty and trying to figure it out :)

But your comment is noted, we are trying to include repositories as much as possible, and probably missed this one. After Laravel 12 update, we should include it.

avatar
You can use Markdown
avatar
You can use Markdown