Model relationships
Database tables are related to each other: a post has an author and comments. In Eloquent a relationship is described by a model method, after which the related records are available as a regular property.
The foreign key
A relationship is stored in a column holding the identifier of another table. In the comments migration one line creates it:
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->text('body');
$table->timestamps();
});cascadeOnDelete() removes the comments together with the post.
One to many
A post has many comments — the hasMany() method:
class Post extends Model
{
public function comments()
{
return $this->hasMany(Comment::class);
}
}Related records are read as a property, without parentheses:
$post = Post::find(1);
foreach ($post->comments as $comment) {
echo $comment->body;
}The inverse relationship
A comment belongs to one post — the belongsTo() method:
class Comment extends Model
{
public function post()
{
return $this->belongsTo(Post::class);
}
}echo $comment->post->title;Creating a related record
Through the relationship a record is created with the right post_id straight away:
$post->comments()->create(['body' => 'Great post!']);Here the relationship is called as a method, with parentheses: that gives you a query builder rather than a finished list.
Many to many
A post has many tags, and a tag has many posts. This relationship needs a pivot table post_tag with the columns post_id and tag_id:
class Post extends Model
{
public function tags()
{
return $this->belongsToMany(Tag::class);
}
}$post->tags()->attach($tagId); // attach a tag
$post->tags()->detach($tagId); // detach a tagEager loading
The with() method loads related records in advance, with one extra query:
$posts = Post::with('comments')->get();Common mistake
Without with(), accessing a relationship in a loop runs a separate query for every record. A hundred posts mean a hundred and one queries — this is known as the N+1 problem.
// Slow: a comments query on every iteration.
foreach (Post::all() as $post) {
echo $post->comments->count();
}
// Fast: just two queries.
foreach (Post::with('comments')->get() as $post) {
echo $post->comments->count();
}