Consulteu els articles:
Les Facades a Laravel proveeixen d'un interfície "estàtica" per accedir a les classes que estan disponibles al service container de l'aplicació. Laravel "facades" fan el servei de "static proxies" per accedir a les classes del service container permetent utilitzar la còmoda sintaxi a l'estil de crides estàtiques ("Facade::", vegeu static i Scope Resolution Operator) però sense els inconvenients dels mètodes estàtics, és a dir, mantenint la flexibilitat i la testabilitat del sistema
Vegeu:
https://laravel.com/docs/master/facades#facade-class-reference
Observeu que utilitzar una Facade com per exemple Cache és equivalent a:
$cache = new Illuminate\Cache\Repository() // nota: amb el pas de paràmetres que correspongui si cal es clar App::make('cache') $this->app->make('chache etc...
En el context d'una aplicació Laravel una Facad és un classe que proveix accés a objectes del Laravel IoC Container. Per crear una Facade només cal heretar de la classe Illuminate\Support\Facades\Facade de Laravel i implementar un únic mètode:
getFacadeAccessor
Que simplement ha de retornar un String amb l'objecte que hem de resoldre del contenidor Laravel. La classe Facade de Laravel fa ús del mètode màgic de PHP __callStatic() per mapejar les crides a mètodes estàtics com a crides a mètodes que no són estàtics (necessariament no ho han de ser) del objecte que obtenim del contenidor. Un Exemple:
class Cache extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'cache'; } }
Abans de poder utilitzar una facade cal haver definit un binding al contenidor per a l'objecte cache.
Les facades a Laravel ha nestat sovint criticades sense conèixer els detalls de com estan implementades pel fet de que semblen una "simple" crida a un mètode estàtic (vegeu static i Scope Resolution Operator)), per exemple:
Route::get('/', '[email protected]');
El problema és que sovint estes crítiques es fan sense saber que realment la línia anterior equival a:
$app['router']->get('/', '[email protected]');
I aquí no hi ha cap crida a mètode estàtic! De fet tampoc era una crida a un mètode estàtic l'ús de la Facade simplement són Syntax Sugar o el que també es coneix com formes alternatives d'escriure codi de forma més simple.
Quan es crida una Facade el sistema Laravel la resol com una classes del Laravel IoC container i executa el mètode en la instància del objecte que equival a la Facade.
Quoting Taylor Otwell:
However, service location can lead developers into some bad architectural habits. For instance, since service location is very “easy”, it can lead to responsibility bloat in your classes. Generally, classes with small, focused responsibilities are to be desired since they are easier to understand, test, debug, etc. However, if you are using Facades to push to the queue, send an e-mail, and validate some data all within a single class, that class’ core responsibilities are obscured. It is concerned about way too many things.
És a dir el simple fet de utilitzar una Facade no vol dis que estiguem fent un disseny SOLID especialment si la Facade té multiples responsabilitats i no compleix amb la S de SOLID (Single Responsability Principle)
Si voleu conèixer els detalls de com estan implementades les Facades veieu el vídeo de Laracast:
https://laracasts.com/lessons/decoding-facades
Resources:
Es necessiten 3 passes:
1) Crear un Service Container Binding
Per crear un Service Container Binding només cal executar el mètode bind amb la Facade App, per exemple si volem registrar un payment:
App::bind('payment', function() { return new \PaymentGateway\Payment; });
també es pot fer sense una Facade directament utilitzant app (si estem dins d'un Service Provider):
$this->app->bind('payment', function () { return new \PaymentGateway\Payment; });
Observeu que es poden injectar dependències amb:
$this->app->singleton('FooBar', function ($app) { return new FooBar($app['SomethingElse']); });
Una qüestió important és on executar aquest codi? És possible (però no gaire ordenat ni recomanable) executar-ho a qualsevol lloc com per exemple el fitxer routes.php però el més habitual es fer-ho a un ServiceProvider. Per exemple per a Payment podriem crear un PaymentServiceProvider. Per crear un ServiceProvider podeu utilitzar php artisan:
$ php artisan make:provider PaymentServiceProvider
Al mètode register és el lloc ideal per a registrar Service container bindings. Vegem un exemple:
class PaymentServiceProvider extends ServiceProvider { /** * Register bindings in the container. * * @return void */ public function register() { $this->app->bind('payment', function ($app) { return new \PaymentGateway\Payment; }); } }
NOTA: Pot ser interessant utilitzar prefixes a mode d'espais de noms per evitar col·lisions per exemple vendor/payment
2) Crear una Facade:
use Illuminate\Support\Facades\Facade; class Payment extends Facade { protected static function getFacadeAccessor() { return 'payment'; } }
3) Afegir la facade a fitxer app/config.php
Aquest pas és el més conegut perquè és el mateix que fem quan només utilitzem Facades de tercers és a dir no pròpies. Al fitxer app/config.php cal afegir la facade al vector aliases:
Resources:
Laravel ships with many facades, and you have probably been using them without even knowing it!
Podeu trobar una llista completa a:
http://laravel.com/docs/5.1/facades#facade-class-reference
Resources: