> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Pagination

> Die Pagination-Funktionen von Laravel im Überblick. Von den Unterschieden zwischen paginate(), simplePaginate() und cursorPaginate() über die Anzeige in Blade bis zu API-Antworten und der URL-Anpassung.

## Was ist Pagination

Die Pagination von Laravel ist in den Query Builder und das Eloquent ORM integriert und ohne Konfiguration einsatzbereit. Die aktuelle Seite wird automatisch aus dem Query-Parameter `page` des HTTP-Requests gelesen und den generierten Links auch automatisch hinzugefügt.

Das Standard-HTML unterstützt Tailwind CSS; alternativ ist Bootstrap CSS verfügbar.

## Drei Arten der Pagination

| Methode            | Rückgabewert           | Merkmale                                                  |
| ------------------ | ---------------------- | --------------------------------------------------------- |
| `paginate()`       | `LengthAwarePaginator` | Ermittelt die Gesamtzahl. Erzeugt Seitenlinks mit Nummern |
| `simplePaginate()` | `Paginator`            | Ermittelt keine Gesamtzahl. Nur „Zurück“ und „Weiter“     |
| `cursorPaginate()` | `CursorPaginator`      | Cursor-basiert. Ideal für große Datenmengen               |

## Grundlagen

### Pagination mit dem Query Builder

```php theme={null}
use Illuminate\Support\Facades\DB;

// 15 Einträge pro Seite
$users = DB::table('users')->paginate(15);
```

### Pagination mit Eloquent

```php theme={null}
use App\Models\User;

$users = User::paginate(15);

// Mit Bedingung
$users = User::where('votes', '>', 100)->paginate(15);
```

### simplePaginate

Wenn Sie die Gesamtzahl nicht benötigen (und nur „Zurück“- und „Weiter“-Links anzeigen), ist `simplePaginate()` effizienter.

```php theme={null}
$users = DB::table('users')->simplePaginate(15);
$users = User::where('active', true)->simplePaginate(15);
```

<Tip>
  Wenn Sie keine Anzeige „X von insgesamt Y“ brauchen, wählen Sie `simplePaginate()`. `paginate()` führt zusätzlich eine `COUNT(*)`-Abfrage aus, `simplePaginate()` ist daher schneller.
</Tip>

### cursorPaginate (Cursor-Pagination)

Cursor-Pagination verwendet statt eines OFFSET eine WHERE-Klausel und ist bei großen Datenmengen entsprechend performant. Für Infinite-Scroll-UIs besonders geeignet.

```php theme={null}
// orderBy ist erforderlich
$users = DB::table('users')->orderBy('id')->cursorPaginate(15);
$users = User::where('active', true)->cursorPaginate(15);
```

Statt einer Seitennummer enthält die erzeugte URL einen Cursor-String.

```
http://example.com/users?cursor=eyJpZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0
```

<Warning>
  Für Cursor-Pagination ist `orderBy` erforderlich. Zudem muss die Sortierspalte zur paginierten Tabelle gehören.
</Warning>

### OFFSET vs. Cursor

```sql theme={null}
-- paginate() / simplePaginate() — verwendet OFFSET
SELECT * FROM users ORDER BY id ASC LIMIT 15 OFFSET 15;

-- cursorPaginate() — verwendet WHERE (Index kann greifen)
SELECT * FROM users WHERE id > 15 ORDER BY id ASC LIMIT 15;
```

Cursor-Pagination nutzt Indizes effektiv und ist auch dann stabil, wenn Datensätze häufig hinzugefügt oder gelöscht werden – Duplikate oder ausgelassene Einträge sind unwahrscheinlicher. Allerdings sind nummerierte Seitenlinks nicht möglich; nur „Zurück“ und „Weiter“.

## Umsetzung im Controller

```php theme={null}
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\View\View;

class UserController extends Controller
{
    public function index(): View
    {
        $users = User::orderBy('name')->paginate(20);

        return view('users.index', compact('users'));
    }
}
```

## Pagination-Links in Blade anzeigen

```blade theme={null}
<div class="container">
    @foreach ($users as $user)
        <p>{{ $user->name }}</p>
    @endforeach

    {{-- Pagination-Links ausgeben (Tailwind CSS) --}}
    {{ $users->links() }}
</div>
```

