arvil
arvil

Reputation: 920

eloquent - dynamic and conditional whereHas() in the query builder

I am trying to avoid DRY in my query builder, specifically on adding additional method in the chain.

Example, this is initially the query builder that I have:

$products = $app->myShop->realProducts()
        ->where($query)
        ->skip($skip)->take($take)
        ->orderBy($sortKey, $sortOrder)
        ->get();

Then if user used some filter, I needed to append a method (specifically a whereHas()) to the query builder

    $products = $app->myShop->realProducts()
        ->where($query)
        ->whereHas('colour', function ($q) use ($find) {
            $q->where('colour_slug', $find);
        })
        ->skip($skip)->take($take)
        ->orderBy($sortKey, $sortOrder)
        ->get();

I find it "ugly" that to achieve this result, I have to keep repeating those builder query:

if ($user_filtered_this_page == TRUE) {

    $products = $app->myShop->realProducts()->where($query)
        ->whereHas('colour', function ($q) use ($find) {
            $q->where('colour_slug', $find);
        })
        ->skip($skip)->take($take)
        ->orderBy($sortKey, $sortOrder)
        ->get();

} else {

    $products = $app->myShop->realProducts()->where($query)
        ->skip($skip)->take($take)
        ->orderBy($sortKey, $sortOrder)
        ->get();
}

Is there a more clever or elegant way to dynamically and conditionally append the whereHas() method to the chain?

Hope somebody can help. Thank you!

Upvotes: 3

Views: 6439

Answers (3)

Aref Ben Lazrek
Aref Ben Lazrek

Reputation: 1064

This could be done using Query Builder Conditional Clauses

    $products = $app->myShop->realProducts()
        ->where($query)
        ->when($user_filtered_this_page, function($query) use($find){
            $query->whereHas('colour', function ($q) use ($find) {
                $q->where('colour_slug', $find);
            })
        })
        ->skip($skip)->take($take)
        ->orderBy($sortKey, $sortOrder)
        ->get();

Upvotes: 3

Jonathon
Jonathon

Reputation: 16283

The query doesn't get executed until you call ->get() so you can quite simply build your query, conditionally add your ->whereHas() and then execute it:

$query= $app->myShop->realProducts()
    ->where($query)
    ->skip($skip)->take($take)
    ->orderBy($sortKey, $sortOrder);

if (...) {
    $query->whereHas(...);
}

$products = $query->get();

Upvotes: 13

Odin Thunder
Odin Thunder

Reputation: 3547

You can write like this:

$products = $app->myShop->realProducts()->where($query)
            ->whereHas('colour', function ($q) use ($find) {
                if ($user_filtered_this_page) {
                $q->where('colour_slug', $find);
            }
            })
            ->skip($skip)->take($take)
            ->orderBy($sortKey, $sortOrder)
            ->get();

Hope it help you ;)

Upvotes: 2

Related Questions