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

# Collezioni

> Come manipolare i dati in modo efficiente con la classe Collection di Laravel.

## Cosa sono le Collection

`Illuminate\Support\Collection` è un wrapper fluido per array di dati.
Invece di chiamare separatamente le funzioni array di PHP, con una catena di metodi trasformi i dati in modo intuitivo.

```php theme={null}
// Con funzioni array
$names = array_filter(
    array_map(fn ($user) => $user['name'], $users),
    fn ($name) => $name !== null
);

// Con Collection
$names = collect($users)
    ->pluck('name')
    ->filter()
    ->values();
```

<Info>
  Le Collection sono **immutabili**. Ogni metodo restituisce una nuova istanza senza modificare l'originale.
</Info>

## Creazione delle Collection

### Helper `collect()`

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

$users = collect([
    ['name' => 'Mario Rossi', 'age' => 28, 'role' => 'admin'],
    ['name' => 'Giulia Bianchi', 'age' => 34, 'role' => 'editor'],
    ['name' => 'Luca Verdi', 'age' => 22, 'role' => 'viewer'],
]);
```

### `Collection::make()`

```php theme={null}
$collection = Collection::make([1, 2, 3]);
```

### `Collection::fromJson()`

```php theme={null}
$collection = Collection::fromJson('[{"name":"Mario"},{"name":"Giulia"}]');
```

## Metodi più usati

### `map` — trasforma ogni elemento

```php theme={null}
$users = collect([
    ['name' => 'Mario Rossi', 'email' => 'mario@example.com'],
    ['name' => 'Giulia Bianchi', 'email' => 'giulia@example.com'],
]);

$masked = $users->map(function (array $user) {
    $parts = explode('@', $user['email']);
    return [
        'name' => $user['name'],
        'email' => substr($parts[0], 0, 2) . '***@' . $parts[1],
    ];
});
```

### `filter` / `reject`

```php theme={null}
$products = collect([
    ['name' => 'Laptop', 'price' => 1200, 'in_stock' => true],
    ['name' => 'Mouse', 'price' => 35, 'in_stock' => false],
    ['name' => 'Tastiera', 'price' => 80, 'in_stock' => true],
]);

// Solo disponibili
$inStock = $products->filter(fn ($product) => $product['in_stock']);

// Escludi i non disponibili
$available = $products->reject(fn ($product) => ! $product['in_stock']);

// filter() senza argomenti rimuove i valori falsy
$names = collect(['Mario', '', null, 'Giulia', false])->filter()->values();
// ['Mario', 'Giulia']
```

<Tip>
  Dopo `filter()` gli indici possono avere "buchi". Chiama `values()` per riottenere una sequenza da 0.
</Tip>

### `first` / `last`

```php theme={null}
$orders = collect([
    ['id' => 1, 'status' => 'shipped', 'amount' => 50],
    ['id' => 2, 'status' => 'pending', 'amount' => 120],
    ['id' => 3, 'status' => 'pending', 'amount' => 35],
]);

$nextOrder = $orders->first(fn ($order) => $order['status'] === 'pending');
$order = $orders->first(fn ($order) => $order['status'] === 'cancelled', null);
$latest = $orders->last();
```

### `pluck`

```php theme={null}
$users = collect([
    ['id' => 1, 'name' => 'Mario', 'department' => 'Sviluppo'],
    ['id' => 2, 'name' => 'Giulia', 'department' => 'Vendite'],
]);

$names = $users->pluck('name');           // ['Mario', 'Giulia']
$nameById = $users->pluck('name', 'id');  // [1 => 'Mario', 2 => 'Giulia']
```

### `groupBy`

```php theme={null}
$byDepartment = $users->groupBy('department');

$byFirstChar = $users->groupBy(fn ($user) => mb_substr($user['name'], 0, 1));
```

### `sortBy` / `sortByDesc`

```php theme={null}
$cheapFirst = $products->sortBy('price');
$expensiveFirst = $products->sortByDesc('price');

$sorted = $products->sortBy([
    ['price', 'asc'],
    ['name', 'asc'],
]);
```

### `each` — esegui su ogni elemento

```php theme={null}
$orders->each(function (array $order) {
    \Log::info("Processing #{$order['id']}", ['amount' => $order['amount']]);
});

// Restituendo false esci dal ciclo
$orders->each(function (array $order) {
    if ($order['amount'] > 100) {
        return false;
    }
});
```

### `flatMap`

```php theme={null}
$users = collect([
    ['name' => 'Mario', 'tags' => ['php', 'laravel']],
    ['name' => 'Giulia', 'tags' => ['javascript', 'vue']],
]);

$allTags = $users->flatMap(fn ($user) => $user['tags']);
// ['php', 'laravel', 'javascript', 'vue']
```

### `reduce` — aggrega

```php theme={null}
$total = $orders->reduce(
    fn ($carry, $order) => $carry + ($order['price'] * $order['quantity']),
    0
);
```

<Tip>
  Per somme semplici puoi usare `sum()`.
</Tip>

### `reduceInto` — aggrega su oggetto

Simile a `reduce`, ma la callback non deve restituire nulla. Utile per modificare direttamente un oggetto.

```php theme={null}
class OrderStats
{
    public int $total = 0;
    public int $count = 0;
}

$stats = $orders->reduceInto(new OrderStats, function (OrderStats $stats, array $order) {
    $stats->total += $order['amount'];
    $stats->count++;
});
```

Per accumulare su array/scalari usa il passaggio per riferimento.

```php theme={null}
$even = $collection->reduceInto([], function (array &$result, int $value) {
    if ($value % 2 === 0) {
        $result[] = $value;
    }
});
```

### `chunk` — dividi in batch

```php theme={null}
$users = collect(range(1, 100))->map(fn ($i) => ['id' => $i, 'name' => "Utente {$i}"]);

