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

# Illuminate\Support\Manager — anatomia del sistema di driver

> La classe centrale del sistema di driver in uso da Laravel 4.0. Dalla registrazione di driver personalizzati a MultipleInstanceManager.

## Cos'è Manager

`Illuminate\Support\Manager` è una classe astratta presente fin da Laravel 4.0. Fornisce la base per costruire facilmente sistemi in cui è possibile alternare più "driver" — per cache, sessioni, mail e altro.

Un "driver" è un backend che espone la stessa interfaccia ma cambia implementazione internamente. Per la sessione, ad esempio, esistono i driver `file`, `cookie`, `database`, `redis`, e si commuta tramite la chiave `driver` del file di configurazione.

```mermaid theme={null}
classDiagram
    class Manager {
        <<abstract>>
        #container
        #config
        #customCreators[]
        #drivers[]
        +driver(name) mixed
        +extend(driver, Closure) self
        +getDrivers() array
        +forgetDrivers() self
        +getDefaultDriver()* string
        #createDriver(driver) mixed
        #callCustomCreator(driver) mixed
    }

    class SessionManager {
        +getDefaultDriver() string
        #createFileDriver() Store
        #createDatabaseDriver() Store
        #createRedisDriver() Store
        #createArrayDriver() Store
    }

    class YourCustomManager {
        +getDefaultDriver() string
        #createFooDriver() mixed
        #createBarDriver() mixed
    }

    Manager <|-- SessionManager
    Manager <|-- YourCustomManager
```

## Come è utilizzato nel framework

Ci sono classi che hanno "Manager" nel nome ma **non** ereditano da `Illuminate\Support\Manager`.

| Classe                               | Estende `Manager`?             |
| ------------------------------------ | ------------------------------ |
| `Illuminate\Session\SessionManager`  | ✅ Sì                           |
| `Illuminate\Cache\CacheManager`      | ❌ No (implementazione propria) |
| `Illuminate\Queue\QueueManager`      | ❌ No (implementazione propria) |
| `Laravel\Socialite\SocialiteManager` | ✅ Sì                           |

Le classi che non estendono `Manager` condividono comunque l'idea di base di estendersi tramite `extend()`. Comprendere il pattern `Manager` aiuta quindi a capire il funzionamento di tutto il framework.

## Meccanismo di base

### driver() — ottenere un driver

Chiamando `driver()`, il driver viene risolto secondo questi passaggi.

```mermaid theme={null}
flowchart TD
    A["Chiama driver(name)"] --> B{"drivers[] contiene<br>una cache?"}
    B -- sì --> C["Restituisce<br>l'istanza in cache"]
    B -- no --> D{"customCreators[]<br>ha una registrazione?"}
    D -- sì --> E["Crea l'istanza con<br>callCustomCreator()"]
    D -- no --> F{"Il metodo<br>createXxxDriver() esiste?"}
    F -- sì --> G["Chiama<br>createXxxDriver()"]
    F -- no --> H["Solleva<br>InvalidArgumentException"]
    E --> I["Mette in cache in drivers[] e restituisce"]
    G --> I
```

Nel codice sorgente vedi che il nome del metodo viene composto dal nome del driver con `Str::studly()`.

```php theme={null}
// da Illuminate\Support\Manager::createDriver()
protected function createDriver($driver)
{
    if (isset($this->customCreators[$driver])) {
        return $this->callCustomCreator($driver);
    }

    $method = 'create'.Str::studly($driver).'Driver';

    if (method_exists($this, $method)) {
        return $this->$method();
    }

    throw new InvalidArgumentException("Driver [$driver] not supported.");
}
```

Quindi al driver `file` corrisponde `createFileDriver()`, al driver `my-custom` corrisponde `createMyCustomDriver()`.

### extend() — registrare un driver personalizzato

Passando a `extend()` un nome di driver e una closure, puoi registrare un driver personalizzato. L'argomento della closure è l'istanza del container.

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

Session::extend('redis-cluster', function ($app) {
    return new RedisClusterSessionHandler(
        $app->make('redis'),
        $app['config']['session'],
    );
});
```

`extend()` collega la closure a `$this`, quindi all'interno della closure puoi accedere alle proprietà e ai metodi del Manager.

```php theme={null}
// da Illuminate\Support\Manager::extend()
public function extend($driver, Closure $callback)
{
    try {
        $callback = $callback->bindTo($this, static::class) ?? throw new RuntimeException;
    } catch (Throwable) {
        $callback = $callback->bindTo(null, static::class);
    }

    $this->customCreators[$driver] = $callback;

    return $this;
}
```

### \_\_call — delega al driver di default

La classe `Manager` implementa `__call`: le chiamate a metodi che non esistono sul Manager stesso vengono automaticamente delegate al driver di default.

```php theme={null}
public function __call($method, $parameters)
{
    return $this->driver()->$method(...$parameters);
}
```

Così `SessionManager::get('key')` usa direttamente il Manager, ma l'elaborazione effettiva è a carico del driver.

## Esempio: implementazione di SessionManager

Guardando `Illuminate\Session\SessionManager` si capisce concretamente come si usa `Manager`.

```php theme={null}
namespace Illuminate\Session;

