Merge 'with' and 'whereHas' in Laravel 5
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
# Simplifying Eloquent: Merging `whereHas` and `with` in Laravel 5
As senior developers working with Eloquent, we often encounter situations where we need to combine filtering logic (`whereHas`) with eager loading (`with`). The code snippet you provided perfectly illustrates a common point of confusion: trying to reuse a dynamic closure for both constraining the relationship *and* specifying what to load. While your existing code works, it does feel redundant, and there are cleaner, more expressive ways to handle these operations in Laravel 5 (and modern Eloquent).
Let's dive into why this happens and how we can simplify it without sacrificing clarity or performance.
## Understanding the Redundancy
Your goal is to retrieve `User` models who have related `submissions`, and ensure that the loaded `submissions` also satisfy a specific condition (i.e., they are linked to a specific task, `$id`).
The original approach:
```php
$filterTask = function($query) use ($id) {
$query->where('taskid', $id);
};
User::whereHas('submissions', $filterTask)
->with(['submissions' => $filterTask])
->get();
```
Here, you are passing the same filtering logic (`$filterTask`) to both methods. `whereHas('submissions', $filterTask)` filters the primary `User` query based on whether a related `submission` exists that matches `$id`. Then, `with(['submissions' => $filterTask])` tells Eloquent to load the `submissions` relationship, applying the *exact same filter* to those loaded submissions.
While functional, this pattern can become verbose and slightly confusing because it forces you to define the constraint twice. The core principle of Eloquent is that relationships are defined by constraints; we should aim to express the intent cleanly.
## The Simplified Approach: Separation of Concerns
The key to simplification is realizing that `whereHas` handles *existence* checks on the relationship, whereas `with` handles *loading*. If you need to filter the loaded data specifically (e.g., only load submissions where `taskid = X`), itâs often cleaner to handle those constraints separately or by structuring your query differently.
For the specific goalâgetting users who have submissions related to a task, and ensuring those submissions meet a criteriaâwe can separate the filtering into two distinct steps if necessary, or use more direct constraint methods.
### Method 1: Filtering the Parent Query First (The Cleanest Way)
If your primary requirement is simply to find Users based on the existence of a filtered relationship, you should focus `whereHas` entirely on the primary model constraints.
If you only care that the User *has* submissions related to `$id`, and not necessarily filtering what those submissions are loaded with, simplify it like this:
```php
$usersWithFilteredSubmissions = User::whereHas('submissions', function ($query) use ($id) {
$query->where('taskid', $id);
})->with('submissions')->get();
```
In this scenario, you only need to define the constraint once within the `whereHas` closure. The `with('submissions')` then handles the eager loading without needing a duplicated filter inside the `with` array. This adheres better to principles of clear query construction advocated by Laravel standards found at [https://laravelcompany.com](https://laravelcompany.com).
### Method 2: Filtering Nested Relationships (When Strict Loading is Required)
If your requirement truly means: "Get Users who have submissions, and only load those submissions that belong to Task X," then you must ensure the constraint applies correctly during eager loading. In many cases, if `whereHas` already establishes the necessary link, applying a filter in `with` can be slightly complex unless you are dealing with polymorphic relationships or very deep nesting.
If Method 1 doesn't meet your exact data requirement (e.g., you need to load *only* submissions linked to `$id`, and not all of the user's submissions), then you might need to restructure your query entirely using nested `whereHas` clauses if applicable, or use relationships that naturally enforce these constraints directly on the model definitions.
## Conclusion
The redundancy in merging `whereHas` and `with` often stems from trying to force a single callback function into two distinct roles. By separating the concernsâusing `whereHas` solely for filtering the parent record based on relationship existence, and using `with` strictly for eager loadingâwe achieve cleaner, more maintainable Eloquent queries. Always strive for clarity in your query construction; this practice is fundamental to writing effective code with frameworks like Laravel.