PHP
Filter Parent Models Based on Related Model Conditions
Efficiently filter parent Eloquent models based on the existence or conditions of their related models using `whereHas` or `has` methods.
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
class ReportController extends Controller
{
public function usersWithPosts()
{
// Get users who have at least one post
$users = User::has('posts')->get();
// Equivalent SQL: SELECT * FROM users WHERE EXISTS (SELECT * FROM posts WHERE users.id = posts.user_id)
echo "Users with any posts: " . $users->pluck('name')->implode(', ') . "
";
// Get users who have posts with 'published' status
$usersWithPublishedPosts = User::whereHas('posts', function (Builder $query) {
$query->where('status', 'published');
})->get();
// Equivalent SQL: SELECT * FROM users WHERE EXISTS (SELECT * FROM posts WHERE users.id = posts.user_id AND status = 'published')
echo "Users with published posts: " . $usersWithPublishedPosts->pluck('name')->implode(', ') . "
";
// Get users who DO NOT have any posts
$usersWithoutPosts = User::doesntHave('posts')->get();
echo "Users without any posts: " . $usersWithoutPosts->pluck('name')->implode(', ') . "
";
// Get users who DO NOT have posts with 'published' status
$usersWithoutPublishedPosts = User::whereDoesntHave('posts', function (Builder $query) {
$query->where('status', 'published');
})->get();
echo "Users without published posts: " . $usersWithoutPublishedPosts->pluck('name')->implode(', ') . "
";
return response()->json([
'users_with_posts' => $users->pluck('name'),
'users_with_published_posts' => $usersWithPublishedPosts->pluck('name'),
'users_without_posts' => $usersWithoutPosts->pluck('name'),
'users_without_published_posts' => $usersWithoutPublishedPosts->pluck('name'),
]);
}
}
How it works: Eloquent's `has()` and `whereHas()` methods are powerful for filtering parent models based on the existence or specific conditions of their related models. `has('relationship')` retrieves parent models that have at least one related record. `whereHas('relationship', function (Builder $query) { ... })` extends this by allowing you to add more specific constraints to the related model's query. Conversely, `doesntHave()` and `whereDoesntHave()` retrieve parent models that do not have any or specific related records, respectively. These methods are crucial for complex relational queries without needing raw SQL joins.