use Illuminate\Support\Manager;

class SessionManager extends Manager
{
    // richiesto: restituisce il driver di default
    public function getDefaultDriver()
    {
        return $this->config->get('session.driver');
    }

    // creazione del driver file
    protected function createFileDriver()
    {
        return $this->createNativeDriver();
    }

    // creazione del driver database
    protected function createDatabaseDriver()
    {
        $table = $this->config->get('session.table');
        $lifetime = $this->config->get('session.lifetime');

        return $this->buildSession(new DatabaseSessionHandler(
            $this->getDatabaseConnection(), $table, $lifetime, $this->container
        ));
    }

    // creazione del driver redis
    protected function createRedisDriver()
    {
        $handler = $this->createCacheHandler('redis');
        // ...
        return $this->buildSession($handler);
    }
}
```

## Usare Manager in un pacchetto proprio

### Implementazione di base

Come esempio, creiamo una classe personalizzata che estende `Manager` per un servizio di notifica.

<Steps>
  <Step title="Creare la classe che estende Manager">
    ```php theme={null}
    namespace App\Notifications;

    use Illuminate\Support\Manager;

    class NotificationManager extends Manager
    {
        public function getDefaultDriver(): string
        {
            return $this->config->get('notifications.driver', 'slack');
        }

        protected function createSlackDriver(): SlackNotifier
        {
            return new SlackNotifier(
                $this->config->get('notifications.slack'),
            );
        }

        protected function createEmailDriver(): EmailNotifier
        {
            return new EmailNotifier(
                $this->config->get('notifications.email'),
            );
        }

        protected function createLogDriver(): LogNotifier
        {
            return new LogNotifier(
                $this->container->make('log'),
            );
        }
    }
    ```
  </Step>

  <Step title="Registrare nel service provider">
    ```php theme={null}
    namespace App\Providers;

    use App\Notifications\NotificationManager;
    use Illuminate\Support\ServiceProvider;

    class NotificationServiceProvider extends ServiceProvider
    {
        public function register(): void
        {
            $this->app->singleton(NotificationManager::class, function ($app) {
                return new NotificationManager($app);
            });
        }
    }
    ```
  </Step>

  <Step title="Aggiungere un driver personalizzato">
    ```php theme={null}
    // in AppServiceProvider::boot() o simile

    $manager = app(NotificationManager::class);

    $manager->extend('teams', function ($app) {
        return new TeamsNotifier(
            $app['config']['notifications.teams'],
        );
    });
    ```
  </Step>

  <Step title="Utilizzare">
    ```php theme={null}
    $manager = app(NotificationManager::class);

    // usa il driver di default
    $manager->send('messaggio');

    // specifica un driver
    $manager->driver('email')->send('messaggio');

    // il driver risolto una volta viene messo in cache
    $manager->driver('slack'); // restituisce la stessa istanza
    ```
  </Step>
</Steps>

## MultipleInstanceManager

`Illuminate\Support\MultipleInstanceManager` è una classe introdotta in Laravel 10. Mentre `Manager` gestisce "tipi" di driver, `MultipleInstanceManager` gestisce più "istanze" con nome.

### Differenze rispetto a Manager

|                                  | `Manager`                              | `MultipleInstanceManager`                     |
| -------------------------------- | -------------------------------------- | --------------------------------------------- |
| Unità di gestione                | Tipo di driver (`file`, `redis`, ecc.) | Istanza con nome (`mailer1`, `mailer2`, ecc.) |
| Modo di tenere la configurazione | Un unico driver di default             | Configurazione per singola istanza            |
| Usi principali                   | Sessione, cache, ecc.                  | Mail, log e altro con più connessioni         |
| Metodo di accesso                | `driver()`                             | `instance()`                                  |

### Metodi obbligatori

Estendendo `MultipleInstanceManager` devi implementare tre metodi.

```php theme={null}
// dal codice sorgente
abstract public function getDefaultInstance();
abstract public function setDefaultInstance($name);
abstract public function getInstanceConfig($name);
```

`getInstanceConfig()` restituisce l'array di configurazione associato al nome. La configurazione deve sempre includere `driver` (o la chiave indicata da `$driverKey`).

### Flusso di risoluzione

```mermaid theme={null}
flowchart TD
    A["Chiama instance(name)"] --> B["Se name è null<br>usa getDefaultInstance()"]
    B --> C{"instances[] contiene<br>una cache?"}
    C -- sì --> D["Restituisce<br>l'istanza in cache"]
    C -- no --> E["Ottieni configurazione con getInstanceConfig(name)"]
    E --> F{"La config contiene<br>la chiave driver?"}
    F -- no --> G["Solleva RuntimeException"]
    F -- sì --> H{"customCreators[]<br>ha una registrazione?"}
    H -- sì --> I["Crea con callCustomCreator(config)"]
    H -- no --> J["Chiama createXxxDriver(config)"]
    I --> K["Mette in cache in instances[] e restituisce"]
    J --> K
