1

Situation

I have the following models:

  • Post
  • Video
  • Tag

These are stored in the database tables:

  • posts (having id and name columns)
  • videos (having id and name columns)
  • tags (having id and name columns)

And also a table taggables with the columns:

  • tag_id (The ID of the Tag)
  • taggable_id (The ID of the Post or Video)
  • taggable_type (Either App\Post or App\Video)

Both Post and Video models have a morphToMany relationship to Tag, using:

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

And the Tag model has the inverse morphedByMany relationships set with:

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

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

(So far, this works and it is all exactly as described in the Laravel Docs.)

Now, in addition to this, I have a TagGroup model that has a One-to-Many relation with Tag, so multiple tags can belong to a tag group. (With hasMany('App\Tag') and belongsTo('App\TagGroup') using a tag_group_id column in the tags table.)

Question

How can I set-up a relationship between the TagGroup model and the Post and (seperately) Video models? (For example, to get all posts that have been tagged with tags of a certain group.)

I know there is hasManyThrough, but that doesn't seem to work with Many-to-Many Polymorphic relationships as the intermediate. Or am I doing something wrong?

There’s also defining custom intermediate tables with MorphPivot and ->using(), but the docs are very unclear about that.

Can this be done without any extra plugins/frameworks?

Philip
  • 2,888
  • 2
  • 24
  • 36
  • As there is no built-in for `hasManyThrough` of many-to-many relations, there is, as far as I am aware of, also no built-in for such polymorphic relations. You can clearly create some methods to load the models of tag groups, but you most likely won't profit from eager loading... – Namoshek Apr 11 '19 at 05:03

1 Answers1

0

Not sure if this is exactly what you need, but I have this setup

Campaigns --(morphedByMany)--> Articles --(HasMany)--> Tags

The pivot table (model_campaign) linking campaign and articles has the following structure:

model_id | model_type | campaign_id

I got the relationship method to work like this:

class Campaign extends Model
{
    public function tags(): HasManyThrough
    {
        return $this
            ->hasManyThrough(Tag::class, Article::class, 'model_campaign.campaign_id')
            ->join('model_campaign', function ($join) {
                $join
                    ->on('model_campaign.model_id', '=', 'articles.id')
                    ->where('model_campaign.model_type', Article::class);
            });
    }
}

I haven't tested it in detail yet, but on first glance this seems to be working fine

Gregory
  • 1,148
  • 1
  • 9
  • 24