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?
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.