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

# Context

> Come usare la funzionalità Context di Laravel per condividere informazioni tra richieste, job e comandi e aggiungerle automaticamente ai log.

## Cos'è Context

La funzionalità Context di Laravel è un meccanismo per registrare e condividere informazioni attraverso l'esecuzione di richieste, job in coda e comandi.
Le informazioni aggiunte tramite la facade `Illuminate\Support\Facades\Context` vengono aggiunte automaticamente a tutte le voci di log emesse dall'applicazione.

Ti permette di distinguere chiaramente le informazioni passate a una singola chiamata di log da quelle condivise mantenute da Context.
È particolarmente utile per tracciare sistemi distribuiti o architetture basate su code.

### Flusso di propagazione del contesto

```mermaid theme={null}
sequenceDiagram
    participant Client
    participant Middleware
    participant Controller
    participant Queue
    participant Job

    Client->>Middleware: Richiesta HTTP
    Middleware->>Middleware: Context::add('trace_id', uuid)
    Middleware->>Controller: next($request)
    Controller->>Controller: Log::info(...) — trace_id aggiunto automaticamente
    Controller->>Queue: ProcessPodcast::dispatch()
    Queue->>Job: Il contesto viene serializzato e inviato
    Job->>Job: Il contesto viene ripristinato (Hydrate)
    Job->>Job: Log::info(...) — trace_id aggiunto automaticamente
```

## Uso di base

Il caso d'uso più tipico è impostare un `trace_id` in un middleware. Verrà incluso automaticamente in tutte le voci di log successive.

<Steps>
  <Step title="Crea il middleware">
    ```shell theme={null}
    php artisan make:middleware AddContext
    ```
  </Step>

  <Step title="Aggiungi il trace ID a Context">
    ```php theme={null}
    <?php

    namespace App\Http\Middleware;

    use Closure;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Context;
    use Illuminate\Support\Str;
    use Symfony\Component\HttpFoundation\Response;

    class AddContext
    {
        public function handle(Request $request, Closure $next): Response
        {
            Context::add('url', $request->url());
            Context::add('trace_id', Str::uuid()->toString());

            return $next($request);
        }
    }
    ```
  </Step>

  <Step title="Registra il middleware">
    Registralo come middleware globale in `bootstrap/app.php`.

    ```php theme={null}
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->append(\App\Http\Middleware\AddContext::class);
    })
    ```
  </Step>
</Steps>

Dopo questa configurazione, i log scritti da controller e servizi conterranno automaticamente `url` e `trace_id`.

```php theme={null}
Log::info('User authenticated.', ['auth_id' => Auth::id()]);
```

```text theme={null}
User authenticated. {"auth_id":27} {"url":"https://example.com/login","trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697"}
```

## Scrittura nel Context

### add — aggiungere un valore

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

Context::add('key', 'value');

// Aggiungi più valori insieme
Context::add([
    'first_key'  => 'value',
    'second_key' => 'value',
]);
```

`add` sovrascrive una chiave esistente. Per aggiungere solo se non esiste usa `addIf`.

```php theme={null}
Context::add('key', 'first');
Context::addIf('key', 'second');

Context::get('key');
// "first" — non sovrascritto
```

### increment / decrement — gestione di contatori

Metodi dedicati per incrementare/decrementare valori numerici. Il secondo argomento indica la variazione.

```php theme={null}
Context::increment('records_added');
Context::increment('records_added', 5);

Context::decrement('records_added');
Context::decrement('records_added', 5);
```

### when — aggiunta condizionale

Con `when` puoi aggiungere dati diversi a seconda che la condizione sia `true` o `false`.

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

Context::when(
    Auth::user()->isAdmin(),
    fn ($context) => $context->add('permissions', Auth::user()->permissions),
    fn ($context) => $context->add('permissions', []),
);
```

### push — aggiungere a uno stack

Context supporta uno "stack" per dati in forma di elenco.
Con `push` i dati si accumulano nell'ordine in cui li aggiungi.

```php theme={null}
Context::push('breadcrumbs', 'first_value');
Context::push('breadcrumbs', 'second_value', 'third_value');

Context::get('breadcrumbs');
// ['first_value', 'second_value', 'third_value']
```

Esempio di storico di esecuzione query in uno stack.

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

// Nel metodo boot di AppServiceProvider.php
DB::listen(function ($event) {
    Context::push('queries', [$event->time, $event->sql]);
});
```

## Lettura del Context

### get / all

```php theme={null}
$value = Context::get('key');

// Prendi tutto
$data = Context::all();
```

### only / except — prendi solo alcune chiavi

```php theme={null}
$data = Context::only(['first_key', 'second_key']);

$data = Context::except(['first_key']);
```

### pull / pop — leggere ed eliminare

`pull` legge il valore e lo elimina dal Context.

```php theme={null}
$value = Context::pull('key');
```

Per estrarre l'ultimo valore da uno stack usa `pop`.

```php theme={null}
Context::push('breadcrumbs', 'first_value', 'second_value');

Context::pop('breadcrumbs');
// 'second_value'

Context::get('breadcrumbs');
// ['first_value']
```

### remember — se non esiste, imposta e restituisci

```php theme={null}
$permissions = Context::remember(
    'user-permissions',
    fn () => $user->permissions,
);
```

### has / missing — verifica dell'esistenza

```php theme={null}
if (Context::has('key')) {
    // ...
}

if (Context::missing('key')) {
    // ...
}
```

<Info>
  `has` restituisce `true` anche se il valore è `null`. Verifica solo la presenza della chiave.
</Info>

## Rimozione dal Context

Con `forget` elimini una chiave.

```php theme={null}
Context::add(['first_key' => 1, 'second_key' => 2]);

Context::forget('first_key');

Context::all();
// ['second_key' => 2]

// Elimina più chiavi insieme
Context::forget(['first_key', 'second_key']);
```

## Context con scope

Con `scope` puoi modificare temporaneamente il Context durante l'esecuzione di una closure e ripristinarlo automaticamente al termine.
Utile in test o elaborazioni locali dove vuoi aggiungere informazioni temporanee ai log.

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

Context::add('trace_id', 'abc-999');
Context::addHidden('user_id', 123);

Context::scope(
    function () {
        Context::add('action', 'adding_friend');

        $userId = Context::getHidden('user_id');

        Log::debug("Adding user [{$userId}] to friends list.");
        // Adding user [987] to friends list.  {"trace_id":"abc-999","user_name":"taylor_otwell","action":"adding_friend"}
    },
    data: ['user_name' => 'taylor_otwell'],
    hidden: ['user_id' => 987],
);

// Terminato lo scope, i valori tornano quelli originali
Context::all();
// ['trace_id' => 'abc-999']

Context::allHidden();
// ['user_id' => 123]
```

<Warning>
  Se modifichi un oggetto dentro lo scope, la modifica si riflette anche fuori. Se usi valori primitivi non c'è problema.
</Warning>

## Hidden Context

Per dati che non vuoi far apparire nei log (password, chiavi API, dati personali) usa Hidden Context.
Non sono leggibili con `get`: solo con metodi dedicati come `getHidden`.

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

Context::addHidden('key', 'value');

Context::getHidden('key');
// 'value'

Context::get('key');
// null — non è leggibile con il normale get
```

Hidden Context espone lo stesso set di metodi del Context normale.

```php theme={null}
Context::addHidden(/* ... */);
Context::addHiddenIf(/* ... */);
Context::pushHidden(/* ... */);
Context::getHidden(/* ... */);
Context::pullHidden(/* ... */);
Context::popHidden(/* ... */);
Context::onlyHidden(/* ... */);
Context::exceptHidden(/* ... */);
Context::allHidden(/* ... */);
Context::hasHidden(/* ... */);
Context::missingHidden(/* ... */);
Context::forgetHidden(/* ... */);
```

## Trasferimento ai job in coda

Quando dispatchi un job nella coda, il Context corrente viene serializzato automaticamente nel payload del job.
All'esecuzione del job il Context viene ripristinato, così il `trace_id` impostato nella richiesta viene ereditato anche nei log della coda.

```php theme={null}
// Impostato nel middleware
Context::add('trace_id', Str::uuid()->toString());

