Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Easy Pagination Laravel Package

eonx-com/easy-pagination

Easy Pagination is a lightweight Laravel/PHP package that simplifies paginating query results and collections. It offers a clean, consistent API for building paginators, controlling page sizes, and integrating with Eloquent and the query builder, making reliable pagination easy to add to APIs and vi...

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a pagination input library, not a paginator. It parses what a client asked for (page, per_page, sorting) into a transport-agnostic value object you hand to your own query layer. Laravel's paginate() fuses request-reading, query execution, and response shaping into one call; this package solves only the first third, but solves it consistently across HTTP, CLI, and queue contexts.

Before you write production code, confirm the actual API surface. With 2 stars, 0 dependents, and docs-only maturity, the README is a starting point, not a spec. Read the source and the tests.

composer require eonx-com/easy-pagination

Then, in order:

  1. README.md — intended usage and any constructor/factory signatures.
  2. src/ — find the concrete pagination class(es) and any interfaces. Interfaces signal the intended extension points.
  3. tests/ — the most reliable documentation of edge-case behaviour (zero page? negative per-page? missing params? string vs int?).
  4. composer.json — check the PHP constraint and whether it pulls in illuminate/*. A genuinely generic package should have no Laravel dependency, which is what makes it reusable outside HTTP requests.

First use case — parse the request into a bounded object, then feed your query builder:

use Eonx\EasyPagination\Pagination; // confirm the exact FQCN in src/

public function index(Request $request)
{
    $pagination = Pagination::fromArray($request->query()); // verify factory name

    return UserResource::collection(
        User::query()
            ->orderBy($pagination->getSort() ?? 'id')
            ->forPage($pagination->getPage(), $pagination->getPerPage())
            ->get()
    );
}

If the API turns out to be one or two value objects (likely, given the name), budget an hour to read the source and decide whether to adopt or copy. At this maturity, a 40-line DTO of your own is a legitimate competitor — decide with eyes open.

Implementation Patterns

Controller → service → repository. Keep parsing at the edge and pass the value object inward. It becomes the seam that lets you test pagination logic without an HTTP request:

final class ListOrders
{
    public function __construct(private OrderRepository $orders) {}

    public function __invoke(PaginationInterface $pagination): Collection
    {
        return $this->orders->paginate($pagination);
    }
}

Normalise once, at construction. Don't scatter ?? 1 and max(1, min(100, ...)) across controllers. Build the object with defaults and clamping in one place — a base controller method, a form request, or a small factory:

protected function paginationFrom(Request $request): Pagination
{
    $pagination = Pagination::fromArray($request->query());

    // Defensive clamp regardless of what the package does with per_page
    if ($pagination->getPerPage() > 100) {
        $pagination = $pagination->withPerPage(100); // verify a wither exists
    }

    return $pagination;
}

Bridge to Laravel's output layer. You still want LengthAwarePaginator for a consistent JSON envelope (data, meta, links). Build it manually from the value object so you own the query and the shape:

$paginator = new LengthAwarePaginator(
    $items,
    $total,
    $pagination->getPerPage(),
    $pagination->getPage(),
    ['path' => $request->url(), 'query' => $request->query()]
);

return OrderResource::collection($paginator);

Wrap it behind an internal interface. This is the load-bearing pattern for a low-adoption package. Define PaginationParamsFactory (or similar) in your app, have one small class delegate to the vendor, and let controllers/services depend on your interface:

interface PaginationParamsFactory
{
    public function fromRequest(Request $request): PaginationParams;
}

Call sites never see Eonx\EasyPagination\*. If the package is orphaned — or you simply outgrow it — you replace one class instead of grepping the codebase.

Reuse across contexts. Because the object is transport-agnostic, a console command or queued job can construct it from an array (['page' => 2, 'per_page' => 50]) instead of an HTTP request, and share the same query path. This is the clearest ergonomic win over raw $request->get('page').

Pilot one endpoint. Migrate a single low-traffic list endpoint first. If it works without friction, follow it endpoint-by-endpoint as you touch them — do not big-bang rewrite working pagination.

Gotchas and Tips

  • Verify the API before writing code. Factory names (fromArray, fromRequest?), withers (withPerPage, withPage?), and sort handling are all guesses until you read src/. Cheap to check, expensive to assume.
  • Do not trust client input for the cap. The stated goal is "resolves page/per-page with upper limits," but confirm in the tests. If the package does not enforce a max per_page, a caller can request 100,000 rows and your database takes the hit. Enforce the cap in your adapter regardless.
  • Check for negative/zero handling. Confirm what page=0, page=-1, and per_page=abc produce in tests/. If they pass through unchanged, forPage(-1, ...) will misbehave silently.
  • Read composer.json for framework coupling. If it depends on illuminate/http, this is a Laravel-only utility and you should not pretend otherwise. If it's PSR-only, you get the CLI/queue reuse promised above. Either is fine — just know which you bought.
  • Pin the version. Read-only subtree splits sometimes ship tags ahead of or behind the parent monorepo. Use an exact constraint ("1.2.3" not "^1.2"), commit the lockfile, and record the commit hash. It makes the eventual audit or replacement trivial.
  • Audit for transitive easy-* creep. One install can drag in sibling packages, multiplying the unmaintained surface. Run composer why after install and confirm the dependency graph is what you expect.
  • Don't let the vendor class leak. The temptation is to type-hint Eonx\EasyPagination\Pagination directly in controllers and repositories. That works today and is a one-line change tomorrow — every time. The internal interface costs ~15 lines once.
  • Expect no upstream fixes. With 0 dependents and no community, you are the maintainer of last resort. The runtime cost is negligible (constant per-request, no state, no config); the upgrade cost is binary at every PHP/Laravel bump. Budget an annual review, or fold the 40 lines into your codebase once the pattern is proven.
  • Extension point: don't force it. If the interface is PaginationInterface with getPage()/getPerPage()/getSort(), your repository can accept that interface and stay decoupled from the concrete class. If there is no interface, define your own and adapt — same wrapper, slightly more code.
  • Debugging. If pagination appears to ignore the request, log the parsed object at construction time (['page' => ..., 'per_page' => ..., 'sort' => ...]). Nine times out of ten it's a query-string name mismatch (per_page vs perPage vs limit) or a framework middleware stripping query params — not a package bug.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tobya/saloonfire
kjmtrue/laravel-debugbar
hexincorp/debugbar
razorbacks/laravel-shibboleth
adilazhari/laravel-idempotency
mamitech/laravel-slow-query-log
mamitech/laravel-http-logger
medeirosrafael/docxmustache
webdevlabs/phreak
vis/log-envelope
digitickets/lalit
acacha/names
scool/foundation
frankkessler/guzzle-oauth2-middleware
delatbabel/site-config
delatbabel/applog
eusonlito/laravel-gettext
henzeb/housepedia-intelligence-laravel
aliqsm/laravel-authkit
itsjustvita/laravel-wp-migrator