How to Define and Use N:M Relationships in Laravel Eloquent
Many-to-many (N:M) relationships are a fundamental concept in relational databases. Laravel Eloquent makes it easy to define and work with these relationships using pivot tables. In this guide, we’ll walk through how to create an N:M relationship using generic tables for a Products and Categories example.
What Is an N:M Relationship?
An N:M relationship exists when multiple records in one table relate to multiple records in another. For instance:
- A product can belong to multiple categories.
- A category can include multiple products.
To implement this, a pivot table is used to store the relationships between the two entities.
Example Scenario: Products and Categories
We’ll create the following:
products
table: Contains product details.categories
table: Contains category details.category_product
(pivot table): Links products with categories.
Step 1: Creating the Database Tables
Migration for the Pivot Table
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCategoryProductTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('category_product', function (Blueprint $table) {
$table->unsignedBigInteger('product_id');
$table->unsignedBigInteger('category_id');
// Composite primary key
$table->primary(['product_id', 'category_id']);
// Foreign key constraints
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('category_product');
}
}
Key Elements:
- Pivot Table Name: Named
category_product
by convention (alphabetical order of related table names). - Composite Primary Key: Ensures a unique combination of
product_id
andcategory_id
. - Foreign Keys: Links the pivot table to
products
andcategories
.
Run the migration with:
php artisan migrate
Step 2: Define Eloquent Models and Relationships
Product Model (Product
)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $table = 'products';
public function categories()
{
return $this->belongsToMany(Category::class, 'category_product', 'product_id', 'category_id');
}
}
Category Model (Category
)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
protected $table = 'categories';
public function products()
{
return $this->belongsToMany(Product::class, 'category_product', 'category_id', 'product_id');
}
}
Step 3: Using the Relationship in Laravel
Now that the relationships are defined, let’s perform CRUD operations.
Attach Categories to a Product
To link a product with one or more categories:
$product = Product::find($productId);
$product->categories()->attach($categoryIds);
Detach Categories from a Product
To remove a relationship between a product and categories:
$product->categories()->detach($categoryIds);
Sync Categories for a Product
To replace all existing categories for a product with a new set:
$product->categories()->sync($categoryIds);
Retrieve Categories for a Product
To get all categories a product belongs to:
$product->categories;
Retrieve Products for a Category
To get all products in a specific category:
$category->products;
Step 4: Best Practices
- Table Naming: Use descriptive names for the pivot table, combining the related tables in alphabetical order.
- Primary Keys: Use composite primary keys in the pivot table to ensure uniqueness.
- Cascade Deletes: Set
onDelete('cascade')
on foreign key constraints to maintain referential integrity when a product or category is deleted.
Bonus: Querying Relationships with Constraints
You can add constraints when querying relationships. For example:
Products in a Specific Category
$products = Category::where('name', 'Electronics')->first()->products;
Categories of a Product Created in the Last 30 Days
$categories = Product::where('created_at', '>=', now()->subDays(30))->first()->categories;
Conclusion
Defining and using N:M relationships in Laravel Eloquent is a straightforward process. By leveraging pivot tables and Eloquent’s belongsToMany
methods, you can effectively manage complex relationships in your application. This approach is flexible, scalable, and maintains the relational integrity of your data.
Start implementing these techniques to simplify and organize your many-to-many relationships today!