> ## 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

> Pagination Laravel : différences entre paginate(), simplePaginate() et cursorPaginate(), affichage dans Blade, réponses API et personnalisation des URL.

## Qu'est-ce que la pagination

La pagination de Laravel est intégrée au query builder et à l'ORM Eloquent : aucune configuration n'est nécessaire. La page courante est extraite automatiquement du paramètre `page` de la requête HTTP et ajoutée aux liens générés.

Le HTML par défaut est compatible avec Tailwind CSS ; Bootstrap est aussi disponible.

## Trois types de pagination

| Méthode            | Retour                 | Caractéristiques                                                 |
| ------------------ | ---------------------- | ---------------------------------------------------------------- |
| `paginate()`       | `LengthAwarePaginator` | Récupère le total. Génère des liens numérotés                    |
| `simplePaginate()` | `Paginator`            | Ne récupère pas le total. Uniquement « Précédent » / « Suivant » |
| `cursorPaginate()` | `CursorPaginator`      | Basée sur un curseur. Idéale pour de grands volumes              |

## Utilisation de base

### Pagination du query builder

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

// 15 éléments par page
$users = DB::table('users')->paginate(15);
```

### Pagination Eloquent

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

$users = User::paginate(15);

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

### simplePaginate

Si la requête `COUNT(*)` du total n'est pas nécessaire (uniquement liens « précédent »/« suivant »), utilisez `simplePaginate()` pour plus d'efficacité.

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

<Tip>
  Si vous n'avez pas besoin d'afficher « X sur Y », choisissez `simplePaginate()`. `paginate()` exécute une requête `COUNT(*)` supplémentaire, donc `simplePaginate()` est plus rapide.
</Tip>

### cursorPaginate (pagination par curseur)

La pagination par curseur remplace `OFFSET` par une clause `WHERE`, ce qui offre de bonnes performances pour de grandes quantités de données. Idéale pour les UI en défilement infini.

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

Les URL générées contiennent une chaîne de curseur au lieu d'un numéro de page.

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

<Warning>
  La pagination par curseur exige `orderBy`. De plus, la colonne d'ordre doit appartenir à la table paginée.
</Warning>

### Comparaison OFFSET vs. curseur

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

-- cursorPaginate() — utilise WHERE (bénéficie des index)
SELECT * FROM users WHERE id > 15 ORDER BY id ASC LIMIT 15;
```

La pagination par curseur exploite bien les index, et évite les doublons/oublis lorsque les données sont modifiées fréquemment. En revanche, elle ne propose pas de liens numérotés, seulement « Précédent » / « Suivant ».

## Implémentation dans un contrôleur

```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'));
    }
}
```

## Affichage des liens de pagination dans Blade

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

{{-- Affichage des liens (compatible Tailwind CSS) --}}
{{ $users->links() }}
```

La méthode `links()` génère automatiquement le HTML des liens. Par défaut, trois pages avant et trois pages après la page courante sont affichées.

### Ajuster le nombre de liens affichés

`onEachSide()` permet de modifier le nombre de liens de chaque côté.

```blade theme={null}
{{-- Affiche 5 pages de chaque côté de la page courante --}}
{{ $users->onEachSide(5)->links() }}
```

## Nombre d'éléments par page passé par la requête

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

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

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

## Plusieurs paginateurs sur la même page

Si deux paginateurs cohabitent, ils entreront en conflit sur le paramètre `page`. Renommez-le via le troisième argument.

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

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

## Personnalisation de l'URL

### Modifier l'URL de base

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

// URLs de la forme /admin/users?page=N
$users->withPath('/admin/users');
```

### Ajouter des paramètres de requête

```php theme={null}
// Ajoute sort=votes à chaque lien
$users->appends(['sort' => 'votes']);

// Reprend tous les paramètres de la requête courante
$users->withQueryString();
```

### Ajouter un fragment de hachage

```php theme={null}
// Ajoute #users à la fin des URL
$users->fragment('users');
```

## Réponse API (JSON)

Retourner un paginateur directement depuis une route ou un contrôleur le convertit automatiquement en JSON.

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

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

Format JSON de la réponse :

```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": "Taro Yamada" },
        { "id": 2, "name": "Hanako Suzuki" }
    ]
}
```