Die Methode `links()` erzeugt automatisch das HTML für die Seitenlinks. Standardmäßig werden drei Seiten vor und nach der aktuellen Seite angezeigt.

### Anzahl der angezeigten Links anpassen

Mit `onEachSide()` legen Sie fest, wie viele Links um die aktuelle Seite herum erscheinen.

```blade theme={null}
{{-- Fünf Seiten vor und nach der aktuellen Seite --}}
{{ $users->onEachSide(5)->links() }}
```

## Anzahl pro Seite aus dem Request übernehmen

```php theme={null}
public function index(Request $request): View
{
    $perPage = $request->integer('per_page', 15);
    $perPage = min(max($perPage, 1), 100); // auf 1–100 begrenzen

    $users = User::paginate($perPage);

    return view('users.index', compact('users'));
}
```

## Mehrere Paginatoren auf einer Seite

Zeigen Sie zwei Paginatoren auf derselben Seite an, kollidiert die gemeinsame Nutzung des Parameters `page`. Über das dritte Argument können Sie den Parameternamen ändern.

```php theme={null}
$users = User::paginate(
    perPage: 15,
    columns: ['*'],
    pageName: 'users'
);

$posts = Post::paginate(
    perPage: 10,
    columns: ['*'],
    pageName: 'posts'
);
```

## URL anpassen

### Basis-URL ändern

```php theme={null}
$users = User::paginate(15);

// URLs im Format /admin/users?page=N erzeugen
$users->withPath('/admin/users');
```

### Query-Parameter anhängen

```php theme={null}
// sort=votes an jeden Seitenlink anhängen
$users->appends(['sort' => 'votes']);

// Alle Query-Parameter des aktuellen Requests übernehmen
$users->withQueryString();
```

### Hash-Fragment anhängen

```php theme={null}
// #users an das Ende der URL anhängen
$users->fragment('users');
```

## API-Antworten (JSON)

Geben Sie einen Paginator direkt aus einer Route oder einem Controller zurück, wird er automatisch in JSON umgewandelt.

```php theme={null}
use App\Models\User;

Route::get('/api/users', function () {
    return User::paginate(15);
});
```

Das JSON-Format der Antwort:

```json theme={null}
{
    "total": 50,
    "per_page": 15,
    "current_page": 1,
    "last_page": 4,
    "first_page_url": "http://example.com/api/users?page=1",
    "last_page_url": "http://example.com/api/users?page=4",
    "next_page_url": "http://example.com/api/users?page=2",
    "prev_page_url": null,
    "path": "http://example.com/api/users",
    "from": 1,
    "to": 15,
    "data": [
        { "id": 1, "name": "Max Mustermann" },
        { "id": 2, "name": "Erika Musterfrau" }
    ]
}
```

### Kombination mit API-Ressourcen

Um das Ergebnis von `paginate()` in eine API-Ressourcen-Collection zu verpacken, übergeben Sie es an `UserResource::collection()`.

```php theme={null}
use App\Http\Resources\UserResource;
use App\Models\User;

Route::get('/api/users', function () {
    $users = User::paginate(15);

    return UserResource::collection($users);
});
```

Wenn Sie an `UserResource::collection()` einen Paginator übergeben, werden die Pagination-Informationen automatisch als Metadaten ergänzt.

<Info>
  Im JSON von `cursorPaginate()` stehen statt Seitennummern die Felder `next_cursor` und `prev_cursor`. API-Clients übergeben deren Werte als `cursor`-Parameter im nächsten Request.
</Info>

## Eigene Pagination-Views

### In der View direkt angeben

```blade theme={null}
{{-- Links über eine eigene View ausgeben --}}
{{ $paginator->links('vendor.pagination.custom') }}

{{-- Zusätzliche Daten übergeben --}}
{{ $paginator->links('vendor.pagination.custom', ['theme' => 'dark']) }}
```

### Standard-View durch eigene Datei ersetzen

Veröffentlichen Sie zunächst die offiziellen Views und passen Sie sie an.

```shell theme={null}
php artisan vendor:publish --tag=laravel-pagination
```

Dabei entstehen in `resources/views/vendor/pagination/` u. a. folgende Dateien:

* `tailwind.blade.php` — Standard (für Tailwind CSS)
* `bootstrap-5.blade.php` — für Bootstrap 5
* `simple-tailwind.blade.php` — für simplePaginate
* ...

