PHP

Filtering Eloquent Models by Related Model Conditions with `whereHas`

Learn how to filter your main Eloquent models based on the existence or specific conditions of their related models using `whereHas` and `orWhereHas` methods in Laravel.

<?php
// Assume you have Post and Comment models with a one-to-many relationship:
// Post hasMany Comments
// Comment belongsTo Post

// In your Post model (app/Models/Post.php)
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;
    protected $fillable = ['title', 'content'];

    public function comments()
    {
        return $this->hasMany(Comment::class);
    }
}

// In your Comment model (app/Models/Comment.php)
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    use HasFactory;
    protected $fillable = ['post_id', 'body', 'is_approved'];

    public function post()
    {
        return $this->belongsTo(Post::class);
    }
}

// Example Usage in a controller or route
use App\Models\Post;

// Find all posts that have at least one comment
$postsWithComments = Post::whereHas('comments')->get();

// Find all posts that have at least one APPROVED comment
$postsWithApprovedComments = Post::whereHas('comments', function ($query) {
    $query->where('is_approved', true);
})->get();

// Find all posts that have at least one comment from a specific user (user_id = 5)
$postsWithUserComments = Post::whereHas('comments', function ($query) {
    $query->where('user_id', 5);
})->get();

// Find all posts that DO NOT have any comments
$postsWithoutComments = Post::doesntHave('comments')->get();

// Find all posts that have at least one approved comment OR have no comments at all
$complexFilter = Post::whereHas('comments', function ($query) {
    $query->where('is_approved', true);
})->orDoesntHave('comments')->get();
How it works: The `whereHas` method allows you to retrieve parent models based on conditions applied to their related models. It's incredibly useful for filtering. For instance, you can find all `Post` models that have *any* associated `Comment`, or more specifically, posts that have *approved* comments. `doesntHave` is its inverse, finding parent models without any related models. These methods generate efficient SQL queries, often involving `EXISTS` subqueries, to filter the main table without necessarily loading all related data into memory.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs