Relationships
Define how models relate with hasMany, belongsTo and more.
Syntax
public function posts() { return $this->hasMany(Post::class); }Eloquent models can describe how tables relate. Define a method that returns a relationship type:
hasMany()— one user has many posts.belongsTo()— a post belongs to a user.belongsToMany()— many-to-many.
Access them like properties: $user->posts.
Example
class User extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
}
// Usage:
// $user->posts; // a Collection of the user's postsWhen to use it
- A blog's Post model defines hasMany('App\Models\Comment') so $post->comments returns all related Comment records without writing a JOIN.
- An e-commerce Order model uses belongsToMany('App\Models\Product') with a pivot table so each order can contain many products and each product can appear in many orders.
- A user profile uses hasOne('App\Models\Profile') to ensure a one-to-one relationship and access $user->profile->bio directly.
More examples
hasMany and belongsTo
Defines both sides of a one-to-many relationship: a Post has many Comments, and each Comment belongs to a Post.
// app/Models/Post.php
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}
// app/Models/Comment.php
public function post(): BelongsTo
{
return $this->belongsTo(Post::class);
}
// Usage
$comments = $post->comments; // Collection of Comment models
$parent = $comment->post; // The Post modelbelongsToMany with pivot
Declares a many-to-many relationship using an order_product pivot table, exposing qty and unit_price as pivot attributes.
// app/Models/Order.php
public function products(): BelongsToMany
{
return $this->belongsToMany(Product::class)
->withPivot('qty', 'unit_price')
->withTimestamps();
}
// Attach a product with pivot data
$order->products()->attach($productId, ['qty' => 2, 'unit_price' => 49.99]);
// Sync (detaches any not in the array)
$order->products()->sync([$id1, $id2]);Eager loading to prevent N+1
with() eager loads the author and tags relationships in just two queries, eliminating the N+1 problem that lazy loading causes.
// N+1 problem: 1 query for posts + N queries for each author
$posts = Post::all();
foreach ($posts as $post) {
echo $post->author->name; // extra query per post
}
// Eager loading: 2 queries total
$posts = Post::with('author', 'tags')->get();
foreach ($posts as $post) {
echo $post->author->name; // no extra query
}
Discussion