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.
WOW, that lesson was amazing too, thanks
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
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.
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.
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.