> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Facades

> Explicamos el funcionamiento y uso de las facades de Laravel, las facades en tiempo real, cómo probarlas y cuándo usarlas frente a la inyección de dependencias.

## ¿Qué es una facade?

Una facade proporciona una interfaz "estática" a las clases disponibles en el [contenedor de servicios](/es/service-container) de la aplicación. Laravel incluye numerosas facades que dan acceso a casi todas sus funcionalidades.

Las facades de Laravel funcionan como "proxies estáticos" sobre las clases reales del contenedor y ofrecen una sintaxis concisa y expresiva manteniendo mejor testabilidad y flexibilidad que los métodos estáticos tradicionales.

Todas las facades de Laravel están en el namespace `Illuminate\Support\Facades`.

```php theme={null}
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Route;

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

<Info>
  No pasa nada si aún no comprendes por completo su funcionamiento. Empieza por aprender a usarlas y continúa aprendiendo Laravel.
</Info>

## Cómo funciona una facade

En una aplicación Laravel, una facade es una clase que da acceso a un objeto del contenedor. Este mecanismo se implementa con la clase `Facade`. Todas las facades de Laravel y las tuyas propias extienden la clase base `Illuminate\Support\Facades\Facade`.

La clase base `Facade` utiliza el método mágico `__callStatic()` para delegar las llamadas a la facade al objeto resuelto desde el contenedor.

```mermaid theme={null}
flowchart LR
    A["Cache::get('key')"] --> B["Facade::__callStatic()"]
    B --> C["getFacadeAccessor()<br>→ 'cache'"]
    C --> D["Contenedor de servicios<br>make('cache')"]
    D --> E["Instancia real<br>CacheManager"]
    E --> F["Ejecuta<br>get('key')"]
```

```php theme={null}
<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Cache;
use Illuminate\View\View;

class UserController extends Controller
{
    /**
     * Muestra el perfil del usuario indicado
     */
    public function showProfile(string $id): View
    {
        $user = Cache::get('user:'.$id);

        return view('profile', ['user' => $user]);
    }
}
```

Importamos la fachada `Cache` en la parte superior del archivo. Esa fachada actúa como proxy hacia una implementación de la interfaz `Illuminate\Contracts\Cache\Factory`. Todas las llamadas a través de la fachada se pasan a la instancia interna del servicio de caché de Laravel.

Si miras la clase `Illuminate\Support\Facades\Cache`, verás que no existe el método estático `get`.

```php theme={null}
class Cache extends Facade
{
    /**
     * Obtiene el nombre registrado del componente
     */
    protected static function getFacadeAccessor(): string
    {
        return 'cache';
    }
}
```

`Cache` extiende la clase base `Facade` y define `getFacadeAccessor()`. Este método devuelve el nombre del binding en el contenedor. Cuando llamas a un método estático de `Cache`, Laravel resuelve el binding `cache` del contenedor y ejecuta el método solicitado (`get` en este caso) sobre el objeto obtenido.

## Cuándo usar facades y cuándo no

### Ventajas de las facades

Ofrecen una sintaxis concisa y fácil de recordar para usar las funcionalidades de Laravel, sin necesidad de recordar los nombres de clase largos que habría que inyectar o configurar manualmente. Además, gracias al uso particular de los métodos dinámicos de PHP, son fáciles de probar.

### Cuidado con el crecimiento del ámbito

Un peligro habitual al usar facades es la "acumulación de responsabilidades" en la clase. Como son cómodas y no requieren inyección, es fácil que la clase se hinche usando muchas facades. Con la inyección de dependencias, un constructor grande te avisa visualmente. Al usar facades, mantén las clases pequeñas y con responsabilidad acotada.

<Warning>
  Si notas que una clase crece demasiado, considera dividirla en clases más pequeñas.
</Warning>

### Facades vs. inyección de dependencias

Una gran ventaja de la inyección de dependencias es poder sustituir la implementación inyectada. Es útil en las pruebas: puedes inyectar mocks o stubs y comprobar qué métodos se han llamado sobre ellos.

Los métodos estáticos "puros" no se pueden mockear normalmente, pero las facades sí, ya que redirigen las llamadas al objeto del contenedor mediante métodos dinámicos. Se pueden probar como si se tratara de una instancia inyectada.

```php theme={null}
use Illuminate\Support\Facades\Cache;

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

Para esta ruta puedes escribir la siguiente prueba comprobando que `Cache::get` se llama con los argumentos esperados.

