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

# Paginazione

> Illustra la funzionalità di paginazione di Laravel. Copre le differenze tra paginate(), simplePaginate() e cursorPaginate(), la visualizzazione in Blade, la risposta API e la personalizzazione degli URL.

## Cos'è la paginazione

La paginazione di Laravel è integrata con Query Builder ed Eloquent ORM e si può usare senza configurazioni. La pagina corrente viene letta automaticamente dal parametro di query `page` della richiesta HTTP e aggiunta automaticamente ai link generati.

L'HTML predefinito è compatibile con Tailwind CSS; puoi scegliere anche Bootstrap CSS.

## Tre tipi di paginazione

| Metodo             | Ritorno                | Caratteristiche                                          |
| ------------------ | ---------------------- | -------------------------------------------------------- |
| `paginate()`       | `LengthAwarePaginator` | Recupera il totale. Genera link ai numeri di pagina      |
| `simplePaginate()` | `Paginator`            | Non recupera il totale. Solo "precedente" e "successivo" |
| `cursorPaginate()` | `CursorPaginator`      | Basato su cursore. Ideale per grandi volumi di dati      |

## Uso di base

### Paginazione con Query Builder

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

// Recupera 15 elementi per pagina
$users = DB::table('users')->paginate(15);
```

### Paginazione con Eloquent

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

$users = User::paginate(15);

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

### simplePaginate

Quando non serve la query di conteggio totale (mostri solo i link "precedente" e "successivo"), è più efficiente usare `simplePaginate()`.

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

<Tip>
  Se non ti serve mostrare "elemento N di M totali", scegli `simplePaginate()`. `paginate()` esegue una query `COUNT(*)` aggiuntiva, quindi `simplePaginate()` è più veloce.
</Tip>

### cursorPaginate (paginazione a cursore)

La paginazione a cursore usa una clausola WHERE al posto di OFFSET, offrendo prestazioni elevate su grandi volumi di dati. Particolarmente adatta a UI a scroll infinito.

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

Gli URL generati contengono una stringa di cursore invece del numero di pagina.

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

<Warning>
  Per usare la paginazione a cursore è obbligatorio `orderBy`. Inoltre, la colonna di ordinamento deve appartenere alla tabella oggetto della paginazione.
</Warning>

### Confronto tra OFFSET e cursore

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

-- cursorPaginate() — usa una clausola WHERE (l'indice viene sfruttato)
SELECT * FROM users WHERE id > 15 ORDER BY id ASC LIMIT 15;
```

La paginazione a cursore sfrutta gli indici in modo efficace e riduce il rischio di duplicazioni o omissioni di record anche in presenza di inserimenti e cancellazioni frequenti. Non genera però link ai singoli numeri di pagina: solo "precedente" e "successivo".

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

## Visualizzazione dei link di paginazione in Blade

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

{{-- Emette i link di paginazione (compatibili con Tailwind CSS) --}}
{{ $users->links() }}
```

Il metodo `links()` genera automaticamente l'HTML dei link. Vengono mostrati i link alle 3 pagine prima e dopo la pagina corrente.

### Regolare il numero di link mostrati

Con `onEachSide()` puoi cambiare il numero di link mostrati prima e dopo la pagina corrente.

```blade theme={null}
{{-- Mostra 5 pagine prima e 5 dopo quella corrente --}}
{{ $users->onEachSide(5)->links() }}
```

## Ricevere dalla richiesta il numero di elementi per pagina

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

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

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

## Mostrare più paginator nella stessa pagina

Se hai due paginator sulla stessa schermata, entrambi usano il parametro `page` andando in conflitto. Cambia il nome del parametro con il terzo argomento.

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

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

## Personalizzazione degli URL

### Cambiare l'URL base

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

// Genera URL nel formato /admin/users?page=N
$users->withPath('/admin/users');
```

### Aggiungere parametri di query

```php theme={null}
// Aggiunge sort=votes a ogni link di pagina
$users->appends(['sort' => 'votes']);

// Eredita tutti i parametri di query della richiesta corrente
$users->withQueryString();
```

### Aggiungere un frammento hash

```php theme={null}
// Aggiunge #users in fondo agli URL
$users->fragment('users');
```

## Risposta API (output JSON)

Restituendo il paginator direttamente da una route o controller, viene convertito automaticamente in JSON.

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

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

Formato JSON della risposta:

```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": "Mario Rossi" },
        { "id": 2, "name": "Giulia Bianchi" }
    ]
}
```

### Combinazione con le API resource

Per incapsulare il risultato di `paginate()` in una API resource collection, passalo a `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);
});
```

Passando il paginator a `UserResource::collection()`, le informazioni di paginazione vengono aggiunte automaticamente come metadati.

<Info>
  Nel JSON di `cursorPaginate()` non ci sono numeri di pagina ma `next_cursor` e `prev_cursor`. Il client API usa questi valori come parametro `cursor` della richiesta successiva.
</Info>

## Viste di paginazione personalizzate

### Specificare direttamente il file della vista

```blade theme={null}
{{-- Emette i link usando una vista personalizzata --}}
{{ $paginator->links('vendor.pagination.custom') }}

{{-- Passa dati aggiuntivi --}}
{{ $paginator->links('vendor.pagination.custom', ['theme' => 'dark']) }}
```

### Cambiare la vista predefinita con un file personalizzato

Pubblica prima le viste ufficiali e poi personalizzale.

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

In `resources/views/vendor/pagination/` vengono generati i seguenti file:

* `tailwind.blade.php` — predefinito (per Tailwind CSS)
* `bootstrap-5.blade.php` — per Bootstrap 5
* `simple-tailwind.blade.php` — per simplePaginate
* ...

Modifica direttamente `tailwind.blade.php` oppure crea una nuova vista e indicala in `AppServiceProvider`.

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

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

### Usare Bootstrap CSS

Se al posto di Tailwind usi Bootstrap, configuralo in `boot()` di `AppServiceProvider`.

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

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

## Creazione manuale di un paginator

Se vuoi paginare dati esistenti come un array, istanzia direttamente la classe paginator.

```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()]
);
```

## Metodi d'istanza comuni

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

$paginator->currentPage();     // Numero di pagina corrente
$paginator->lastPage();        // Numero dell'ultima pagina (non disponibile con simplePaginate)
$paginator->total();           // Totale (non disponibile con simplePaginate)
$paginator->perPage();         // Elementi per pagina
$paginator->count();           // Elementi nella pagina corrente
$paginator->firstItem();       // Indice del primo elemento della pagina corrente
$paginator->lastItem();        // Indice dell'ultimo elemento della pagina corrente
$paginator->hasPages();        // Se esistono più pagine
$paginator->hasMorePages();    // Se esiste una pagina successiva
$paginator->onFirstPage();     // Se è la prima pagina
$paginator->onLastPage();      // Se è l'ultima pagina
$paginator->nextPageUrl();     // URL della pagina successiva
$paginator->previousPageUrl(); // URL della pagina precedente
$paginator->url(3);            // URL della pagina 3
$paginator->items();           // Array degli elementi della pagina corrente
```

## Riepilogo

<AccordionGroup>
  <Accordion title="Come scegliere il metodo di paginazione">
    * **`paginate()`** — Quando servono totale e link ai numeri di pagina (schermate a lista comuni)
    * **`simplePaginate()`** — Quando bastano i soli link "precedente" e "successivo" (più veloce)
    * **`cursorPaginate()`** — Con grandi volumi di dati, scroll infinito o scritture frequenti (massime prestazioni)
  </Accordion>

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

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

    Passa il risultato di `paginate()` alla vista e usa `links()` per emettere i link alle pagine.
    La pagina corrente viene rilevata automaticamente dal parametro di query `page`.
  </Accordion>

  <Accordion title="Paginazione nelle API">
    Restituendo direttamente il paginator dalla route, viene convertito automaticamente in JSON.
    Per combinarlo con le API resource restituisci `UserResource::collection($paginator)`.
    La risposta contiene `data` (array di record) e vari metadati.
  </Accordion>
</AccordionGroup>


## Related topics

- [Laravel Scout](/it/scout.md)
- [Guida all'aggiornamento da Laravel 12 a 13](/it/blog/upgrade-12-to-13.md)
- [Eloquent API Resource](/it/eloquent-resources.md)
- [Laravel MCP](/it/mcp.md)
- [⚡Introduzione a Livewire 4 — creare UI reattive senza JavaScript](/it/blog/livewire-introduction.md)
