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

# Façades

> Fonctionnement et usage des façades Laravel, façades en temps réel, tests et comparaison avec l'injection de dépendances.

## Qu'est-ce qu'une façade

Une façade fournit une interface « statique » aux classes disponibles dans le [conteneur de services](/fr/service-container) de l'application. Laravel inclut de nombreuses façades qui donnent accès à presque toutes ses fonctionnalités.

Les façades agissent comme des « proxys statiques » vers des classes concrètes du conteneur de services, offrant une syntaxe concise et expressive tout en étant plus testables et plus flexibles que les méthodes statiques classiques.

Toutes les façades Laravel sont définies dans le 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>
  Il n'est pas nécessaire de comprendre totalement leur fonctionnement pour les utiliser. Commencez par les utiliser et poursuivez votre apprentissage de Laravel.
</Info>

## Fonctionnement des façades

Dans une application Laravel, une façade est une classe qui fournit un accès à un objet du conteneur. Ce mécanisme est assuré par la classe `Facade`. Toutes les façades de Laravel (et vos façades personnalisées) héritent de la classe de base `Illuminate\Support\Facades\Facade`.

La classe `Facade` de base utilise la méthode magique `__callStatic()` pour déléguer les appels sur la façade à l'objet résolu par le conteneur.

```mermaid theme={null}
flowchart LR
    A["Cache::get('key')"] --> B["Facade::__callStatic()"]
    B --> C["getFacadeAccessor()<br>→ 'cache'"]
    C --> D["Conteneur de services<br>make('cache')"]
    D --> E["Instance de la classe réelle<br>CacheManager"]
    E --> F["Exécution de<br>get('key')"]
```

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

namespace App\Http\Controllers;

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

class UserController extends Controller
{
    /**
     * Affiche le profil de l'utilisateur donné.
     */
    public function showProfile(string $id): View
    {
        $user = Cache::get('user:'.$id);

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

En tête du fichier, on importe la façade `Cache`. Elle fait office de proxy vers l'implémentation de l'interface `Illuminate\Contracts\Cache\Factory`. Tous les appels via cette façade sont transmis à l'instance interne du service de cache.

Regardons la classe `Illuminate\Support\Facades\Cache` : la méthode statique `get` n'y existe pas.

```php theme={null}
class Cache extends Facade
{
    /**
     * Retourne le nom d'enregistrement du composant.
     */
    protected static function getFacadeAccessor(): string
    {
        return 'cache';
    }
}
```

La façade `Cache` étend `Facade` et définit `getFacadeAccessor()`. Cette méthode retourne le nom du binding dans le conteneur. Quand on appelle une méthode statique sur `Cache`, Laravel résout le binding `cache` depuis le conteneur puis exécute la méthode demandée (ici `get`) sur l'objet obtenu.

## Quand utiliser (ou éviter) les façades

### Avantages des façades

Les façades offrent une syntaxe concise et mémorisable pour utiliser Laravel sans avoir à retenir des noms de classes longs à injecter et configurer. Grâce à l'utilisation particulière des méthodes dynamiques PHP, elles sont aussi faciles à tester.

### Attention au scope creep

Le principal risque est le « gonflement » de vos classes. Les façades étant simples à utiliser et sans injection, on est tenté d'en ajouter de plus en plus. Avec l'injection de dépendances, un constructeur volumineux vous alerte visuellement. Restez donc attentif à la taille de vos classes et gardez leurs responsabilités restreintes.

<Warning>
  Si une classe devient trop grande, envisagez de la découper en plusieurs classes plus petites.
</Warning>

### Façades vs. injection de dépendances

L'un des grands atouts de l'injection est la possibilité de substituer l'implémentation d'une classe injectée. Utile pour les tests : on injecte un mock/stub et on vérifie les appels de méthodes.

Les méthodes statiques réelles ne peuvent pas être mockées en général, mais les façades s'appuient sur des méthodes dynamiques qui délèguent au conteneur. On peut donc les tester comme une instance injectée.

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

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

Vous pouvez écrire ce test pour vérifier que `Cache::get` a été appelée avec les bons arguments.

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

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

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

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

### Façades vs. helpers

Outre les façades, Laravel propose des fonctions « helper » pour les tâches courantes : créer une vue, déclencher un événement, dispatcher un job, envoyer une réponse HTTP, etc. Beaucoup de helpers font la même chose que la façade correspondante.

```php theme={null}
// Via la façade
return Illuminate\Support\Facades\View::make('profile');

// Équivalent avec le helper
return view('profile');
```

Il n'y a pas de différence réelle entre les deux. Vous pouvez tester le helper comme la façade équivalente.

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

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

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

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

## Façades en temps réel

Les façades en temps réel permettent de traiter n'importe quelle classe de l'application comme une façade. Voyons d'abord un code sans façade en temps réel.

Supposons que le modèle `Podcast` ait une méthode `publish`. Publier un podcast nécessite d'injecter une instance `Publisher`.

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

namespace App\Models;

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

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

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

Avec une façade en temps réel, on n'a plus besoin de passer explicitement `Publisher` tout en gardant la testabilité. On préfixe le namespace de la classe importée par `Facades`.

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

namespace App\Models;

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

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

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

À l'usage, l'interface ou la classe située après `Facades` est résolue par le conteneur pour obtenir l'implémentation du publisher.

```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>
  Les façades en temps réel sont utiles pour simplifier le mocking pendant les tests, sans devoir passer d'argument.
</Tip>

## Tests des façades

Pour tester une façade, utilisez `shouldReceive` qui retourne une instance mock Mockery. Comme la façade est résolue via le conteneur, elle est bien plus testable qu'une classe statique classique.

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

test('affiche le profil utilisateur', function () {
    Cache::shouldReceive('get')
        ->once()
        ->with('user:1')
        ->andReturn(['name' => 'Taylor']);

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

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

Méthodes de mock fréquentes :

| Méthode                   | Description                               |
| ------------------------- | ----------------------------------------- |
| `shouldReceive('method')` | S'attend à ce que la méthode soit appelée |
| `once()`                  | Une seule fois                            |
| `times(n)`                | n fois                                    |
| `with(args)`              | Avec des arguments donnés                 |
| `andReturn(value)`        | Retourne la valeur spécifiée              |
| `andReturnNull()`         | Retourne null                             |

## Principales façades

Correspondance entre façades courantes, leur classe concrète et le nom du binding du conteneur.

| Façade         | 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`       |

## Prochaines étapes

<Card title="Contrats" icon="file-contract" href="/fr/contracts">
  Découvrez le concept de contrats, complément des façades, et quand les utiliser.
</Card>


## Related topics

- [Analyse statique de packages (PHPStan / Larastan)](/fr/advanced/package-static-analysis.md)
- [Développement de packages Laravel](/fr/advanced/package-development.md)
- [Contrats](/fr/contracts.md)
- [Conteneur de services](/fr/service-container.md)
- [Journalisation](/fr/logging.md)
