1. Conceptos de arquitectura
  2. Fachadas

Únete a nuestra comunidad de Telegram @webblend!

Aquí encontrarás fragmentos de código de Laravel y consejos útiles sobre desarrollo web.

Introducción

A lo largo de la documentación de Laravel, verás ejemplos de código que interactúan con las funciones de Laravel a través de "fachadas". Las fachadas proporcionan una interfaz "estática" a las clases disponibles en el contenedor de servicios de la aplicación. Laravel incluye muchas fachadas que brindan acceso a casi todas las características de Laravel.

Las fachadas de Laravel sirven como "proxies estáticos" para clases subyacentes en el contenedor de servicios, proporcionando la ventaja de una sintaxis concisa y expresiva, manteniendo al mismo tiempo más testabilidad y flexibilidad que los métodos estáticos tradicionales. Está perfectamente bien si no comprendes completamente cómo funcionan las fachadas; simplemente sigue adelante y continúa aprendiendo sobre Laravel.

Todas las fachadas de Laravel están definidas en el espacio de nombres Illuminate\Support\Facades. Entonces, podemos acceder fácilmente a una fachada de la siguiente manera:

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Route;
 
Route::get('/cache', function () {
return Cache::get('key');
});

A lo largo de la documentación de Laravel, muchos de los ejemplos utilizarán fachadas para demostrar varias características del framework.

Funciones de Ayuda

Para complementar las fachadas, Laravel ofrece una variedad de "funciones de ayuda" globales que facilitan aún más la interacción con funciones comunes de Laravel. Algunas de las funciones de ayuda comunes con las que puedes interactuar son view, response, url, config y más. Cada función de ayuda ofrecida por Laravel está documentada con su función correspondiente; sin embargo, hay una lista completa disponible en la documentación dedicada de funciones de ayuda.

Por ejemplo, en lugar de usar la fachada Illuminate\Support\Facades\Response para generar una respuesta JSON, simplemente podemos usar la función response. Debido a que las funciones de ayuda están disponibles globalmente, no es necesario importar ninguna clase para usarlas:

use Illuminate\Support\Facades\Response;
 
Route::get('/users', function () {
return Response::json([
// ...
]);
});
 
Route::get('/users', function () {
return response()->json([
// ...
]);
});

Cuándo Usar Facades

Las fachadas tienen muchos beneficios. Proporcionan una sintaxis concisa y memorable que te permite utilizar las características de Laravel sin recordar nombres largos de clases que deban ser inyectados o configurados manualmente. Además, debido a su uso único de los métodos dinámicos de PHP, son fáciles de probar.

Sin embargo, debes tener cuidado al usar fachadas. El peligro principal de las fachadas es la "expansión de alcance" de la clase. Dado que las fachadas son tan fáciles de usar y no requieren inyección, puede ser fácil dejar que tus clases continúen creciendo y usar muchas fachadas en una sola clase. Al utilizar la inyección de dependencias, este potencial se mitiga mediante la retroalimentación visual que te da un constructor grande, indicando que tu clase está creciendo demasiado. Así que, al usar fachadas, presta especial atención al tamaño de tu clase para que su alcance de responsabilidad se mantenga estrecho. Si tu clase está creciendo demasiado, considera dividirla en varias clases más pequeñas.

Facades Vs. Inyección de Dependencias

Uno de los principales beneficios de la inyección de dependencias es la capacidad de intercambiar implementaciones de la clase inyectada. Esto es útil durante las pruebas, ya que puedes inyectar un objeto simulado o de prueba y afirmar que se llamaron varios métodos en la simulación.

Normalmente, no sería posible simular o poner en espera un método de clase verdaderamente estático. Sin embargo, dado que las fachadas utilizan métodos dinámicos para enviar llamadas de método a objetos resueltos del contenedor de servicios, realmente podemos probar las fachadas de la misma manera que probaríamos una instancia de clase inyectada. Por ejemplo, dada la siguiente ruta:

use Illuminate\Support\Facades\Cache;
 
Route::get('/cache', function () {
return Cache::get('key');
});

Usando los métodos de prueba de fachadas de Laravel, podemos escribir la siguiente prueba para verificar que el método Cache::get fue llamado con el argumento que esperábamos:

use Illuminate\Support\Facades\Cache;
 