### Combinaison avec les API Resources

Pour envelopper le résultat de `paginate()` dans une collection de resource API, passez-le à `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);
});
```

Les informations de pagination sont automatiquement ajoutées comme métadonnées.

<Info>
  Le JSON de `cursorPaginate()` contient `next_cursor` et `prev_cursor` au lieu de numéros de page. Le client API doit renvoyer ces valeurs dans le paramètre `cursor` de la requête suivante.
</Info>

## Vues de pagination personnalisées

### Spécifier la vue directement

```blade theme={null}
{{-- Utilise une vue personnalisée --}}
{{ $paginator->links('vendor.pagination.custom') }}

{{-- Passer des données supplémentaires --}}
{{ $paginator->links('vendor.pagination.custom', ['theme' => 'dark']) }}
```

### Remplacer la vue par défaut

Publiez d'abord les vues officielles, puis personnalisez-les.

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

Les fichiers suivants sont générés dans `resources/views/vendor/pagination/` :

* `tailwind.blade.php` — Par défaut (Tailwind CSS)
* `bootstrap-5.blade.php` — Bootstrap 5
* `simple-tailwind.blade.php` — Pour simplePaginate
* …

Modifiez `tailwind.blade.php` ou créez une nouvelle vue et déclarez-la dans `AppServiceProvider`.

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

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

### Utiliser Bootstrap CSS

Pour utiliser Bootstrap au lieu de Tailwind, déclarez-le dans `boot()` du `AppServiceProvider`.

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

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

## Créer manuellement un paginateur

Pour paginer des données existantes (par exemple un tableau), instanciez directement la classe.

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

$items = collect(range(1, 200))->map(fn ($i) => ['id' => $i, 'name' => "Élément {$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()]
);
```

## Méthodes courantes de l'instance

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

$paginator->currentPage();     // Numéro de la page courante
$paginator->lastPage();        // Dernière page (indisponible avec simplePaginate)
$paginator->total();           // Total (indisponible avec simplePaginate)
$paginator->perPage();         // Nombre par page
$paginator->count();           // Nombre d'éléments sur la page courante
$paginator->firstItem();       // Numéro du premier élément
$paginator->lastItem();        // Numéro du dernier élément
$paginator->hasPages();        // Y a-t-il plusieurs pages ?
$paginator->hasMorePages();    // Y a-t-il une page suivante ?
$paginator->onFirstPage();     // Est-ce la première page ?
$paginator->onLastPage();      // Est-ce la dernière page ?
$paginator->nextPageUrl();     // URL de la page suivante
$paginator->previousPageUrl(); // URL de la page précédente
$paginator->url(3);            // URL de la page 3
$paginator->items();           // Tableau des éléments de la page courante
```

## Récapitulatif

<AccordionGroup>
  <Accordion title="Choix du type de pagination">
    * **`paginate()`** — Quand vous avez besoin du total et des liens numérotés (liste standard).
    * **`simplePaginate()`** — Quand « Précédent » / « Suivant » suffit (plus rapide).
    * **`cursorPaginate()`** — Grands volumes, défilement infini, écritures fréquentes (meilleures performances).
  </Accordion>

  <Accordion title="Pattern d'affichage Blade">
    ```blade theme={null}
    @foreach ($users as $user)
        <p>{{ $user->name }}</p>
    @endforeach

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

    Passez le résultat de `paginate()` à la vue et affichez les liens avec `links()`.
    La page courante est détectée automatiquement via le paramètre `page`.
  </Accordion>

  <Accordion title="Pagination pour une API">
    Retourner directement un paginateur produit du JSON automatiquement.
    Combinez avec une API resource via `UserResource::collection($paginator)`.
    La réponse contient `data` (tableau des enregistrements) et diverses métadonnées.
  </Accordion>
</AccordionGroup>


## Related topics

- [Laravel Scout](/fr/scout.md)
- [Guide de mise à niveau de Laravel 12 vers 13](/fr/blog/upgrade-12-to-13.md)
- [Laravel MCP](/fr/mcp.md)
- [Eloquent API Resources](/fr/eloquent-resources.md)
- [⚡Introduction à Livewire 4 — créer des UI réactives sans JavaScript](/fr/blog/livewire-introduction.md)
