Fornitori di Servizio (Service Providers)
Introduzione
I provider di servizi sono il punto centrale di tutte le operazioni di avvio dell’applicazione Laravel. La tua applicazione e tutti i servizi principali di Laravel vengono avviati tramite i provider di servizi.
Ma cosa intendiamo per “avviato”? In generale, intendiamo la registrazione di elementi, compresa la registrazione dei binding del container dei servizi, degli ascoltatori degli eventi, dei middleware e persino delle route. I provider di servizi sono il punto centrale per configurare la tua applicazione.
Se apri il file config/app.php incluso in Laravel, vedrai un array di providers. Questi sono tutti i provider di servizi che verranno caricati per la tua applicazione. Per impostazione predefinita, nell’array sono elencati un insieme di provider di servizi di base di Laravel. Questi provider avviano i componenti principali di Laravel, come il mailer, la coda, la cache e altri. Molti di questi provider sono “deferred”, il che significa che non verranno caricati ad ogni richiesta, ma solo quando i servizi che forniscono sono effettivamente necessari.
In questa panoramica, imparerai come scrivere i tuoi provider di servizi e come registrarli nella tua applicazione Laravel.
Scrivere Provider di Servizi
Tutti i provider di servizi estendono la classe Illuminate\Support\ServiceProvider. La maggior parte dei provider di servizi contiene un metodo register e un metodo boot. All’interno del metodo register, dovresti solo collegare le cose nel container dei servizi. Non dovresti mai cercare di registrare listener di eventi, percorsi o qualsiasi altra funzionalità all’interno del metodo register.
Il CLI Artisan può generare un nuovo provider tramite il comando make:provider:
php artisan make:provider RiakServiceProvider
Il metodo Register
Come accennato in precedenza, all’interno del metodo register dovresti solo effettuare le registrazioni nel service container. Non dovresti mai cercare di registrare event listener, route o qualsiasi altra funzionalità all’interno del metodo register. Altrimenti, potresti utilizzare accidentalmente un servizio fornito da un provider che non è ancora stato caricato.
Diamo un’occhiata a un service provider di base. All’interno di qualsiasi metodo del tuo service provider, hai sempre accesso alla proprietà $app che fornisce l’accesso al service container:
<?php namespace App\Providers; use App\Services\Riak\Connection; use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\ServiceProvider; class RiakServiceProvider extends ServiceProvider { /** * Register any application services. */ public function register(): void { $this->app->singleton(Connection::class, function (Application $app) { return new Connection(config('riak')); }); } }
Questo service provider definisce solo un metodo register e lo utilizza per definire un’implementazione di App\Services\Riak\Connection nel service container. Se non sei ancora familiare con il service container di Laravel, consulta la sua documentazione.
Le proprietà bindings e singletons
Se il tuo service provider registra molteplici binding semplici, potresti preferire utilizzare le proprietà bindings e singletons invece di registrare manualmente ogni binding nel container. Quando il framework carica il service provider, controlla automaticamente queste proprietà e registra i loro binding:
<?php namespace App\Providers; use App\Contracts\DowntimeNotifier; use App\Contracts\ServerProvider; use App\Services\DigitalOceanServerProvider; use App\Services\PingdomDowntimeNotifier; use App\Services\ServerToolsProvider; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * All of the container bindings that should be registered. * * @var array */ public $bindings = [ ServerProvider::class => DigitalOceanServerProvider::class, ]; /** * All of the container singletons that should be registered. * * @var array */ public $singletons = [ DowntimeNotifier::class => PingdomDowntimeNotifier::class, ServerProvider::class => ServerToolsProvider::class, ]; }
Il metodo Boot
Quindi, cosa fare se è necessario registrare un view composer all’interno del nostro service provider? Questo dovrebbe essere fatto all’interno del metodo boot. Questo metodo viene chiamato dopo che tutti gli altri service provider sono stati registrati, il che significa che hai accesso a tutti gli altri servizi che sono stati registrati dal framework:
<?php namespace App\Providers; use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; class ComposerServiceProvider extends ServiceProvider { /** * Bootstrap any application services. */ public function boot(): void { View::composer('view', function () { // ... }); } }
Iniezione di Dipendenza nel Metodo boot
Puoi usare l’Injection di dipendenza per il metodo boot del tuo service provider. Il service container inietterà automaticamente tutte le dipendenze di cui hai bisogno:
use Illuminate\Contracts\Routing\ResponseFactory; /** * Bootstrap any application services. */ public function boot(ResponseFactory $response): void { $response->macro('serialized', function (mixed $value) { // ... }); }
Registrazione dei Provider
Tutti i provider di servizi vengono registrati nel file di configurazione config/app.php. Questo file contiene un array di providers in cui è possibile elencare i nomi delle classi dei provider di servizi. Per impostazione predefinita, un insieme di provider di servizi principali di Laravel è registrato in questo array. I provider predefiniti avviano i componenti principali di Laravel, come il mailer, la coda, la cache e altri.
Per registrare il tuo provider, aggiungilo all’array:
'providers' => ServiceProvider::defaultProviders()->merge([ // Other Service Providers App\Providers\ComposerServiceProvider::class, ])->toArray(),
Providers Differiti (Deferred Providers)
Se il tuo provider sta solo registrando dei binding nel container dei servizi, puoi scegliere di differire la sua registrazione fino a quando uno dei binding registrati non viene effettivamente richiesto. Ritardare il caricamento di un provider del genere migliorerà le prestazioni della tua applicazione, poiché non viene caricato dal filesystem ad ogni richiesta.
Laravel compila e memorizza una lista di tutti i servizi forniti dai provider di servizi differiti, insieme al nome della classe del provider di servizi. Successivamente, solo quando si tenta di risolvere uno di questi servizi, Laravel carica il provider di servizi.
Per differire il caricamento di un provider, implementa l’interfaccia \Illuminate\Contracts\Support\DeferrableProvider e definisci un metodo provides. Il metodo provides dovrebbe restituire i binding del container dei servizi registrati dal provider:
<?php namespace App\Providers; use App\Services\Riak\Connection; use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Support\ServiceProvider; class RiakServiceProvider extends ServiceProvider implements DeferrableProvider { /** * Register any application services. */ public function register(): void { $this->app->singleton(Connection::class, function (Application $app) { return new Connection($app['config']['riak']); }); } /** * Get the services provided by the provider. * * @return array<int, string> */ public function provides(): array { return [Connection::class]; } }