Devio's avatar
Level 2

Proper way to use ->when() condition for optional request parameter

I have a request that should use simplePagination only if paginate is 0 in the query. if paginate doesn't exist or is any other value the response should use classic pagination. How can I achieve this in the code below.

Controller

public function index(Request $request){
      Post::pagination($request);
}

Post Model

public function scopePagination($query, $request){
      $query->when($request->paginate ==0, function($query){
            $query->simplePaginate();
      })->when($request->paginate !=0, function($query){
            $query->paginate();		
      });
}

NB:: I know there is $request->has() but the code feels messy when I use that

0 likes
13 replies
vincent15000's avatar

Your code seems to be the right one.

You can perhaps add query().

Post::query()->pagination($request);
Devio's avatar
Level 2

@vincent15000 I have a few filters and sorting before pagination. Just simplified it for the question. My issue is with the when condition logic, i.e., if I use has :

condition 1 ( paginate is false in the query) :

$request->has('paginate')  &&  in_array($request->paginate, [0, '0', 'false', false])

condition 2 ( paginate is empty or if not, is not 0 or false)

!$request->has('paginate')  ||  !in_array($request->paginate, [0, '0', 'false', false])

I feel like there is a simpler way of doing this

from my testing:

$request->paginate returns null if it does not exist or if it does not have a value

$request->has('paginate') returns true if paginate exists in the query, even if it doesn't have a value, i.e., <domain>?paginate will still return true

1 like
Devio's avatar
Level 2

I found a simpler way by adding another parameter to the query(simplePaginate):

condition 1 ( simplePaginate is in the query) :

$request->has('simplePaginate')

condition 2 ( simplePaginate is not in query)

!$request->has('simplePaginate')

although I didn't want to add another param in the query as it will make the documentation of the API messy

1 like
Ben Taylor's avatar

You could try using the default argument to tidy it up

->when($request->has('simplePaginate'), fn (Builder $q) => $q->simplePaginate(), fn (Builder $q) => $q->paginate())
2 likes
Ben Taylor's avatar

If the paginate methods don't work inside a when method, then you could do something like this:

$posts = Post::query();

if($request->has('simplePaginate')
{
    return $posts->simplePaginate();
}

return $posts->paginate();
1 like
vincent15000's avatar

@Ben Taylor @devio I prefer including directly the condition inside the query with when().

public function scopePagination($query, $request)
{
      $query->when($request->paginate, function ($query) {
            $query->paginate();
      })->when(!$request->paginate, function ($query) {
            $query->simplePaginate();		
      });
}
Snapey's avatar

in this situation A simple if statement is easier to understand

public function scopePagination($query, $request)
{
    if($request->input('pagination', false) {
        $query->paginate();
        return;
     }

     $query->simplePaginate();
}
Devio's avatar
Devio
OP
Best Answer
Level 2

I found a solution:

public function scopePagination($query, $request)
    {
        return $query->when(
            in_array($request->paginate, ['0', 'false']),
            fn($query) => $query->simplePaginate($request->limit ?? 12),
            fn($query) => $query->paginate($request->limit ?? 12)->withQueryString()
        );
    }

@ben taylor Thanks, did not know you could add a second closure to when()

NB::I only used string values since 0==NULL or false==NULL is true in php

1 like
vincent15000's avatar

@Devio Why do you have the best answer whereas it's @ben who seems to give you the better help ? You should give the best answer to @ben.

Devio's avatar
Level 2

@vincent15000 Notice I had already hinted at adding a simplePaginate parameter (the solution given by @ben ) and stated "although I didn't want to add another param in the query as it will make the documentation of the API messy".

And I only have it as as the best answer simply because it is the best answer, in the thread, to my original question.

If your have a better solution, that works, kindly share. I will gladly set that as the best answer.

1 like

Please or to participate in this conversation.