```php theme={null}
use Illuminate\Support\Facades\Cache;

test('basic example', function () {
    Cache::shouldReceive('get')
        ->with('key')
        ->andReturn('value');

    $response = $this->get('/cache');

    $response->assertSee('value');
});
```

### Facades vs. funciones helper

Además de las facades, Laravel ofrece funciones "helper" para tareas comunes: crear vistas, disparar eventos, despachar jobs, enviar respuestas HTTP, etc. Muchas hacen lo mismo que la facade correspondiente.

```php theme={null}
// Llamada usando la fachada
return Illuminate\Support\Facades\View::make('profile');

// Llamada equivalente con función helper
return view('profile');
```

No hay diferencia sustancial entre facades y helpers. Aunque uses helpers, puedes hacer las mismas pruebas que con las facades.

```php theme={null}
use Illuminate\Support\Facades\Cache;

test('cache helper test', function () {
    Cache::shouldReceive('get')
        ->with('key')
        ->andReturn('value');

    $response = $this->get('/cache');

    $response->assertSee('value');
});
```

## Facades en tiempo real

Con las facades en tiempo real, puedes tratar cualquier clase de tu aplicación como una fachada. Veamos primero un ejemplo sin usarlas.

Supón que el modelo `Podcast` tiene un método `publish`. Para publicar el podcast necesita una instancia de `Publisher`.

```php theme={null}
<?php

namespace App\Models;

use App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;

class Podcast extends Model
{
    /**
     * Publica el podcast
     */
    public function publish(Publisher $publisher): void
    {
        $this->update(['publishing' => now()]);

        $publisher->publish($this);
    }
}
```

Con una facade en tiempo real puedes mantener la misma testabilidad sin tener que pasar explícitamente la instancia de `Publisher`. Para crearla, añade el prefijo `Facades` al namespace de la clase que importas.

```php theme={null}
<?php

namespace App\Models;

use Facades\App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;

class Podcast extends Model
{
    /**
     * Publica el podcast
     */
    public function publish(): void
    {
        $this->update(['publishing' => now()]);

        Publisher::publish($this);
    }
}
```

Cuando se usa una facade en tiempo real, la implementación se resuelve desde el contenedor usando la parte de interfaz o clase que aparece después del prefijo `Facades`.

```php theme={null}
<?php

use App\Models\Podcast;
use Facades\App\Contracts\Publisher;
use Illuminate\Foundation\Testing\RefreshDatabase;

pest()->use(RefreshDatabase::class);

test('podcast can be published', function () {
    $podcast = Podcast::factory()->create();

    Publisher::shouldReceive('publish')->once()->with($podcast);

    $podcast->publish();
});
```

<Tip>
  Las facades en tiempo real son útiles cuando quieres poder mockear en pruebas sin tener que pasar dependencias como argumentos.
</Tip>

## Cómo probar facades

Para probar una facade usa `shouldReceive`, que devuelve una instancia mock de Mockery. Como las facades se resuelven y gestionan a través del contenedor, son mucho más fáciles de probar que los métodos estáticos habituales.

```php theme={null}
use Illuminate\Support\Facades\Cache;

test('mostrar el perfil del usuario', function () {
    Cache::shouldReceive('get')
        ->once()
        ->with('user:1')
        ->andReturn(['name' => 'Taylor']);

    $response = $this->get('/users/1');

    $response->assertSee('Taylor');
});
```

Métodos habituales del mock:

| Método                    | Descripción                                 |
| ------------------------- | ------------------------------------------- |
| `shouldReceive('method')` | Se espera que se llame al método            |
| `once()`                  | Se espera una única llamada                 |
| `times(n)`                | Se esperan n llamadas                       |
| `with(args)`              | Se espera que se llame con estos argumentos |
| `andReturn(value)`        | Devuelve el valor indicado                  |
| `andReturnNull()`         | Devuelve null                               |

## Lista de facades principales

Tabla de facades habituales, sus clases reales y sus bindings en el contenedor.

| Facade         | Clase                                     | 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`       |

## Próximos pasos

<Card title="Contracts (contratos)" icon="file-contract" href="/es/contracts">
  Aprende sobre los Contracts, la contraparte conceptual de las facades, y cuándo elegir uno u otro.
</Card>


## Related topics

- [Análisis estático de paquetes (PHPStan / Larastan)](/es/advanced/package-static-analysis.md)
- [Desarrollo de paquetes Laravel](/es/advanced/package-development.md)
- [Contracts (contratos)](/es/contracts.md)
- [Mocking](/es/mocking.md)
- [Contenedor de servicios](/es/service-container.md)
