0

The below Controller method changes the query based on the flags which are activated.

    public function index(Request $request)
    {
        $q = new ProductModel();

        if($request->has('flag1')) {
            $q = $q->includeFlag1();
        }

        if($request->has('flag2')) {
            $q = $q->doFlag2();
        }

        if($request->has('flag3')) {
            $q = $q->doFlagthing3();
        }

        return $q->paginate();
    }

Most example code I've seen will call a where() from the beginning instead of creating a new Model instance and looks something like this:

        $q = ProductModel::where('available', true);
        if($request->has('flag1')) {
            $q->includeFlag1();
        }

But in my case based on the table fields it isn't possible for me to start from a where like this so it seems I must do $q = $q every time in every case... It's not neat, neither would doing something hacky like attempting to use a where true clause.

How can I clean either get the query object neatly from the beginning and use that or otherwise avoid having to do $q = $q inside each if()?

1 Answer 1

1

You can use query() and when() methods :

public function index(Request $request)
{
    $query = ProductModel::query()
        ->when($request->has('flag1'), function ($q) {
           $q->includeFlag1();
        })
        ->when($request->has('flag2'), function ($q) {
           $q->doFlag2();
        })
        ->when($request->has('flag3'), function ($q) {
           $q->doFlagthing3();
        })
        ->paginate();
}

The official documentation is here: https://laravel.com/docs/9.x/queries#conditional-clauses

Sometimes you may want certain query clauses to apply to a query based on another condition. (...) The when method only executes the given closure when the first argument is true. If the first argument is false, the closure will not be executed.

You have also a more concise alternative using arrow functions (thanks @miken32's comment):

public function index(Request $request)
{
    $query = ProductModel::query()
        ->when($request->has('flag1'), fn ($q) => $q->includeFlag1())
        ->when($request->has('flag2'), fn ($q) => $q->doFlag2())
        ->when($request->has('flag3'), fn ($q) => $q->doFlagthing3())
        ->paginate();
}
Sign up to request clarification or add additional context in comments.

1 Comment

I would suggest arrow functions are neater and more concise. ->when($request->has('flag3'), fn ($q) => $q->doFlagthing3())

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.