> ## 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 van het driversysteem

> De kernklasse van het driversysteem dat al sinds Laravel 4.0 bestaat. Van het registreren van custom drivers tot de MultipleInstanceManager.

## Wat is Manager?

`Illuminate\Support\Manager` is een abstracte klasse die al sinds Laravel 4.0 bestaat. Ze biedt de basis om eenvoudig systemen te bouwen waarin je tussen meerdere "drivers" kunt wisselen, zoals cache, sessies en mail.

Een "driver" is een backend met dezelfde interface maar een andere interne implementatie. Voor sessies bestaan er bijvoorbeeld drivers zoals `file`, `cookie`, `database` en `redis`, en je wisselt ertussen via de `driver`-sleutel in het configuratiebestand.

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

## Gebruik binnen het framework

Er bestaan klassen die wel `Manager` in hun naam hebben, maar **niet** van `Illuminate\Support\Manager` erven.

| Klasse                               | Erft van `Manager`?                      |
| ------------------------------------ | ---------------------------------------- |
| `Illuminate\Session\SessionManager`  | ✅ Erft ervan                             |
| `Illuminate\Cache\CacheManager`      | ❌ Erft er niet van (eigen implementatie) |
| `Illuminate\Queue\QueueManager`      | ❌ Erft er niet van (eigen implementatie) |
| `Laravel\Socialite\SocialiteManager` | ✅ Erft ervan                             |

Ook de klassen die er niet van erven volgen hetzelfde basisidee van uitbreiden via `extend()`. Wie het `Manager`-patroon begrijpt, begrijpt daarmee ook hoe het framework als geheel werkt.

## Hoe het in de basis werkt

### driver() — een driver ophalen

Als je `driver()` aanroept, wordt de driver in de volgende stappen opgelost.

```mermaid theme={null}
flowchart TD
    A["driver(name) aanroepen"] --> B{Staat er een cache<br>in drivers[]?}
    B -- ja --> C["Gecachte instantie<br>teruggeven"]
    B -- nee --> D{Staat er een registratie<br>in customCreators[]?}
    D -- ja --> E["Instantie aanmaken met<br>callCustomCreator()"]
    D -- nee --> F{"Bestaat de methode<br>createXxxDriver()?"}
    F -- ja --> G["createXxxDriver()<br>aanroepen"]
    F -- nee --> H["InvalidArgumentException<br>gooien"]
    E --> I["Cachen in drivers[] en teruggeven"]
    G --> I
```

Als je de daadwerkelijke broncode bekijkt, wordt de methodenaam samengesteld uit de drivernaam via `Str::studly()`.

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

Voor de `file`-driver wordt dus `createFileDriver()` aangeroepen, en voor de `my-custom`-driver `createMyCustomDriver()`.

### extend() — een custom driver registreren

Door een drivernaam en een closure aan `extend()` door te geven, kun je je eigen driver registreren. Het argument van de closure is de containerinstantie.

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

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

Omdat `extend()` de closure aan `$this` bindt, heb je binnen de closure toegang tot de properties en methodes van de Manager.

```php theme={null}
// Uit 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 — delegatie naar de standaarddriver

De Manager-klasse implementeert `__call`, waardoor methodeaanroepen die niet op de Manager zelf bestaan automatisch worden gedelegeerd naar de standaarddriver.

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

Zo kun je de Manager rechtstreeks gebruiken, zoals `SessionManager::get('key')`, terwijl het eigenlijke werk aan de driver wordt overgelaten.

## Implementatievoorbeeld: SessionManager

Als je `Illuminate\Session\SessionManager` bekijkt, zie je concreet hoe je `Manager` gebruikt.

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

use Illuminate\Support\Manager;

class SessionManager extends Manager
{
    // Verplicht: geeft de standaarddriver terug
    public function getDefaultDriver()
    {
        return $this->config->get('session.driver');
    }

    // Aanmaken van de file-driver
    protected function createFileDriver()
    {
        return $this->createNativeDriver();
    }

    // Aanmaken van de database-driver
    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
        ));
    }

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

## Manager gebruiken in je eigen package

### Basisimplementatie

We maken een custom klasse die van `Manager` erft, met een notificatieservice als voorbeeld.

<Steps>
  <Step title="Maak een klasse die van Manager erft">
    ```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="Registreer in een 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="Voeg een custom driver toe">
    ```php theme={null}
    // In bijvoorbeeld AppServiceProvider::boot()

    $manager = app(NotificationManager::class);

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

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

    // Gebruik de standaarddriver
    $manager->send('Bericht');

    // Geef een specifieke driver op
    $manager->driver('email')->send('Bericht');

    // Een eenmaal opgeloste driver wordt gecachet
    $manager->driver('slack'); // Dezelfde instantie wordt teruggegeven
    ```
  </Step>
</Steps>

## MultipleInstanceManager

`Illuminate\Support\MultipleInstanceManager` is een klasse die in Laravel 10 is toegevoegd. Waar `Manager` de "soorten" drivers beheert, kan `MultipleInstanceManager` meerdere benoemde "instanties" beheren.

### Verschillen met Manager