Bearbeiten Sie `tailwind.blade.php` direkt oder erstellen Sie eine neue View und geben Sie sie im `AppServiceProvider` an.

```php theme={null}
use Illuminate\Pagination\Paginator;

public function boot(): void
{
    Paginator::defaultView('vendor.pagination.custom');
    Paginator::defaultSimpleView('vendor.pagination.simple-custom');
}
```

### Bootstrap CSS verwenden

Wenn Sie statt Tailwind Bootstrap nutzen möchten, konfigurieren Sie das in der Methode `boot()` des `AppServiceProvider`.

```php theme={null}
use Illuminate\Pagination\Paginator;

public function boot(): void
{
    Paginator::useBootstrapFive(); // Bootstrap 5
    // Paginator::useBootstrapFour(); // Bootstrap 4
}
```

## Paginator manuell erstellen

Um Pagination auf bereits vorhandene Daten (z. B. Arrays) anzuwenden, instanziieren Sie eine Paginator-Klasse direkt.

```php theme={null}
use Illuminate\Pagination\LengthAwarePaginator;

$items = collect(range(1, 200))->map(fn ($i) => ['id' => $i, 'name' => "Item {$i}"]);

$perPage = 15;
$currentPage = request()->integer('page', 1);

$paginator = new LengthAwarePaginator(
    items: $items->forPage($currentPage, $perPage),
    total: $items->count(),
    perPage: $perPage,
    currentPage: $currentPage,
    options: ['path' => request()->url()]
);
```

## Häufig verwendete Instanzmethoden

```php theme={null}
$paginator = User::paginate(15);

$paginator->currentPage();     // Aktuelle Seitennummer
$paginator->lastPage();        // Letzte Seitennummer (bei simplePaginate nicht verfügbar)
$paginator->total();           // Gesamtzahl (bei simplePaginate nicht verfügbar)
$paginator->perPage();         // Anzahl pro Seite
$paginator->count();           // Anzahl auf der aktuellen Seite
$paginator->firstItem();       // Nummer des ersten Eintrags auf der aktuellen Seite
$paginator->lastItem();        // Nummer des letzten Eintrags auf der aktuellen Seite
$paginator->hasPages();        // Gibt es mehrere Seiten?
$paginator->hasMorePages();    // Gibt es eine nächste Seite?
$paginator->onFirstPage();     // Ist es die erste Seite?
$paginator->onLastPage();      // Ist es die letzte Seite?
$paginator->nextPageUrl();     // URL der nächsten Seite
$paginator->previousPageUrl(); // URL der vorherigen Seite
$paginator->url(3);            // URL von Seite 3
$paginator->items();           // Elemente der aktuellen Seite
```

## Zusammenfassung

<AccordionGroup>
  <Accordion title="Welche Pagination wählen?">
    * **`paginate()`** — wenn Gesamtzahl und nummerierte Seitenlinks nötig sind (typische Listenansichten)
    * **`simplePaginate()`** — wenn „Zurück“/„Weiter“-Links genügen (schneller)
    * **`cursorPaginate()`** — bei großen Datenmengen, Infinite Scroll oder häufigen Schreibvorgängen (beste Performance)
  </Accordion>

  <Accordion title="Blade-Ausgabe – Grundmuster">
    ```blade theme={null}
    @foreach ($users as $user)
        <p>{{ $user->name }}</p>
    @endforeach

    {{ $users->links() }}
    ```

    Übergeben Sie das Ergebnis von `paginate()` an die View und geben Sie mit `links()` die Seitenlinks aus.
    Die aktuelle Seite wird automatisch aus dem Query-Parameter `page` gelesen.
  </Accordion>

  <Accordion title="Pagination in APIs">
    Ein direkt aus einer Route zurückgegebener Paginator wird automatisch in JSON umgewandelt.
    In Kombination mit API-Ressourcen geben Sie `UserResource::collection($paginator)` zurück.
    Die Antwort enthält `data` (das Datensatz-Array) und diverse Meta-Informationen.
  </Accordion>
</AccordionGroup>


## Related topics

- [Laravel Scout](/de/scout.md)
- [⚡ Einführung in Livewire 4 – Reaktive UIs ohne JavaScript](/de/blog/livewire-introduction.md)
- [Laravel MCP](/de/mcp.md)
