Inverse or Inverted MANY to Many Relationships in Laravel

Many-to-many relationships are a type of relationship available in relational databases where multiple records from one table are related to multiple records from another table; for example, if we have a Post and Tags relationship, where a Post can have many Tags and a Tag can be assigned to multiple Posts. This means that a record can be associated with many records; to save this type of relationship, a pivot table is used that stores at least the PKs of both entities; so, in this type of relationship, we can obtain the tags of a post, which would be the direct relationship, or we can obtain the posts of a tag, which would be the inverse relationship.

Many-to-many relationships in Laravel

In this post, we are going to learn how we can work with inverse Many-to-Many relationships in Laravel.

Working with the many-to-many direct relationship

Before that, let's see how the direct connection is, in this example I have a normal relationship between Posts and Tags or labels, where a Post has multiple labels and a label can be assigned to one or many Posts, therefore it is a many-to-many relationship; for this, we have a pivot table called taggable in which we store these values: it has the following structure:

  • The tag_id column stores the identifiers of the Tag table
  • The taggable_id column stores the identifiers of the Post table

If we are going to maintain a relationship in which a label BELONGS to a Post, we have:

class Post extends Model
{
    protected $fillable = ...
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }

For tags, which is the inverse relationship (if you want to get the posts of a tag):To get the tags of a post:

class Tag extends Model
{
    protected $fillable = ...
    public function post()
    {
        return $this->hasMany(Post::class);
    }
}

To get the tags of a post:

$posts = Post->with('tags')->get();

Inverse relationship

The problem comes when you want to obtain the relations in an inverse way, that is, given a label, you want to obtain all the Posts that belong to that label; for that, from the label, we have to create the direct relationship, since with the hasMany we can NOT do this operation; so:

 public function myPosts()
    {
        return $this->belongsToMany(Post::class,'taggables','tag_id','taggable_id');
    }

Remaining as:

class Tag extends Model
{
    protected $fillable = ['title', 'url_clean'];
    public function post()
    {
        return $this->hasMany(Post::class);
    }
    public function myPosts()
    {
        return $this->belongsToMany(Post::class,'taggables','tag_id','taggable_id');
    }
}

And with this we can already obtain the direct relationship between Tags and Posts; so:

$posts = $tag::myPost()->get();

In my case, I have one more relationship, which is that of courses, in which a post belongs to a course, so:

    $courses_tags = Tag::whereHas('myPost', function ($query) {
                return $query->where('type', 'courses');
            })->get();

And the relationship or model for our course is:

class Course extends Model
{
    protected $fillable = ['name', 'description', 'image', 'post_id'];
    public function post()
    {
        return $this->belongsTo(Post::class);
    }
}
class Post extends Model
{
    protected $fillable = ['title', 'url_clean', 'content', 'category_id', 'posted', 'description', 'final_content', 'aux_content', 'web_content', 'image', 'path', 'date', 'type'];
    public function category()
    {
        return $this->belongsTo(Category::class);
    }
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}

Another example of many-to-many relationships first, you can create an intermediate table called "product_tag" that has the foreign keys for the product and the tag, that is, this would be the pivot table. Now, you can define Laravel's Eloquent models and their corresponding relationships between them.

In the product model, the belongsToMany() method is used to define the relationship with the tag, where a post has multiple tags.

While in the label model the same method can be used to define the inverse relationship with the products:

class Product extends Model
{
   public function tags()
   {
       return $this->belongsToMany(Tag::class);
   }
}
class Tag extends Model
{
   public function products()
   {
       return $this->belongsToMany(Product::class);
   }
}

To reference them we have:

$product = Product::find(1);
$tags = $product->tags;

$tag = Tag::find(1);
$products = $tag->products;

- Andrés Cruz

En español

Andrés Cruz

Develop with Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz In Udemy

I agree to receive announcements of interest about this Blog.

!Courses from!

10$

On Udemy

There are 0d 11:58!

Udemy

!Courses from!

4$

In Academy

View courses

!Books from!

1$

See the books
¡Become an affiliate on Gumroad!