/**
* Un ejemplo básico de prueba funcional.
*/
public function test_basic_example(): void
{
Cache::shouldReceive('get')
->with('key')
->andReturn('value');
 
$response = $this->get('/cache');
 
$response->assertSee('value');
}

Facades Vs. Funciones de Ayuda

Además de las fachadas, Laravel incluye una variedad de funciones de "ayuda" que pueden realizar tareas comunes como generar vistas, disparar eventos, despachar trabajos o enviar respuestas HTTP. Muchas de estas funciones de ayuda realizan la misma función que una fachada correspondiente. Por ejemplo, esta llamada de fachada y llamada de ayuda son equivalentes:

return Illuminate\Support\Facades\View::make('profile');
 
return view('profile');

No hay absolutamente ninguna diferencia práctica entre las fachadas y las funciones de ayuda. Al usar funciones de ayuda, aún puedes probarlas exactamente de la misma manera que lo harías con la fachada correspondiente. Por ejemplo, dada la siguiente ruta:

Route::get('/cache', function () {
return cache('key');
});

El ayudante cache llamará al método get en la clase subyacente de la fachada Cache. Entonces, aunque estemos usando la función de ayuda, podemos escribir la siguiente prueba para verificar que el método fue llamado con el argumento que esperábamos:

use Illuminate\Support\Facades\Cache;
 
/**
* Un ejemplo básico de prueba funcional.
*/
public function test_basic_example(): void
{
Cache::shouldReceive('get')
->with('key')
->andReturn('value');
 
$response = $this->get('/cache');
 
$response->assertSee('value');
}

Cómo Funcionan las Facades

En una aplicación Laravel, una fachada es una clase que proporciona acceso a un objeto desde el contenedor. La maquinaria que hace esto posible está en la clase Facade. Las fachadas de Laravel, y cualquier fachada personalizada que crees, extenderán la clase base Illuminate\Support\Facades\Facade.

La clase base Facade utiliza el método mágico __callStatic() para diferir las llamadas desde tu fachada a un objeto resuelto del contenedor. En el siguiente ejemplo, se realiza una llamada al sistema de caché de Laravel. Al mirar este código, uno podría suponer que se está llamando al método estático get en la clase Cache:

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Cache;
use Illuminate\View\View;
 
class UserController extends Controller
{
/**
* Mostrar el perfil del usuario proporcionado.
*/
public function showProfile(string $id): View
{
$user = Cache::get('user:'.$id);
 
return view('profile', ['user' => $user]);
}
}

Observa que cerca del inicio del archivo estamos "importando" la fachada Cache. Esta fachada sirve como un proxy para acceder a la implementación subyacente de la interfaz Illuminate\Contracts\Cache\Factory. Cualquier llamada que hagamos utilizando la fachada se pasará a la instancia subyacente del servicio de caché de Laravel.

Si observamos la clase Illuminate\Support\Facades\Cache, verás que no hay un método estático get:

class Cache extends Facade
{
/**
* Obtener el nombre registrado del componente.
*/
protected static function getFacadeAccessor(): string
{
return 'cache';
}
}

En cambio, la fachada Cache extiende la clase base Facade y define el método getFacadeAccessor(). La tarea de este método es devolver el nombre de un enlace del contenedor de servicios. Cuando un usuario referencia cualquier método estático en la fachada Cache, Laravel resuelve el enlace cache del contenedor de servicios y ejecuta el método solicitado (en este caso, get) contra ese objeto.

Facades en Tiempo Real

Usando fachadas en tiempo real, puedes tratar cualquier clase en tu aplicación como si fuera una fachada. Para ilustrar cómo se puede usar esto, examinemos primero un código que no utiliza fachadas en tiempo real. Por ejemplo, supongamos que nuestro modelo Podcast tiene un método publish. Sin embargo, para publicar el podcast, necesitamos inyectar una instancia de Publisher:

<?php
 
namespace App\Models;
 
use App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;
 
class Podcast extends Model
{
/**
* Publicar el podcast.
*/
public function publish(Publisher $publisher): void
{
$this->update(['publishing' => now()]);
 
$publisher->publish($this);
}
}

Inyectar una implementación de publisher en el método nos permite probar fácilmente el método de forma aislada, ya que podemos simular el publisher inyectado. Sin embargo, nos obliga a pasar siempre una instancia de publisher cada vez que llamamos al método publish. Usando fachadas en tiempo real, podemos mantener la misma capacidad de prueba sin tener que pasar explícitamente una instancia de Publisher. Para generar una fachada en tiempo real, agrega el espacio de nombres de la clase importada con el prefijo Facades:

