> ## 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 — anatomie du système de drivers

> La classe cœur du système de drivers présent depuis Laravel 4.0. De l'enregistrement d'un driver personnalisé jusqu'au MultipleInstanceManager.

## Qu'est-ce que Manager

`Illuminate\Support\Manager` est une classe abstraite présente depuis Laravel 4.0. Elle fournit les fondations permettant de construire simplement un système capable de basculer entre plusieurs « drivers », comme le cache, la session ou le mail.

Un « driver » est un backend qui présente la même interface mais dont l'implémentation interne diffère. Par exemple, pour la session, on trouve les drivers `file`, `cookie`, `database` ou `redis`, sélectionnés via la clé `driver` du fichier de configuration.

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

## Utilisation dans le framework

Toutes les classes appelées `Manager` **n'héritent pas** de `Illuminate\Support\Manager`.

| Classe                               | Hérite-t-elle de `Manager` ?  |
| ------------------------------------ | ----------------------------- |
| `Illuminate\Session\SessionManager`  | ✅ Oui                         |
| `Illuminate\Cache\CacheManager`      | ❌ Non (implémentation dédiée) |
| `Illuminate\Queue\QueueManager`      | ❌ Non (implémentation dédiée) |
| `Laravel\Socialite\SocialiteManager` | ✅ Oui                         |

Les classes qui n'en héritent pas suivent tout de même la même logique fondamentale d'extension via `extend()`. Comprendre le pattern `Manager` aide donc à comprendre le fonctionnement de tout le framework.

## Principe de base

### driver() — obtenir un driver

L'appel à `driver()` résout un driver selon les étapes suivantes.

```mermaid theme={null}
flowchart TD
    A["Appel de driver(name)"] --> B{Y a-t-il un cache<br>dans drivers[] ?}
    B -- Oui --> C["Renvoie l'instance<br>mise en cache"]
    B -- Non --> D{Un enregistrement<br>existe-t-il dans customCreators[] ?}
    D -- Oui --> E["Génère l'instance via<br>callCustomCreator()"]
    D -- Non --> F{"La méthode createXxxDriver()<br>existe-t-elle ?"}
    F -- Oui --> G["Appelle createXxxDriver()"]
    F -- Non --> H["Lève InvalidArgumentException"]
    E --> I["Met en cache dans drivers[] et renvoie"]
    G --> I
```

Dans le code source, le nom de la méthode est construit à partir du nom du driver via `Str::studly()`.

```php theme={null}
// Extrait de 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.");
}
```

Autrement dit, le driver `file` appelle `createFileDriver()` et le driver `my-custom` appelle `createMyCustomDriver()`.

### extend() — enregistrer un driver personnalisé

Vous pouvez enregistrer votre propre driver en passant un nom et une closure à `extend()`. La closure reçoit l'instance du conteneur en argument.

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

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

`extend()` lie la closure à `$this`, ce qui permet d'accéder aux propriétés et méthodes du Manager depuis la closure.

```php theme={null}
// Extrait de 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 — délégation au driver par défaut

La classe Manager implémente `__call`. Les appels de méthodes qui n'existent pas sur le Manager lui-même sont automatiquement délégués au driver par défaut.

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

C'est ce qui permet d'écrire `SessionManager::get('key')` en utilisant directement le Manager, tout en confiant le traitement effectif au driver.

## Exemple d'implémentation : SessionManager

`Illuminate\Session\SessionManager` illustre concrètement l'utilisation de `Manager`.

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

use Illuminate\Support\Manager;

class SessionManager extends Manager
{
    // Obligatoire : retourne le driver par défaut
    public function getDefaultDriver()
    {
        return $this->config->get('session.driver');
    }

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

    // Construction du 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
        ));
    }

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

## Utiliser Manager dans un package maison

### Implémentation de base

Prenons un service de notifications pour créer une classe personnalisée héritant de `Manager`.

<Steps>
  <Step title="Créer une classe qui hérite de 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="Enregistrer via un 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="Ajouter un driver personnalisé">
    ```php theme={null}
    // Dans AppServiceProvider::boot() par exemple

    $manager = app(NotificationManager::class);

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

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

    // Utiliser le driver par défaut
    $manager->send('message');

    // Spécifier un driver précis
    $manager->driver('email')->send('message');

    // Un driver résolu est mis en cache
    $manager->driver('slack'); // renvoie la même instance
    ```
  </Step>
</Steps>

## MultipleInstanceManager

`Illuminate\Support\MultipleInstanceManager` est une classe ajoutée dans Laravel 10. Là où `Manager` gère les « types » de drivers, `MultipleInstanceManager` gère plusieurs « instances » nommées.

### Différences avec Manager

|                  | `Manager`                              | `MultipleInstanceManager`                           |
| ---------------- | -------------------------------------- | --------------------------------------------------- |
| Unité de gestion | Type de driver (`file`, `redis`, etc.) | Instance nommée (`mailer1`, `mailer2`, etc.)        |
| Configuration    | Un driver par défaut unique            | Configuration par instance                          |
| Usage principal  | Session, cache, etc.                   | Mail, log, etc. lorsqu'il faut plusieurs connexions |
| Méthode d'accès  | `driver()`                             | `instance()`                                        |

### Méthodes obligatoires

Pour hériter de `MultipleInstanceManager`, il faut implémenter trois méthodes.

```php theme={null}
// Extrait du code source
abstract public function getDefaultInstance();
abstract public function setDefaultInstance($name);
abstract public function getInstanceConfig($name);
```

`getInstanceConfig()` renvoie le tableau de configuration associé au nom. Ce tableau doit obligatoirement contenir la clé `driver` (ou la clé spécifiée par `$driverKey`).

### Flot de résolution

```mermaid theme={null}
flowchart TD
    A["Appel de instance(name)"] --> B["Si name est null,<br>utiliser getDefaultInstance()"]
    B --> C{Y a-t-il un cache<br>dans instances[] ?}
    C -- Oui --> D["Renvoie l'instance<br>mise en cache"]
    C -- Non --> E["Récupère la config via getInstanceConfig(name)"]
    E --> F{La config contient-elle<br>la clé driver ?}
    F -- Non --> G["Lève RuntimeException"]
    F -- Oui --> H{Un enregistrement<br>existe-t-il dans customCreators[] ?}
    H -- Oui --> I["Génère via callCustomCreator(config)"]
    H -- Non --> J["Appelle createXxxDriver(config)"]
    I --> K["Met en cache dans instances[] et renvoie"]
    J --> K
