⬡ Lacelium
⌘K
Version 2.x ▾
Data Navigation

Pagination

Lacelium includes an intelligent query paginator designed to work natively with Eloquent and Twig, automatically maintaining query string parameters, sort orders, and search filters across page transitions.

Controller Integration

The Lacelium\Core\Pagination\Paginator class wraps any Eloquent or Capsule query builder instance. Always clone your builder instance when executing the final slice query so the total count calculation remains isolated.

namespace App\Http\Controllers;

use App\Models\Task;
use Lacelium\Core\Http\Request;
use Lacelium\Core\Http\Response;
use Lacelium\Core\Pagination\Paginator;

class TaskController
{
    public function index(Request $request, Response $response): Response
    {
        // 1. Build filtered base query
        $query = Task::query()
            ->when($request->query('status'), fn($q, $s) => $q->where('status', $s))
            ->orderByDesc('created_at');

        // 2. Instantiate paginator (computes total count & current page automatically)
        $perPage   = 15;
        $paginator = Paginator::fromQuery($query, $request, perPage: $perPage);

        // 3. Slice and fetch the active page models
        $items = (clone $query)
            ->forPage($paginator->currentPage, $perPage)
            ->get();

        return $response->render('docs/tasks/index.twig', [
            'items'     => $items,
            'paginator' => $paginator,
        ]);
    }
}

Rendering in Twig Templates

Include the framework's pre-styled docs/paginator.twig component at the bottom of your data tables or lists. It automatically generates pagination controls with accessible ARIA tags and active state indicators.

{# Loop through paginated items #}
{% for task in items %}
{{ task.title }} {{ task.status }}
{% else %}

No records found.

{% endfor %}
{# Render standard navigation buttons & metadata #} {% include 'docs/paginator.twig' with { paginator: paginator } %}

Live Interactive Preview

Experience how Lacelium's pagination buttons preserve existing query parameters (such as search keywords and sorting fields) while updating the page index:

Simulated Navigation State: Page 2 of 8 (118 Total Items)
Generated URL: /tasks?search=finance&sort=desc&page=2

Paginator Properties & Methods

The Paginator object exposes metadata used for custom UI widgets or JSON API responses:

Property / Method Return Type Description
$paginator->currentPage int Current page number (1-indexed).
$paginator->total int Total count of matching records across the entire dataset.
$paginator->perPage int Maximum number of items displayed per page.
$paginator->lastPage int Total number of pages calculated as ceil($total / $perPage).
$paginator->hasPages() bool Returns true if total records exceed perPage.
$paginator->hasMorePages() bool Returns true if current page is less than lastPage.
$paginator->url(int $page) string Builds query string preserving all existing query parameters while updating page.

SPA Zero-Refresh Updates

When combined with Lacelium's SPA routing layer (data-spa="true"), clicking pagination links seamlessly replaces table content and URL history without a full page reload:

<!-- Enable zero-reload SPA navigation on data container -->
<div id="tasks-table-container" data-spa-fragment="true">
    </div>

Performance Guidelines

  • Large Datasets (>100,000 Rows): On massive tables, COUNT(*) can be costly. For analytical dashboards, consider cursor-based pagination with where('id', '>', $lastId).
  • Eager Loading Relations: Always combine with with(['relationship']) on the sliced query to avoid N+1 query execution.
  • Sanitize Bounds: The paginator automatically guards against negative page indices and numbers exceeding lastPage.

Next Steps