// Dispatch del job dal controller
ProcessPodcast::dispatch($podcast);
```

```php theme={null}
class ProcessPodcast implements ShouldQueue
{
    use Queueable;

    public function handle(): void
    {
        Log::info('Processing podcast.', ['podcast_id' => $this->podcast->id]);
    }
}
```

```text theme={null}
Processing podcast. {"podcast_id":95} {"url":"https://example.com/login","trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697"}
```

Il `trace_id` della richiesta compare anche nei log dei job.

### Dehydrating — personalizzare l'invio del job

Con `Context::dehydrating` puoi trasformare il Context appena prima dell'invio del job.
Ad esempio, quando vuoi passare in coda la locale determinata dall'header `Accept-Language`.

```php theme={null}
// AppServiceProvider.php

use Illuminate\Log\Context\Repository;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Context;

public function boot(): void
{
    Context::dehydrating(function (Repository $context) {
        $context->addHidden('locale', Config::get('app.locale'));
    });
}
```

<Warning>
  Nella callback `dehydrating` non usare la facade `Context`: manipola solo il repository `$context` passato come argomento.
  L'uso della facade modificherebbe il Context del processo corrente.
</Warning>

### Hydrated — ripristino all'esecuzione del job

Con `Context::hydrated` puoi eseguire logica quando il Context viene ripristinato prima dell'esecuzione del job.
Ad esempio, applica al file di configurazione la locale salvata.

```php theme={null}
// AppServiceProvider.php

use Illuminate\Log\Context\Repository;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Context;

public function boot(): void
{
    Context::hydrated(function (Repository $context) {
        if ($context->hasHidden('locale')) {
            Config::set('app.locale', $context->getHidden('locale'));
        }
    });
}
```

<Warning>
  Anche nella callback `hydrated` non usare la facade `Context`: manipola solo il repository `$context` passato.
</Warning>

## Riepilogo

<AccordionGroup>
  <Accordion title="Differenze tra Context e Log::withContext">
    |                      | `Context`                      | `Log::withContext`            |
    | -------------------- | ------------------------------ | ----------------------------- |
    | Ambito               | Tutti i canali di log          | Solo un canale specifico      |
    | Trasferimento ai job | Automatico (Dehydrate/Hydrate) | No                            |
    | Dati Hidden          | Supportati                     | No                            |
    | Uso                  | Tracing, sistemi distribuiti   | Metadati specifici del canale |
  </Accordion>

  <Accordion title="Dati adatti a Hidden Context">
    Hidden Context non compare nei log, quindi puoi memorizzare in sicurezza:

    * Session ID o user ID (se non vuoi che restino nei log)
    * Chiavi API e token di autenticazione
    * Locale o valori di configurazione (da ereditare in coda ma non necessari nei log)
    * Flag e stati interni
  </Accordion>

  <Accordion title="Pattern comuni di Dehydrate/Hydrate">
    1. **Trasferimento della locale**: in `dehydrating` salvi `app.locale` in Hidden Context; in `hydrated` la ripristini con `Config::set`.
    2. **Propagazione dell'autenticazione**: puoi far riferimento nel job alle informazioni dell'utente autenticato nella richiesta.
    3. **Tenant ID**: in app multi-tenant condividi l'identificatore di tenant attraverso la coda.
  </Accordion>
</AccordionGroup>


## Related topics

- [Logging](/it/logging.md)
- [Contesto e filtraggio della sessione](/it/packages/laravel-copilot-sdk/session-context.md)
- [Gestione degli errori](/it/error-handling.md)
- [Telemetria](/it/packages/laravel-copilot-sdk/telemetry.md)
- [Eventi di streaming](/it/packages/laravel-copilot-sdk/streaming-events.md)
