Eloquent::when(): No More if-elses for Conditional Queries

Tutorial last revisioned on August 10, 2022 with Laravel 9

For a while many of us used to write conditional queries with "if-else", something like this:

if (request('filter_by') == 'likes') {
    $query->where('likes', '>', request('likes_amount', 0));
if (request('filter_by') == 'date') {
    $query->orderBy('created_at', request('ordering_rule', 'desc'));

What if I told you there's a (much) better way? Easily readable and more Laravel-ish. Meet when() method.

$query = Author::query();

$query->when(request('filter_by') == 'likes', function ($q) {
    return $q->where('likes', '>', request('likes_amount', 0));
$query->when(request('filter_by') == 'date', function ($q) {
    return $q->orderBy('created_at', request('ordering_rule', 'desc'));

$authors = $query->get();

Looks nicer, doesn't it?

Notice: click here to watch video version of this lesson, in my 2-hour online-course Eloquent: Expert Level

Wait, there's more

In the example below we will filter users only if the role was passed as a request option.

This means - as long as there is no parameter or it's false/null - you will see all of the users but if it becomes a value, lets say "1" for administrator - you will only see administrators.

$query = User::query();

// From Laravel 5.4 you can pass the same condition value as a parameter
$query->when(request('role', false), function ($q, $role) {
    return $q->where('role_id', $role);

$authors = $query->get();

What about default values?

Bellow example shows third argument to the when method. This closure will only execute if the first argument evaluates as false.

->when(request('filter_by') == 'likes', function ($q) {
    return $q->where('likes', '>', request('likes_amount', 0));
}, function ($q) {
    return $q->orderBy('created_at', request('ordering_rule', 'desc'));

It's not just a prettier way to write the same "IF" but is also a great way to organize conditional queries.

More information about conditional queries: https://laravel.com/docs/master/queries#conditional-clauses

Here's a pull request for the parameter acceptance (not mentioned in official docs): https://github.com/laravel/framework/pull/18419


Very nice tip, thanks !


Learn something new thank you sir


Looks nicer, doesn't it?

Actually, no. I don't understand why it's so complicated, to use an additional function where you can just "if ", complicating the readability of the code.


Today I learnt something valuable. My query was something like this:

  • $query->when($request->min_price , function ($q) use ($min_price, $max_price) { $q->whereBetween('price', [ $min_price, $max_price ]); });*

This used to return all of the data. It seemed like this filter was not used.

The important lesson here is, When we directly use $request->min_price, then it replaces the exact value of the min price. And suppose the min_price is 0. Since laravel uses if conditions for when statements, the if condition became false (0). And hence the query was not executed.

The proper method was as to use request('min_price') or $request->has('min_price)

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 50 courses (910 lessons, total 46 h 42 min)
  • 68 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials