Eloquent: Relationships - Laravel 12.x - The PHP Framework For Web Artisans
In order to define a many to many relationship, 3 tables are needed.
Assume we have 2 tables, books
and authors
. The relationship between authors and books is many to many, because a book can have many authors, and an author can have many books.
In order to implement this relationship, a third table is needed, which is usually named author_book
by convention.
---
title: Example Database
---
classDiagram
class books {
+ int id
}
class authors {
+ int id
}
class author_book {
+ int book_id references books@id
+ int author_id references authors@id
}
books -- author_book
authors -- author_book
The intermediatory table author_book
is created via a new migration:
php artisan make:migration create_author_book_table
<?php
use Illuminate\\Database\\Migrations\\Migration;
use Illuminate\\Database\\Schema\\Blueprint;
use Illuminate\\Support\\Facades\\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('author_book', function (Blueprint $table) {
$table->id();
$table->foreignId('author_id')->constrained(); // referencing authors table
$table->foreignId('book_id')->constrained(); // referencing books table
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('author_book');
}
};
Many to many relations are implemented using a BelongsToMany
method on the model.
<?php
namespace App\\Models;
use App\\Models\\Author;
use Illuminate\\Database\\Eloquent\\Model;
use Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;
class Book extends Model
{
public function authors() : BelongsToMany
{
return $this->belongsToMany(Author::class); // referencing authors
}
}
<?php
namespace App\\Models;
use App\\Models\\Book;
use Illuminate\\Database\\Eloquent\\Model;
use Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;
class Author extends Model
{
public function books():BelongsToMany
{
return $this->belongsToMany(Book::class); // referencing books
}
}
<aside> š”
By default Eloquent uses the names of both models in alphabetical order separated by a _
as the name of the intermediate table.
graph LR
A("Table A") --> C("A_B")
B("Table B") --> C("A_B")
To override this behavior, the name of the intermediate table should be passed as the second argument to the belongsToMany
method:
public function books():BelongsToMany
{
return $this->belongsToMany(Book::class, **'intermediate_table'**);
}
Column names of the keys on the table can also be customized by passing additional arguments to theĀ belongsToMany
Ā method. The third argument is the foreign key name of the model on which you are defining the relationship, while the fourth argument is the foreign key name of the model that you are joining to:
public function books():BelongsToMany
{
return $this->belongsToMany(Book::class, 'intermediate_table', 'author_id',
'book_id');
}
</aside>
use App\\Models\\Author;
$author = Author::find(1);
foreach ($author->books as $book) {
echo $book->title;
}
$publishedBooks = Author::find(1)->books()->where('published', true)->get();