<?php
 
namespace App\Models;
 
use App\Contracts\Publisher;
use Facades\App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;
 
class Podcast extends Model
{
/**
* Publicar el podcast.
*/
public function publish(Publisher $publisher): void
public function publish(): void
{
$this->update(['publishing' => now()]);
 
$publisher->publish($this);
Publisher::publish($this);
}
}

Cuando se utiliza la fachada en tiempo real, la implementación del publisher se resolverá del contenedor de servicios utilizando la parte de la interfaz o el nombre de la clase que aparece después del prefijo Facades. Al realizar pruebas, podemos usar las funciones de prueba de fachadas integradas en Laravel para simular esta llamada al método:

<?php
 
namespace Tests\Feature;
 
use App\Models\Podcast;
use Facades\App\Contracts\Publisher;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
 
class PodcastTest extends TestCase
{
use RefreshDatabase;
 
/**
* Un ejemplo de prueba.
*/
public function test_podcast_can_be_published(): void
{
$podcast = Podcast::factory()->create();
 
Publisher::shouldReceive('publish')->once()->with($podcast);
 
$podcast->publish();
}
}

Referencia de Clases de Facades

A continuación, encontrarás cada fachada y su clase subyacente. Esta es una herramienta útil para explorar rápidamente la documentación de la API para una fachada específica. También se incluye la clave de enlace del contenedor de servicios cuando sea aplicable.

Fachada Clase Enlace del Contenedor de Servicios
App Illuminate\Foundation\Application app
Artisan Illuminate\Contracts\Console\Kernel artisan
Auth Illuminate\Auth\AuthManager auth
Auth (Instance) Illuminate\Contracts\Auth\Guard auth.driver
Blade Illuminate\View\Compilers\BladeCompiler blade.compiler
Broadcast Illuminate\Contracts\Broadcasting\Factory  
Broadcast (Instance) Illuminate\Contracts\Broadcasting\Broadcaster  
Bus Illuminate\Contracts\Bus\Dispatcher  
Cache Illuminate\Cache\CacheManager cache
Cache (Instance) Illuminate\Cache\Repository cache.store
Config Illuminate\Config\Repository config
Cookie Illuminate\Cookie\CookieJar cookie
Crypt Illuminate\Encryption\Encrypter encrypter
Date Illuminate\Support\DateFactory date
DB Illuminate\Database\DatabaseManager db
DB (Instance) Illuminate\Database\Connection db.connection
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  
Lang Illuminate\Translation\Translator translator
Log Illuminate\Log\LogManager log
Mail Illuminate\Mail\Mailer mailer
Notification Illuminate\Notifications\ChannelManager  
Password Illuminate\Auth\Passwords\PasswordBrokerManager auth.password
Password (Instance) Illuminate\Auth\Passwords\PasswordBroker auth.password.broker
Pipeline (Instance) Illuminate\Pipeline\Pipeline  
Process Illuminate\Process\Factory  
Queue Illuminate\Queue\QueueManager queue
Queue (Instance) Illuminate\Contracts\Queue\Queue queue.connection
Queue (Base Class) Illuminate\Queue\Queue  
Redirect Illuminate\Routing\Redirector redirect
Redis Illuminate\Redis\RedisManager redis
Redis (Instance) Illuminate\Redis\Connections\Connection redis.connection
Request Illuminate\Http\Request request
Response Illuminate\Contracts\Routing\ResponseFactory  
Response (Instance) Illuminate\Http\Response  
Route Illuminate\Routing\Router router
Schema Illuminate\Database\Schema\Builder  
Session Illuminate\Session\SessionManager session
Session (Instance) Illuminate\Session\Store session.store
Storage Illuminate\Filesystem\FilesystemManager filesystem
Storage (Instance) Illuminate\Contracts\Filesystem\Filesystem filesystem.disk
URL Illuminate\Routing\UrlGenerator url
Validator Illuminate\Validation\Factory validator
Validator (Instance) Illuminate\Validation\Validator  
View Illuminate\View\Factory view
View (Instance) Illuminate\View\View  
Vite Illuminate\Foundation\Vite