Cos’è una facade
Una facade fornisce un’interfaccia “statica” alle classi disponibili nel service container dell’applicazione. Laravel include molte facade che danno accesso a quasi tutte le sue funzionalità. Le facade di Laravel fungono da “proxy statici” alle classi reali all’interno del service container: offrono una sintassi concisa ed espressiva mantenendo maggiore testabilità e flessibilità rispetto ai metodi statici tradizionali. Tutte le facade di Laravel sono definite nel namespaceIlluminate\Support\Facades.
Non è un problema se non comprendi ancora completamente il funzionamento delle facade. Impara prima come usarle e continua a studiare Laravel.
Come funzionano le facade
Nelle applicazioni Laravel, una facade è una classe che offre accesso a un oggetto proveniente dal container. Questo meccanismo è implementato dalla classeFacade. Tutte le facade di Laravel e le facade personalizzate estendono la classe base Illuminate\Support\Facades\Facade.
La classe base Facade usa il metodo magico __callStatic() per delegare le chiamate alla facade all’oggetto risolto dal container.
Cache. Questa facade fa da proxy verso l’implementazione dell’interfaccia Illuminate\Contracts\Cache\Factory. Tutte le chiamate effettuate tramite la facade vengono passate all’istanza interna del servizio di cache di Laravel.
Se guardi la classe Illuminate\Support\Facades\Cache, non troverai un metodo statico get.
Cache estende la classe base Facade e definisce il metodo getFacadeAccessor(). Questo metodo restituisce il nome del binding nel service container. Quando l’utente chiama un metodo statico della facade Cache, Laravel risolve il binding cache dal service container ed esegue su quell’oggetto il metodo richiesto (in questo caso get).
Quando usare (o non usare) le facade
Vantaggi delle facade
Le facade offrono molti vantaggi. Forniscono una sintassi concisa e memorabile che consente di usare le funzionalità di Laravel senza dover ricordare lunghi nomi di classi da iniettare e configurare manualmente. Inoltre, grazie all’uso peculiare dei metodi dinamici di PHP, sono facili da testare.Attenzione allo scope creep
Il rischio principale nell’uso delle facade è lo “scope creep” delle classi. Poiché sono comode e non richiedono iniezione, si tende a far crescere una classe continuando ad aggiungere facade. Con la dependency injection, un costruttore che si allunga dà un chiaro segnale visivo. Quando usi le facade, presta attenzione alla dimensione delle classi e mantieni una responsabilità ristretta.Facade vs dependency injection
Uno dei principali vantaggi della dependency injection è la possibilità di sostituire l’implementazione della classe iniettata. Utile nei test: puoi iniettare mock o stub e verificare che vari metodi vengano invocati sullo stub. Normalmente i metodi statici veri e propri non possono essere mockati né sostituiti, ma le facade — grazie ai metodi dinamici che fanno da proxy verso l’oggetto risolto dal service container — possono essere testate esattamente come un’istanza di classe iniettata.Cache::get sia stato chiamato con l’argomento atteso.
Facade vs funzioni helper
Oltre alle facade, Laravel fornisce funzioni “helper” per svolgere compiti comuni come creare viste, emettere eventi, dispatchare job e inviare risposte HTTP. Molte funzioni helper eseguono la stessa funzione della facade corrispondente.Real-time facade
Con le real-time facade puoi trattare qualsiasi classe dell’applicazione come una facade. Per spiegare come si usano, vediamo prima un codice senza real-time facade. Supponi che il modelloPodcast abbia un metodo publish. Per pubblicare il podcast è però necessario iniettare un’istanza di Publisher.
Publisher, pur mantenendo la stessa testabilità. Per generare una real-time facade aggiungi il prefisso Facades al namespace della classe da importare.
Facades.
Testare le facade
Per testare le facade usa il metodoshouldReceive, che restituisce un’istanza mock di Mockery. Poiché le facade sono realmente risolte e gestite dal service container, sono molto più testabili delle classi statiche tradizionali.
| Metodo | Descrizione |
|---|---|
shouldReceive('method') | Ci si aspetta che il metodo venga chiamato |
once() | Ci si aspetta che venga chiamato una sola volta |
times(n) | Ci si aspetta che venga chiamato n volte |
with(args) | Ci si aspetta che venga chiamato con determinati argomenti |
andReturn(value) | Restituisce il valore indicato |
andReturnNull() | Restituisce null |
Elenco delle facade principali
Tabella di corrispondenza tra le facade più usate, la classe reale e il nome del binding nel service container.| Facade | Classe | Binding |
|---|---|---|
App | Illuminate\Foundation\Application | app |
Auth | Illuminate\Auth\AuthManager | auth |
Cache | Illuminate\Cache\CacheManager | cache |
Config | Illuminate\Config\Repository | config |
Cookie | Illuminate\Cookie\CookieJar | cookie |
Crypt | Illuminate\Encryption\Encrypter | encrypter |
DB | Illuminate\Database\DatabaseManager | db |
Event | Illuminate\Events\Dispatcher | events |
File | Illuminate\Filesystem\Filesystem | files |
Gate | Illuminate\Contracts\Auth\Access\Gate | — |
Hash | Illuminate\Contracts\Hashing\Hasher | hash |
Http | Illuminate\Http\Client\Factory | — |
Log | Illuminate\Log\LogManager | log |
Mail | Illuminate\Mail\Mailer | mailer |
Notification | Illuminate\Notifications\ChannelManager | — |
Queue | Illuminate\Queue\QueueManager | queue |
RateLimiter | Illuminate\Cache\RateLimiter | — |
Redirect | Illuminate\Routing\Redirector | redirect |
Request | Illuminate\Http\Request | request |
Route | Illuminate\Routing\Router | router |
Schema | Illuminate\Database\Schema\Builder | — |
Session | Illuminate\Session\SessionManager | session |
Storage | Illuminate\Filesystem\FilesystemManager | filesystem |
URL | Illuminate\Routing\UrlGenerator | url |
Validator | Illuminate\Validation\Factory | validator |
View | Illuminate\View\Factory | view |
Prossimi passi
Contracts (contratti)
Impara i concetti dei Contracts, controparte delle facade, e quando preferire l’uno o l’altro.