> ## 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 — anatomía del sistema de drivers

> La clase central del sistema de drivers heredado desde Laravel 4.0. Explica desde el registro de drivers personalizados hasta MultipleInstanceManager.

## Qué es Manager

`Illuminate\Support\Manager` es una clase abstracta presente en Laravel desde la versión 4.0. Proporciona la base para construir con facilidad sistemas donde puedes alternar entre varios "drivers", como caché, sesión o correo.

Por «driver» entendemos backends que comparten una misma interfaz pero cuya implementación interna difiere. Por ejemplo, en sesiones existen `file`, `cookie`, `database` y `redis`, y se cambian mediante la clave `driver` del archivo de configuración.

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

## Uso dentro del framework

No todas las clases con nombre `Manager` extienden `Illuminate\Support\Manager`.

| Clase                                | ¿Extiende `Manager`?          |
| ------------------------------------ | ----------------------------- |
| `Illuminate\Session\SessionManager`  | ✅ Sí.                         |
| `Illuminate\Cache\CacheManager`      | ❌ No (implementación propia). |
| `Illuminate\Queue\QueueManager`      | ❌ No (implementación propia). |
| `Laravel\Socialite\SocialiteManager` | ✅ Sí.                         |

Aun así, las clases que no lo heredan comparten la idea básica de extenderse con `extend()`. Entender el patrón `Manager` te ayudará a comprender cómo funciona el framework en general.

## Funcionamiento básico

### driver() — obtener un driver

Cuando llamas a `driver()`, se resuelve siguiendo estos pasos:

```mermaid theme={null}
flowchart TD
    A["Se llama a driver(name)"] --> B{"¿Hay caché en drivers[]?"}
    B -- Sí --> C["Devuelve la instancia cacheada"]
    B -- No --> D{"¿Hay registro en customCreators[]?"}
    D -- Sí --> E["Genera la instancia con callCustomCreator()"]
    D -- No --> F{"¿Existe el método createXxxDriver()?"}
    F -- Sí --> G["Llama a createXxxDriver()"]
    F -- No --> H["Lanza InvalidArgumentException"]
    E --> I["Cachea en drivers[] y la devuelve"]
    G --> I
```

Si miras el código fuente, verás que el nombre del método se construye a partir del nombre del driver con `Str::studly()`.

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

Por tanto, el driver `file` invoca `createFileDriver()` y el driver `my-custom` invoca `createMyCustomDriver()`.

### extend() — registrar un driver personalizado

Pasando el nombre del driver y una closure a `extend()`, puedes registrar tu propio driver. El argumento de la closure es la instancia del contenedor.

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

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

`extend()` hace un bind del closure a `$this`, así que dentro puedes acceder a las propiedades y métodos del Manager.

```php theme={null}
// 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 — delegación al driver por defecto

La clase Manager implementa `__call`, así que cualquier llamada a un método que no exista en el propio Manager se delega automáticamente al driver por defecto.

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

Esto es lo que permite hacer cosas como `SessionManager::get('key')`: usas directamente el Manager, pero el trabajo real lo hace el driver.

## Ejemplo con SessionManager

Si miras `Illuminate\Session\SessionManager`, verás claramente cómo se usa `Manager`.

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

use Illuminate\Support\Manager;

class SessionManager extends Manager
{
    // Obligatorio: devuelve el driver por defecto
    public function getDefaultDriver()
    {
        return $this->config->get('session.driver');
    }

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

    // Crea el 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
        ));
    }

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

## Usar Manager en tu paquete

### Implementación básica

Como ejemplo, creemos una clase de servicio de notificaciones que extiende `Manager`.

<Steps>
  <Step title="Crear una clase que extienda 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="Registrar en 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="Añadir un driver personalizado">
    ```php theme={null}
    // En AppServiceProvider::boot() u otro sitio

    $manager = app(NotificationManager::class);

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

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

    // Usa el driver por defecto
    $manager->send('Mensaje');

    // Especifica un driver concreto
    $manager->driver('email')->send('Mensaje');

    // Una vez resuelto, el driver queda cacheado
    $manager->driver('slack'); // devuelve la misma instancia
    ```
  </Step>
</Steps>

## MultipleInstanceManager

`Illuminate\Support\MultipleInstanceManager` es una clase añadida en Laravel 10. Mientras que `Manager` gestiona «tipos» de driver, `MultipleInstanceManager` gestiona varias «instancias» con nombre.

### Diferencias respecto a Manager

|                     | `Manager`                               | `MultipleInstanceManager`                                  |
| ------------------- | --------------------------------------- | ---------------------------------------------------------- |
| Unidad gestionada   | Tipos de driver (`file`, `redis`, etc.) | Instancias con nombre (`mailer1`, `mailer2`, etc.)         |
| Configuración       | Un único driver por defecto             | Cada instancia tiene su propia configuración               |
| Usos habituales     | Sesiones, caché, etc.                   | Correo, log, cualquier cosa que requiera varias conexiones |
| Método de obtención | `driver()`                              | `instance()`                                               |

### Métodos obligatorios

Al extender `MultipleInstanceManager`, debes implementar tres métodos.

```php theme={null}
// Del código fuente
abstract public function getDefaultInstance();
abstract public function setDefaultInstance($name);
abstract public function getInstanceConfig($name);
```

`getInstanceConfig()` devuelve el array de configuración correspondiente al nombre. La configuración debe contener siempre la clave `driver` (o la clave que hayas especificado con `$driverKey`).

### Flujo de resolución

```mermaid theme={null}
flowchart TD
    A["Se llama a instance(name)"] --> B["Si name es null, usa getDefaultInstance()"]
    B --> C{"¿Hay caché en instances[]?"}
    C -- Sí --> D["Devuelve la instancia cacheada"]
    C -- No --> E["Obtiene la config con getInstanceConfig(name)"]
    E --> F{"¿Tiene la config una clave driver?"}
    F -- No --> G["Lanza RuntimeException"]
    F -- Sí --> H{"¿Hay registro en customCreators[]?"}
    H -- Sí --> I["Genera con callCustomCreator(config)"]
    H -- No --> J["Llama a createXxxDriver(config)"]
    I --> K["Cachea en instances[] y la devuelve"]
    J --> K