```

### Exemple d'implémentation dans un package maison

Prenons l'exemple d'un package prenant en charge simultanément plusieurs passerelles SMS.

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

use Illuminate\Support\MultipleInstanceManager;

class SmsManager extends MultipleInstanceManager
{
    // Nom de l'instance par défaut
    public function getDefaultInstance(): string
    {
        return $this->config->get('sms.default', 'primary');
    }

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

    // Renvoie la configuration associée au nom d'instance
    public function getInstanceConfig($name): array
    {
        return $this->config->get("sms.gateways.{$name}");
    }

    // Construction du driver twilio (la config est passée en argument)
    protected function createTwilioDriver(array $config): TwilioSmsGateway
    {
        return new TwilioSmsGateway(
            $config['account_sid'],
            $config['auth_token'],
        );
    }

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

Fichier de configuration correspondant :

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

Utilisation : on désigne le nom via `instance()`.

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

// Utiliser l'instance par défaut (primary = twilio)
$sms->send('+33612345678', 'Code de confirmation : 123456');

// Cibler une instance par nom
$sms->instance('backup')->send('+33612345678', 'Code de confirmation : 123456');

// Utiliser l'instance dédiée au marketing
$sms->instance('marketing')->send('+33612345678', 'Annonce de campagne');
```

<Tip>
  `MultipleInstanceManager` permet, comme `Manager`, d'ajouter des drivers personnalisés via `extend()`. Il implémente aussi `__call`, si bien que les méthodes absentes de l'instance elle-même sont déléguées à l'instance par défaut.
</Tip>

## Gestion du cache de drivers

### Manipulation du cache dans Manager

```php theme={null}
// Récupérer tous les drivers
$drivers = $manager->getDrivers();

// Vider le cache de tous les drivers
$manager->forgetDrivers();
```

### Manipulation du cache dans MultipleInstanceManager

```php theme={null}
// Supprimer une instance spécifique
$manager->forgetInstance('backup');

// Supprimer l'instance par défaut
$manager->forgetInstance();

// Supprimer plusieurs instances d'un coup
$manager->forgetInstance(['primary', 'backup']);

// Supprimer une instance et purger son cache
$manager->purge('backup');
```

## Résumé

* `Manager` gère les « types » de drivers. Implémentez des méthodes `createXxxDriver()` et étendez avec `extend()`.
* `MultipleInstanceManager` gère les « instances » de drivers nommées. Adapté aux packages nécessitant plusieurs configurations de connexion.
* Toutes les classes nommées `Manager` n'héritent pas de `Illuminate\Support\Manager`. `CacheManager` et `QueueManager` ont leur propre implémentation.

<Card title="Trait Macroable" icon="puzzle-piece" href="/fr/advanced/macroable">
  Découvrez l'utilisation du trait Macroable pour ajouter des méthodes personnalisées aux classes existantes.
</Card>


## Related topics

- [Laravel Socialite (authentification sociale)](/fr/socialite.md)
- [Laravel Sentinel — analyse du middleware de protection des routes](/fr/blog/sentinel-introduction.md)
- [Stockage de fichiers](/fr/filesystem.md)
- [Journalisation](/fr/logging.md)
- [Réinitialisation du mot de passe](/fr/passwords.md)