|                 | `Manager`                            | `MultipleInstanceManager`                                            |
| --------------- | ------------------------------------ | -------------------------------------------------------------------- |
| Beheereenheid   | Soort driver (`file`, `redis`, enz.) | Benoemde instanties (`mailer1`, `mailer2`, enz.)                     |
| Configuratie    | Eén standaarddriver                  | Configuratie per instantie                                           |
| Typisch gebruik | Sessies, cache, enz.                 | Mail, logging en andere zaken die meerdere verbindingen nodig hebben |
| Ophaalmethode   | `driver()`                           | `instance()`                                                         |

### Verplichte methodes

Als je van `MultipleInstanceManager` erft, moet je drie methodes implementeren.

```php theme={null}
// Uit de broncode
abstract public function getDefaultInstance();
abstract public function setDefaultInstance($name);
abstract public function getInstanceConfig($name);
```

`getInstanceConfig()` geeft de configuratie-array terug die bij de naam hoort. De configuratie moet altijd een `driver`-sleutel bevatten (of de sleutel die je via `$driverKey` hebt opgegeven).

### Resolutieflow

```mermaid theme={null}
flowchart TD
    A["instance(name) aanroepen"] --> B["Als name null is, wordt<br>getDefaultInstance() gebruikt"]
    B --> C{Staat er een cache<br>in instances[]?}
    C -- ja --> D["Gecachte instantie<br>teruggeven"]
    C -- nee --> E["Configuratie ophalen met getInstanceConfig(name)"]
    E --> F{Bevat de configuratie<br>een driver-sleutel?}
    F -- nee --> G["RuntimeException gooien"]
    F -- ja --> H{Staat er een registratie<br>in customCreators[]?}
    H -- ja --> I["Aanmaken met callCustomCreator(config)"]
    H -- nee --> J["createXxxDriver(config) aanroepen"]
    I --> K["Cachen in instances[] en teruggeven"]
    J --> K
```

### Implementatievoorbeeld in je eigen package

Als voorbeeld nemen we een package dat gelijktijdig meerdere sms-gateways ondersteunt.

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

use Illuminate\Support\MultipleInstanceManager;

class SmsManager extends MultipleInstanceManager
{
    // Naam van de standaardinstantie
    public function getDefaultInstance(): string
    {
        return $this->config->get('sms.default', 'primary');
    }

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

    // Geeft de configuratie terug die bij de instantienaam hoort
    public function getInstanceConfig($name): array
    {
        return $this->config->get("sms.gateways.{$name}");
    }

    // Aanmaken van de twilio-driver (de configuratie-array wordt doorgegeven)
    protected function createTwilioDriver(array $config): TwilioSmsGateway
    {
        return new TwilioSmsGateway(
            $config['account_sid'],
            $config['auth_token'],
        );
    }

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

Het bijbehorende configuratiebestand:

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

Bij gebruik geef je de naam op via `instance()`.

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

// Gebruik de standaardinstantie (primary = twilio)
$sms->send('+81901234xxxx', 'Verificatiecode: 123456');

// Geef een instantie op via de naam
$sms->instance('backup')->send('+81901234xxxx', 'Verificatiecode: 123456');

// Gebruik de marketinginstantie
$sms->instance('marketing')->send('+81901234xxxx', 'Aankondiging van de campagne');
```

<Tip>
  Aan `MultipleInstanceManager` kun je, net als bij `Manager`, custom drivers toevoegen via `extend()`. Ook `__call` is geïmplementeerd, dus methodes die niet op de instantie zelf bestaan worden gedelegeerd naar de standaardinstantie.
</Tip>

## Drivercache beheren

### Cachebewerkingen van Manager

```php theme={null}
// Alle drivers ophalen
$drivers = $manager->getDrivers();

// De cache van alle drivers wissen
$manager->forgetDrivers();
```

### Cachebewerkingen van MultipleInstanceManager

```php theme={null}
// Een specifieke instantie verwijderen
$manager->forgetInstance('backup');

// De standaardinstantie verwijderen
$manager->forgetInstance();

// Meerdere instanties in één keer verwijderen
$manager->forgetInstance(['primary', 'backup']);

// De instantie verwijderen en ook de cache wissen
$manager->purge('backup');
```

## Samenvatting

* `Manager` beheert de "soorten" drivers. Je implementeert `createXxxDriver()`-methodes en breidt uit via `extend()`
* `MultipleInstanceManager` beheert "instanties" van drivers per naam. Geschikt voor packages die meerdere verbindingsconfiguraties nodig hebben
* Niet elke klasse met `Manager` in de naam erft van `Illuminate\Support\Manager`. `CacheManager` en `QueueManager` hebben een eigen implementatie

<Card title="Macroable-trait" icon="puzzle-piece" href="/nl/advanced/macroable">
  Leer hoe je met de Macroable-trait eigen methodes toevoegt aan bestaande klassen.
</Card>


## Related topics

- [Laravel Sentinel — verkenning van de routebeschermings-middleware](/nl/blog/sentinel-introduction.md)
- [Laravel Socialite (sociale authenticatie)](/nl/socialite.md)
- [BlueskyManager en HasShortHand](/nl/packages/laravel-bluesky/bluesky-manager.md)
- [Een custom authenticatieguard implementeren](/nl/advanced/custom-auth-guard.md)
- [Versiecompatibiliteit van packages beheren](/nl/advanced/package-versioning.md)
