PHP

Filter Models Based on Related Model Existence with `whereHas`

Learn to use Laravel Eloquent's `whereHas` method to filter parent models based on conditions of their related models, enabling complex data retrieval.

// app/Models/Post.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

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

    public function tags()
    {
        return $this->belongsToMany(Tag::class);
    }
}

// app/Models/Comment.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    protected $fillable = ['content', 'is_approved', 'post_id'];
}

// app/Models/Tag.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
    protected $fillable = ['name'];
}

// Usage example: Get posts that have at least one comment
$postsWithComments = Post::has('comments')->get();

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

// Usage example: Get posts that have a specific tag named 'Laravel'
$postsWithLaravelTag = Post::whereHas('tags', function ($query) {
    $query->where('name', 'Laravel');
})->get();

// Usage example: Get posts that *do not* have any comments
$postsWithoutComments = Post::doesntHave('comments')->get();

// Usage example: Get posts that *do not* have any approved comments
$postsWithoutApprovedComments = Post::whereDoesntHave('comments', function ($query) {
    $query->where('is_approved', true);
})->get();
How it works: The `whereHas` method allows you to filter results of a parent model based on conditions applied to its related models. This is highly useful when you need to retrieve, for example, all posts that have comments by a specific user or posts that are associated with a particular tag. `has()` checks for the mere existence of a related model, while `whereHas()` allows adding specific constraints to the related model's query. `doesntHave()` and `whereDoesntHave()` provide the inverse functionality. This is distinct from eager loading relationships (using `with()`) as it focuses on filtering the *parent* models, not fetching the related data for each parent.

Need help integrating this into your project?

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

Hire DigitalCodeLabs