```

### Esempio di implementazione in un pacchetto proprio

Prendiamo come esempio un pacchetto che supporta contemporaneamente più gateway SMS.

```php theme={null}
namespace App\Sms;

use Illuminate\Support\MultipleInstanceManager;

class SmsManager extends MultipleInstanceManager
{
    // nome dell'istanza di default
    public function getDefaultInstance(): string
    {
        return $this->config->get('sms.default', 'primary');
    }

    public function setDefaultInstance($name): void
    {
        $this->config->set('sms.default', $name);
    }

    // restituisce la configurazione associata al nome
    public function getInstanceConfig($name): array
    {
        return $this->config->get("sms.gateways.{$name}");
    }

    // creazione del driver twilio (riceve un array di configurazione)
    protected function createTwilioDriver(array $config): TwilioSmsGateway
    {
        return new TwilioSmsGateway(
            $config['account_sid'],
            $config['auth_token'],
        );
    }

    // creazione del driver vonage
    protected function createVonageDriver(array $config): VonageSmsGateway
    {
        return new VonageSmsGateway(
            $config['api_key'],
            $config['api_secret'],
        );
    }
}
```

File di configurazione corrispondente:

```php theme={null}
// config/sms.php
return [
    'default' => 'primary',

    'gateways' => [
        'primary' => [
            'driver' => 'twilio',
            'account_sid' => env('TWILIO_ACCOUNT_SID'),
            'auth_token' => env('TWILIO_AUTH_TOKEN'),
        ],
        'backup' => [
            'driver' => 'vonage',
            'api_key' => env('VONAGE_API_KEY'),
            'api_secret' => env('VONAGE_API_SECRET'),
        ],
        'marketing' => [
            'driver' => 'twilio',
            'account_sid' => env('TWILIO_MARKETING_SID'),
            'auth_token' => env('TWILIO_MARKETING_TOKEN'),
        ],
    ],
];
```

In fase di utilizzo indichi il nome con `instance()`.

```php theme={null}
$sms = app(SmsManager::class);

// usa l'istanza di default (primary = twilio)
$sms->send('+3934xxxxxxx', 'Codice di conferma: 123456');

// indica un'istanza per nome
$sms->instance('backup')->send('+3934xxxxxxx', 'Codice di conferma: 123456');

// usa l'istanza dedicata al marketing
$sms->instance('marketing')->send('+3934xxxxxxx', 'Novità della campagna');
```

<Tip>
  `MultipleInstanceManager`, come `Manager`, permette di aggiungere driver personalizzati con `extend()`. Implementa anche `__call`, quindi i metodi assenti sull'istanza vengono delegati a quella di default.
</Tip>

## Gestione della cache dei driver

### Operazioni di cache in Manager

```php theme={null}
// ottieni tutti i driver
$drivers = $manager->getDrivers();

// pulisci la cache di tutti i driver
$manager->forgetDrivers();
```

### Operazioni di cache in MultipleInstanceManager

```php theme={null}
// elimina un'istanza specifica
$manager->forgetInstance('backup');

// elimina l'istanza di default
$manager->forgetInstance();

// elimina più istanze in blocco
$manager->forgetInstance(['primary', 'backup']);

// elimina un'istanza pulendo anche la cache
$manager->purge('backup');
```

## Riepilogo

* `Manager` gestisce i "tipi" di driver. Implementi i metodi `createXxxDriver()` ed estendi con `extend()`
* `MultipleInstanceManager` gestisce le "istanze" di driver per nome. È adatto a pacchetti che richiedono più configurazioni di connessione
* Non tutte le classi chiamate `Manager` estendono `Illuminate\Support\Manager`. `CacheManager` e `QueueManager` sono implementazioni indipendenti

<Card title="Trait Macroable" icon="puzzle-piece" href="/it/advanced/macroable">
  Impara come aggiungere metodi personalizzati alle classi esistenti con il trait Macroable.
</Card>


## Related topics

- [Laravel Sentinel — indagine sul middleware di protezione delle rotte](/it/blog/sentinel-introduction.md)
- [Implementare un guard di autenticazione personalizzato](/it/advanced/custom-auth-guard.md)
- [Guida all'aggiornamento da Laravel 12 a 13](/it/blog/upgrade-12-to-13.md)
- [Laravel Chisel — libreria di script post-installazione per starter kit](/it/blog/chisel-introduction.md)
- [Il nuovo ecosistema di analisi del codice Laravel — surveyor / ranger / roster](/it/blog/laravel-ecosystem-analysis.md)
