How to set up a many-to-many relationship in Laravel

Categorized as Laravel Tagged

Many-to-many Eloquent relationships are more advanced types of relationships available in Laravel. For example, one blog post can have several categories, and these categories may also be assigned to other blog posts. In this case, we speak about many-to-many relationships, where the post can have many categories and the category may have many posts.

Let’s set up the database with migrations, then corresponding models and show the code examples.

Migrations

Assuming you already have the Posts and Categories tables and Models, let’s make the migration for the PostsCategories intermediate table.


php artisan make:migration "create many to many posts categories table"

Make sure that id column has the same type in all of these three tables, or you will not be able to set up Foreign Keys.

The basic concept of Foreign Keys is that it is mainly used as a constraint to disable the elimination of links between tables. For example, if you try to change the post’s id in the Posts table, it will not be possible if it is presented as post_id in the PostsCategories table.

Also, if you have Post and Category models, you should name the corresponding columns as post_id and category_id and not as posts_id and categories_id.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateManyToManyPostsCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('PostsCategories', function (Blueprint $table) {
            $table->integer('post_id')->unsigned();
            $table->integer('category_id')->unsigned();
            $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
            $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('PostsCategories');
    }
}

Run the migration

php artisan migrate

Now you have an intermediate table where you can store links between the Posts and Categories. You can add or remove these links both manually and programmatically (with attach(), detach() and sync() methods available in Laravel).

But to make it work we have to adjust our Models with many-to-many relationships.

// Category Model

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;


class Category extends Model
{
    use HasFactory;

    protected $table = 'categories';

    /**
     * The Posts that belong to Categories.
     */
    public function manyPosts()
    {
        return $this->belongsToMany(Post::class, 'PostsCategories');
    }
}
// Post Model

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;

    protected $table = 'posts';

    /**
     * The Categories that belong to Posts.
     */
    public function manyCategories()
    {
        return $this->belongsToMany(Category::class, 'PostsCategories');
    }

}
// PostsCategories Model

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class PostsCategories extends Model
{
    use HasFactory;
}

Now, you have to set up links in the PostsCategories table. Add two records with the same post_id and different category_id. Now retrieve the links information:

$attachedCategories = Post::find(1)->manyCategories;
ddd($attachedCategories);

Leave a reply

Your email address will not be published. Required fields are marked *