```

### Ejemplo en un paquete propio

Como ejemplo, un paquete que soporta varias gateways SMS a la vez.

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

use Illuminate\Support\MultipleInstanceManager;

class SmsManager extends MultipleInstanceManager
{
    // Nombre de la instancia por defecto
    public function getDefaultInstance(): string
    {
        return $this->config->get('sms.default', 'primary');
    }

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

    // Devuelve la configuración del nombre indicado
    public function getInstanceConfig($name): array
    {
        return $this->config->get("sms.gateways.{$name}");
    }

    // Crea el driver twilio (recibe el array de configuración)
    protected function createTwilioDriver(array $config): TwilioSmsGateway
    {
        return new TwilioSmsGateway(
            $config['account_sid'],
            $config['auth_token'],
        );
    }

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

Archivo de configuración correspondiente:

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

En el uso, indica el nombre con `instance()`.

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

// Usa la instancia por defecto (primary = twilio)
$sms->send('+34600000000', 'Código: 123456');

// Especifica la instancia por nombre
$sms->instance('backup')->send('+34600000000', 'Código: 123456');

// Usa la instancia de marketing
$sms->instance('marketing')->send('+34600000000', 'Aviso de campaña');
```

<Tip>
  `MultipleInstanceManager` permite añadir drivers personalizados con `extend()`, igual que `Manager`. También implementa `__call`, así que los métodos que no existen en el propio Manager se delegan a la instancia por defecto.
</Tip>

## Gestión de la caché de drivers

### Operaciones de caché en Manager

```php theme={null}
// Obtiene todos los drivers
$drivers = $manager->getDrivers();

// Limpia la caché de todos los drivers
$manager->forgetDrivers();
```

### Operaciones de caché en MultipleInstanceManager

```php theme={null}
// Elimina una instancia concreta
$manager->forgetInstance('backup');

// Elimina la instancia por defecto
$manager->forgetInstance();

// Elimina varias instancias a la vez
$manager->forgetInstance(['primary', 'backup']);

// Elimina la instancia y purga la caché
$manager->purge('backup');
```

## Resumen

* `Manager` gestiona «tipos» de driver. Implementa los métodos `createXxxDriver()` y extiende con `extend()`.
* `MultipleInstanceManager` gestiona «instancias» de drivers por nombre. Es adecuado para paquetes que necesitan varias configuraciones de conexión.
* No todas las clases con nombre `Manager` extienden `Illuminate\Support\Manager`. `CacheManager` y `QueueManager` tienen implementaciones propias.

<Card title="Trait Macroable" icon="puzzle-piece" href="/es/advanced/macroable">
  Aprende cómo usar el trait Macroable para añadir métodos propios a clases existentes.
</Card>


## Related topics

- [Laravel Sentinel — Investigación del middleware de protección de rutas](/es/blog/sentinel-introduction.md)
- [Almacenamiento de archivos](/es/filesystem.md)
- [Laravel Socialite (autenticación social)](/es/socialite.md)
- [Guía de actualización de Laravel 12 a 13](/es/blog/upgrade-12-to-13.md)
- [Implementación de un guard de autenticación personalizado](/es/advanced/custom-auth-guard.md)