$chunks = $users->chunk(10);

$chunks->each(function (\Illuminate\Support\Collection $batch) {
    // Elabora il batch
});
```

## Concatenazione dei metodi

```php theme={null}
$result = $orders
    ->filter(fn ($order) => $order['status'] === 'completed')
    ->filter(fn ($order) => $order['category'] === 'elettronica')
    ->sortByDesc('amount')
    ->map(fn ($order) => [
        'customer' => $order['customer'],
        'amount'   => number_format($order['amount']) . ' EUR',
    ])
    ->values();
```

## Integrazione con Eloquent

I risultati delle query Eloquent sono sempre istanze di `Illuminate\Database\Eloquent\Collection`, che estende `Collection`.

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

$users = User::where('is_active', true)->get(); // Collection

$adminEmails = User::all()
    ->filter(fn ($user) => $user->role === 'admin')
    ->pluck('email');

$orders = Order::with('items')->where('status', 'completed')->get();

$summary = $orders->map(fn ($order) => [
    'id'         => $order->id,
    'customer'   => $order->user->name,
    'item_count' => $order->items->count(),
    'total'      => $order->items->sum('price'),
]);
```

<Warning>
  Fai filtri e ordinamenti dove possono essere fatti dal DB (con query builder), non con le Collection: altrimenti carichi in memoria dati inutili.
</Warning>

### Metodi specifici di `Eloquent\Collection`

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

$user = $users->find(1);
$ids = $users->modelKeys();
$users->load('orders', 'profile');
$diff = $users->diff($otherUsers);
$intersect = $users->intersect($otherUsers);
```

## Lazy Collection

Le Collection normali caricano tutti i dati in memoria. `LazyCollection` usa i generator PHP per processare un elemento alla volta. Utile con decine di migliaia di record.

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

// In memoria tutto
$users = User::all();

// Uno alla volta
User::cursor()->each(function (User $user) {
    // In memoria un utente per volta
});
```

### Creare una LazyCollection

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

$lazy = LazyCollection::make(function () {
    $handle = fopen('large-file.csv', 'r');

    while (($line = fgetcsv($handle)) !== false) {
        yield $line;
    }

    fclose($handle);
});

$lazy = User::where('is_active', true)->cursor();
```

### Batch di grandi volumi

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

Order::cursor()
    ->filter(fn ($order) => $order->amount > 100)
    ->each(fn ($order) => $order->sendConfirmationEmail());

Order::where('status', 'completed')
    ->cursor()
    ->filter(fn ($order) => $order->amount > 100)
    ->each(fn ($order) => $order->sendConfirmationEmail());
```

<Info>
  `cursor()` recupera un record alla volta dal DB, risparmiando memoria; la connessione al DB resta aperta fino alla fine.
</Info>

### Paginazione con `take` e `skip`

```php theme={null}
$lazy = LazyCollection::make(function () {
    foreach (range(1, 1000000) as $i) {
        yield $i;
    }
});

$page = $lazy->skip(1000)->take(100)->values();
```

## Riepilogo

<AccordionGroup>
  <Accordion title="Metodi più usati">
    | Metodo                        | Descrizione                      |
    | ----------------------------- | -------------------------------- |
    | `collect($array)`             | Crea una Collection              |
    | `map($callback)`              | Trasforma ogni elemento          |
    | `filter($callback)`           | Filtra                           |
    | `reject($callback)`           | Esclude                          |
    | `first($callback)`            | Primo che soddisfa la condizione |
    | `pluck($key)`                 | Estrai una chiave                |
    | `groupBy($key)`               | Raggruppa                        |
    | `sortBy($key)`                | Ordina crescente                 |
    | `sortByDesc($key)`            | Ordina decrescente               |
    | `each($callback)`             | Esegui per ogni elemento         |
    | `flatMap($callback)`          | Mappa e appiattisci              |
    | `reduce($callback, $initial)` | Aggrega in un valore             |
    | `chunk($size)`                | Suddividi                        |
    | `values()`                    | Rinumera indici                  |
    | `sum($key)`                   | Somma                            |
    | `count()`                     | Conta                            |
  </Accordion>

  <Accordion title="Collection vs funzioni array">
    Le Collection migliorano molto la leggibilità.

    ```php theme={null}
    // Con funzioni array
    $result = array_values(array_filter(
        array_map(fn ($u) => $u['name'], $users),
        fn ($name) => strlen($name) > 2
    ));

    // Con Collection
    $result = collect($users)
        ->pluck('name')
        ->filter(fn ($name) => strlen($name) > 2)
        ->values()
        ->all();
    ```
  </Accordion>

  <Accordion title="Collection vs LazyCollection">
    * **Collection**: centinaia/migliaia di record, semplice.
    * **LazyCollection**: decine di migliaia, memoria contenuta; combinala con `cursor()`.
    * `get()` restituisce una Collection, `cursor()` una LazyCollection.
  </Accordion>
</AccordionGroup>


## Related topics

- [Collezioni Eloquent](/it/eloquent-collections.md)
- [WebSocket (Jetstream / Firehose)](/it/packages/laravel-bluesky/websocket.md)
- [Collection Deep Dive](/it/advanced/collection-deep-dive.md)
- [Serializzazione Eloquent](/it/eloquent-serialization.md)
