> ## 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 des Treibersystems

> Die zentrale Klasse des Treibersystems, das seit Laravel 4.0 existiert. Von der Registrierung eigener Treiber bis zum MultipleInstanceManager.

## Was ist Manager?

`Illuminate\Support\Manager` ist eine abstrakte Klasse, die es seit Laravel 4.0 gibt. Sie stellt die Grundlage bereit, um Systeme zu bauen, in denen sich verschiedene „Treiber" für Cache, Session, Mail usw. einfach austauschen lassen.

Ein „Treiber" ist ein Backend mit gleicher Schnittstelle, aber unterschiedlicher interner Implementierung. Bei Sessions z. B. gibt es die Treiber `file`, `cookie`, `database`, `redis` — umgeschaltet wird über den `driver`-Key in der Konfigurationsdatei.

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

## Verwendung im Framework

Nicht jede Klasse mit dem Namen `Manager` erbt tatsächlich von `Illuminate\Support\Manager`.

| Klasse                               | Erbt von `Manager`?           |
| ------------------------------------ | ----------------------------- |
| `Illuminate\Session\SessionManager`  | ✅ Ja                          |
| `Illuminate\Cache\CacheManager`      | ❌ Nein (Eigenimplementierung) |
| `Illuminate\Queue\QueueManager`      | ❌ Nein (Eigenimplementierung) |
| `Laravel\Socialite\SocialiteManager` | ✅ Ja                          |

Auch die nicht erbenden Klassen folgen demselben Grundprinzip der Erweiterung über `extend()`. Wer das `Manager`-Muster versteht, versteht daher auch weite Teile des Frameworks.

## Grundlegende Funktionsweise

### driver() — einen Treiber ermitteln

Der Aufruf von `driver()` löst den Treiber in folgender Reihenfolge auf.

```mermaid theme={null}
flowchart TD
    A["driver(name) aufrufen"] --> B{Cache in<br>drivers[] vorhanden?}
    B -- Ja --> C["Gecachte Instanz zurückgeben"]
    B -- Nein --> D{Ist in customCreators[]<br>eingetragen?}
    D -- Ja --> E["Instanz über<br>callCustomCreator() erzeugen"]
    D -- Nein --> F{"Existiert Methode<br>createXxxDriver()?"}
    F -- Ja --> G["createXxxDriver()<br>aufrufen"]
    F -- Nein --> H["InvalidArgumentException<br>werfen"]
    E --> I["In drivers[] cachen und zurückgeben"]
    G --> I
```

Im tatsächlichen Quellcode wird der Methodenname aus dem Treibernamen per `Str::studly()` zusammengesetzt.

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

Der `file`-Treiber ruft also `createFileDriver()`, der Treiber `my-custom` ruft `createMyCustomDriver()`.

### extend() — einen eigenen Treiber registrieren

Übergeben Sie an `extend()` den Treibernamen und eine Closure, um einen eigenen Treiber zu registrieren. Als Argument erhält die Closure die Container-Instanz.

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

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

`extend()` bindet die Closure an `$this`, sodass Sie in ihr auf Properties und Methoden des Managers zugreifen können.

```php theme={null}
// Aus 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 — Delegation an den Default-Treiber

`Manager` implementiert `__call`; Methodenaufrufe, die es am Manager selbst nicht gibt, werden automatisch an den Default-Treiber delegiert.

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

Dadurch können Sie `SessionManager::get('key')` direkt am Manager aufrufen — die tatsächliche Arbeit erledigt der Treiber.

## Beispielimplementierung SessionManager

Ein Blick in `Illuminate\Session\SessionManager` zeigt die praktische Verwendung von `Manager`.

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

use Illuminate\Support\Manager;

class SessionManager extends Manager
{
    // Pflicht: Default-Treiber zurückgeben
    public function getDefaultDriver()
    {
        return $this->config->get('session.driver');
    }

    // file-Treiber erzeugen
    protected function createFileDriver()
    {
        return $this->createNativeDriver();
    }

    // database-Treiber erzeugen
    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
        ));
    }

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

## Manager in einem eigenen Paket verwenden

### Grundlegende Implementierung

Als Beispiel bauen wir einen Benachrichtigungsdienst als von `Manager` abgeleitete Klasse.

<Steps>
  <Step title="Von Manager ableitende Klasse erstellen">
    ```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="Im Service Provider registrieren">
    ```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="Einen eigenen Treiber ergänzen">
    ```php theme={null}
    // z. B. in AppServiceProvider::boot()

    $manager = app(NotificationManager::class);

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

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

    // Default-Treiber verwenden
    $manager->send('Nachricht');

    // Einen bestimmten Treiber wählen
    $manager->driver('email')->send('Nachricht');

    // Einmal aufgelöste Treiber werden gecacht
    $manager->driver('slack'); // Gibt dieselbe Instanz zurück
    ```
  </Step>
</Steps>

## MultipleInstanceManager

`Illuminate\Support\MultipleInstanceManager` wurde in Laravel 10 hinzugefügt. Während `Manager` die „Art" eines Treibers verwaltet, kann `MultipleInstanceManager` mehrere benannte „Instanzen" verwalten.

### Unterschiede zu Manager

|                    | `Manager`                           | `MultipleInstanceManager`                      |
| ------------------ | ----------------------------------- | ---------------------------------------------- |
| Verwaltungseinheit | Treibertypen (`file`, `redis` usw.) | Benannte Instanzen (`mailer1`, `mailer2` usw.) |
| Konfiguration      | Ein Default-Treiber                 | Konfiguration pro Instanz                      |
| Hauptanwendung     | Session, Cache usw.                 | Mail, Logs — Fälle mit mehreren Verbindungen   |
| Zugriffsmethode    | `driver()`                          | `instance()`                                   |

### Pflichtmethoden

Wer von `MultipleInstanceManager` ableitet, muss drei Methoden implementieren.

```php theme={null}
// Aus dem Quellcode
abstract public function getDefaultInstance();
abstract public function setDefaultInstance($name);
abstract public function getInstanceConfig($name);
```

`getInstanceConfig()` gibt das Konfigurationsarray zu einem Namen zurück. Die Konfiguration muss zwingend den Schlüssel `driver` (bzw. den mit `$driverKey` gesetzten Namen) enthalten.

### Auflösungsablauf

```mermaid theme={null}
flowchart TD
    A["instance(name) aufrufen"] --> B["Ist name null,<br>getDefaultInstance() verwenden"]
    B --> C{Cache in<br>instances[] vorhanden?}
    C -- Ja --> D["Gecachte Instanz zurückgeben"]
    C -- Nein --> E["Konfiguration über getInstanceConfig(name)"]
    E --> F{Enthält die Konfiguration<br>einen driver-Key?}
    F -- Nein --> G["RuntimeException werfen"]
    F -- Ja --> H{Ist in customCreators[]<br>eingetragen?}
    H -- Ja --> I["Über callCustomCreator(config) erzeugen"]
    H -- Nein --> J["createXxxDriver(config) aufrufen"]
    I --> K["In instances[] cachen und zurückgeben"]
    J --> K
