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.
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.
Chiamando driver(), il driver viene risolto secondo questi passaggi.Nel codice sorgente vedi che il nome del metodo viene composto dal nome del driver con Str::studly().
// 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().
Passando a extend() un nome di driver e una closure, puoi registrare un driver personalizzato. L’argomento della closure è l’istanza del container.
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.
Come esempio, creiamo una classe personalizzata che estende Manager per un servizio di notifica.
1
Creare la classe che estende Manager
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'), ); }}
2
Registrare nel service provider
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); }); }}
3
Aggiungere un driver personalizzato
// in AppServiceProvider::boot() o simile$manager = app(NotificationManager::class);$manager->extend('teams', function ($app) { return new TeamsNotifier( $app['config']['notifications.teams'], );});
4
Utilizzare
$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
Illuminate\Support\MultipleInstanceManager è una classe introdotta in Laravel 10. Mentre Manager gestisce “tipi” di driver, MultipleInstanceManager gestisce più “istanze” con nome.
Estendendo MultipleInstanceManager devi implementare tre metodi.
// dal codice sorgenteabstract 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).
Esempio di implementazione in un pacchetto proprio
Prendiamo come esempio un pacchetto che supporta contemporaneamente più gateway SMS.
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'], ); }}
In fase di utilizzo indichi il nome con instance().
$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');
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.
// 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');