Eloquent Polymorphic Relation Many to Many

Many to many relationships for polymorphic relations they share a single list of unique records, those unique records are shared amongst the other tables. If we have a post in the Videos table they are going to be sharing tags.

We are going to have a few tables in order to do this:

php artisan make:model Video -m
php artisan make:model Tag -m
php artisan make:model Taggable -m

Open up the video and tag migration to add this:

            $table->string('name');

Open up taggable to add the linking parts. You can remove the increment id and timestamps:

            $table->integer('tag_id');
            $table->integer('taggable_id');
            $table->string('taggable_type');

Now migrate this

php artisan migrate

Now we need to set the relationship starting in the Post model. Write this:

    public function tags() {
        return $this->morphToMany('App\Models\Tag', 'taggable');
    }

Add this exact piece of code to the Video model as well.

On your Tag model we need to define the Post and Video method:

    public function posts() {
        return $this->morphedByMany('App\Models\Post','taggable');
    }
    public function videos() {
        return $this->morphedByMany('App\Models\Video','taggable');
    }

Create two videos and two tags (try javascript and php). Then connect these in your taggables table.

In taggables table you need to choose a tag from the tags table. Then taggable ID refers to the ID from either videos or posts table. Write the taggable_type like this: App\Models\Video. This will put a tag on a post record and a video record.

Let’s pull out a post’s tag:

Route::get('/post/tag', function(){
    $post = Post::find(1);
    foreach($post->tags as $tag){
        echo $tag;
    }
});

Now let’s do the inverse and find the post from the tag. Look inside your taggable table to see you are referencing the correct model (post or video) or else you’ll get back nothing.

use App\Models\Tag;

Route::get('/tag/post', function(){
    $tag = Tag::find(2);
    foreach($tag->posts as $post){
        echo $post->title;
    }
});

Leave a Reply

Your email address will not be published.