```

### Beispielimplementierung in einem eigenen Paket

Als Beispiel ein Paket, das mehrere SMS-Gateways parallel bedient.

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

use Illuminate\Support\MultipleInstanceManager;

class SmsManager extends MultipleInstanceManager
{
    // Name der Default-Instanz
    public function getDefaultInstance(): string
    {
        return $this->config->get('sms.default', 'primary');
    }

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

    // Konfiguration zum Instanznamen zurückgeben
    public function getInstanceConfig($name): array
    {
        return $this->config->get("sms.gateways.{$name}");
    }

    // twilio-Treiber erzeugen (Konfigurationsarray wird übergeben)
    protected function createTwilioDriver(array $config): TwilioSmsGateway
    {
        return new TwilioSmsGateway(
            $config['account_sid'],
            $config['auth_token'],
        );
    }

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

Zugehörige Konfigurationsdatei:

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

Die Nutzung erfolgt über `instance()` mit einem Namen.

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

// Default-Instanz nutzen (primary = twilio)
$sms->send('+491701234567', 'Bestätigungscode: 123456');

// Instanz nach Name auswählen
$sms->instance('backup')->send('+491701234567', 'Bestätigungscode: 123456');

// Marketing-Instanz nutzen
$sms->instance('marketing')->send('+491701234567', 'Kampagnen-Info');
```

<Tip>
  Wie `Manager` kann auch `MultipleInstanceManager` über `extend()` um eigene Treiber erweitert werden. Es implementiert ebenfalls `__call`, sodass unbekannte Methoden an die Default-Instanz delegiert werden.
</Tip>

## Verwaltung des Treiber-Caches

### Cache-Operationen von Manager

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

// Cache aller Treiber leeren
$manager->forgetDrivers();
```

### Cache-Operationen von MultipleInstanceManager

```php theme={null}
// Eine bestimmte Instanz löschen
$manager->forgetInstance('backup');

// Default-Instanz löschen
$manager->forgetInstance();

// Mehrere Instanzen auf einmal löschen
$manager->forgetInstance(['primary', 'backup']);

// Instanz löschen und Cache leeren
$manager->purge('backup');
```

## Fazit

* `Manager` verwaltet die „Art" eines Treibers. Sie implementieren `createXxxDriver()`-Methoden und erweitern per `extend()`.
* `MultipleInstanceManager` verwaltet „Instanzen" eines Treibers nach Name. Passend für Pakete mit mehreren Verbindungskonfigurationen.
* Nicht jede Klasse mit dem Namen `Manager` erbt von `Illuminate\Support\Manager`. `CacheManager` und `QueueManager` sind eigene Implementierungen.

<Card title="Macroable-Trait" icon="puzzle-piece" href="/de/advanced/macroable">
  Lernen Sie den Macroable-Trait kennen, mit dem Sie bestehenden Klassen eigene Methoden hinzufügen.
</Card>


## Related topics

- [Laravel Sentinel – Analyse der Route-Schutz-Middleware](/de/blog/sentinel-introduction.md)
- [Laravel Socialite (Social Authentication)](/de/socialite.md)
- [Support Contracts (Arrayable / Jsonable / Htmlable / Responsable)](/de/advanced/support-contracts.md)
- [BlueskyManager und HasShortHand](/de/packages/laravel-bluesky/bluesky-manager.md)
- [Macroable-Trait](/de/advanced/macroable.md)
