Framework: Paginate with Query Parameters

Created on 31 Jul 2018  ·  5Comments  ·  Source: laravel/framework

  • Laravel Version: 5.6.28
  • PHP Version: 7.2
  • Database Driver & Version: mysql 5.6

Description:

Can I pass per_page on query parameters like:
http://localhost:8000/api/company?per_page=100

and get the correct per page using only:

return response()->json(Company::paginate())

Most helpful comment

But why?! It is very weird that the "page" number is determined by URL query parameter, but the "limit" (items per page) is taken from Eloquent Model. Why is Model telling what the default limit (items per page) is?! That is so weird! 🙄
https://github.com/illuminate/database/blob/v6.0.2/Eloquent/Builder.php#L698

What I did – I created a macro. In your app/Providers/AppServiceProvider.php file, inside boot method add this:

// Paginate the Eloquent results and allow the user to choose the amount of results per page
\Illuminate\Database\Eloquent\Builder::macro('paginateAuto', function ($perPage = null, ...$args) {
    if ($perPage === null) {
        $perPage = request()->query('limit');
        $defaultPerPage = 10;
        $maxPerPage = 100;

        $perPage = (filter_var($perPage, FILTER_VALIDATE_INT) === false || (int) $perPage < 1)
            ? $defaultPerPage
            : min((int) $perPage, $maxPerPage);
    }

    return $this->paginate($perPage, ...$args);
});

So now I can allow the user to decide how many results he wants (also I have max limit 100) and I don't have to change any Model. Of course, I have to change Controllers and instead of that long and complicated version, I have to write only this:

return response()->json(Company::paginateAuto());

Notice that in my macro I use query parameter called "limit", so you may want to change that to "per_page".

And no, there is no easy way to change/extend/tap the Illuminate\Database\Eloquent\Builder class, so the less painful way is using my macro.

Hey, @taylorotwell @tillkruss , could you please re-open this issue so we could at least talk about this with others? Or is there a legit reason why "per_page" should be extracted from the Model? 🤷‍♂

All 5 comments

You can just pass the query parameter to paginate():

return response()->json(Company::paginate((int) request()->per_page));
return response()->json(Company::paginate((int) $request->per_page));

@staudenmeir thanks, but I things that can be automatically, and we don't need to expose this.. maybe?

I don't think that's possible.

But why?! It is very weird that the "page" number is determined by URL query parameter, but the "limit" (items per page) is taken from Eloquent Model. Why is Model telling what the default limit (items per page) is?! That is so weird! 🙄
https://github.com/illuminate/database/blob/v6.0.2/Eloquent/Builder.php#L698

What I did – I created a macro. In your app/Providers/AppServiceProvider.php file, inside boot method add this:

// Paginate the Eloquent results and allow the user to choose the amount of results per page
\Illuminate\Database\Eloquent\Builder::macro('paginateAuto', function ($perPage = null, ...$args) {
    if ($perPage === null) {
        $perPage = request()->query('limit');
        $defaultPerPage = 10;
        $maxPerPage = 100;

        $perPage = (filter_var($perPage, FILTER_VALIDATE_INT) === false || (int) $perPage < 1)
            ? $defaultPerPage
            : min((int) $perPage, $maxPerPage);
    }

    return $this->paginate($perPage, ...$args);
});

So now I can allow the user to decide how many results he wants (also I have max limit 100) and I don't have to change any Model. Of course, I have to change Controllers and instead of that long and complicated version, I have to write only this:

return response()->json(Company::paginateAuto());

Notice that in my macro I use query parameter called "limit", so you may want to change that to "per_page".

And no, there is no easy way to change/extend/tap the Illuminate\Database\Eloquent\Builder class, so the less painful way is using my macro.

Hey, @taylorotwell @tillkruss , could you please re-open this issue so we could at least talk about this with others? Or is there a legit reason why "per_page" should be extracted from the Model? 🤷‍♂

If you want to keep all the actual query variables in the paginated links (which seems to be useful in most cases), you can use:

return response()->json(Company::paginate()->withQueryString());
Was this page helpful?
0 / 5 - 0 ratings

Related issues

Fuzzyma picture Fuzzyma  ·  3Comments

progmars picture progmars  ·  3Comments

shopblocks picture shopblocks  ·  3Comments

YannPl picture YannPl  ·  3Comments

Anahkiasen picture Anahkiasen  ·  3Comments