Laravel Example

Eloquent Relationships

Learn how to use different types of relationships in Laravel Eloquent ORM

One to One

Basic one-to-one relationship

Model Definition

// app/Models/User.php
class User extends Model
{
    public function profile()
    {
        return $this->hasOne(Profile::class);
    }
}

// app/Models/Profile.php
class Profile extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Usage Example

// Create
$user = User::create([
    'name' => 'John Doe',
    'email' => 'john@example.com'
]);

$user->profile()->create([
    'bio' => 'Laravel Developer',
    'website' => 'https://example.com'
]);

// Access
$user = User::find(1);
$bio = $user->profile->bio;

// Eager Loading
$user = User::with('profile')->find(1);

// Update
$user->profile->update([
    'bio' => 'Full Stack Developer'
]);

Key Points

  • Use hasOne() and belongsTo()
  • Foreign key convention: user_id
  • Eager load to avoid N+1 query
  • Cascade deletes with onDelete('cascade')

One to Many

Parent-child relationship

Model Definition

// app/Models/User.php
class User extends Model
{
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

// app/Models/Post.php
class Post extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Usage Example

// Create
$user = User::find(1);

$post = $user->posts()->create([
    'title' => 'My First Post',
    'content' => 'Hello World'
]);

// Query
$posts = $user->posts;
$latestPost = $user->posts()->latest()->first();

// With Conditions
$publishedPosts = $user->posts()
    ->where('status', 'published')
    ->get();

// Counting Related Models
$postCount = $user->posts()->count();
$userWithCount = User::withCount('posts')->get();

Key Points

  • Use hasMany() for collections
  • Chain query conditions to relationship
  • Count related models with withCount()
  • Access as property or method

Many to Many

Complex relationships with pivot table

Model Definition

// app/Models/Post.php
class Post extends Model
{
    public function tags()
    {
        return $this->belongsToMany(Tag::class)
            ->withTimestamps()
            ->withPivot('order');
    }
}

// app/Models/Tag.php
class Tag extends Model
{
    public function posts()
    {
        return $this->belongsToMany(Post::class)
            ->withTimestamps()
            ->withPivot('order');
    }
}

Migration

Schema::create('post_tag', function (Blueprint $table) {
    $table->id();
    $table->foreignId('post_id')->constrained()->onDelete('cascade');
    $table->foreignId('tag_id')->constrained()->onDelete('cascade');
    $table->integer('order')->nullable();
    $table->timestamps();
    
    $table->unique(['post_id', 'tag_id']);
});

Usage Example

// Attach Tags
$post = Post::find(1);
$post->tags()->attach([
    1 => ['order' => 1],
    2 => ['order' => 2]
]);

// Sync Tags (Remove existing)
$post->tags()->sync([
    1 => ['order' => 1],
    2 => ['order' => 2]
]);

// Toggle Tags
$post->tags()->toggle([1, 2, 3]);

// Access Pivot Data
foreach ($post->tags as $tag) {
    echo $tag->pivot->order;
}

// Query with Pivot
$post->tags()
    ->wherePivot('order', '>', 1)
    ->get();

Key Points

  • Use belongsToMany() in both models
  • Pivot table with naming convention
  • Additional pivot columns with withPivot()
  • Methods: attach(), sync(), toggle()

Has Many Through

Relationship through intermediate model

Model Definition

// app/Models/Country.php
class Country extends Model
{
    public function posts()
    {
        return $this->hasManyThrough(
            Post::class,
            User::class,
            'country_id', // Foreign key on users table
            'user_id',    // Foreign key on posts table
            'id',         // Local key on countries table
            'id'         // Local key on users table
        );
    }
}

// Relationship Chain:
// Country -> User -> Post

Usage Example

// Get all posts from a country
$country = Country::find(1);
$posts = $country->posts;

// With Constraints
$recentPosts = $country->posts()
    ->where('status', 'published')
    ->latest()
    ->get();

// Eager Loading
$countries = Country::with('posts')->get();

// With Nested Eager Loading
$countries = Country::with(['posts.comments'])->get();

Key Points

  • Access distant relations through intermediate model
  • Specify custom keys if not following convention
  • Chain query constraints as usual
  • Eager load for performance optimization