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

# Extensions Blade d'un package et cache de compilation

> En analysant le BladeCompiler de Laravel 13, découvrez comment enregistrer des directives et des conditions personnalisées, séparer la compilation de l'exécution et vérifier le cache des vues lors des mises à jour d'un package.

Pour fournir une syntaxe Blade depuis un package, séparez **le traitement qui convertit le template en PHP** du **traitement qui exécute le PHP généré**. Si vous intégrez la valeur de configuration actuelle au moment de la compilation, les vues mises en cache peuvent continuer à afficher une ancienne valeur.

Cette page s'appuie sur la documentation officielle de Laravel `13.x` et sur l'implémentation du Framework `v13.37.0` pour approfondir les [bases du développement de packages](/fr/advanced/package-development). Pour la syntaxe classique des templates, consultez [Blade](/fr/blade) ; pour les namespaces et la publication des vues, consultez [Surcharger et mettre à jour les vues d'un package](/fr/advanced/package-views).

## Distinguer enregistrement, compilation et exécution

Le callback passé à `Blade::directive()` ne renvoie pas la valeur à afficher, mais **une chaîne de code PHP à générer**. L'argument `$expression` n'est pas non plus une valeur évaluée : c'est l'expression PHP écrite dans le template.

```mermaid theme={null}
flowchart TD
    A["Enregistrement de l'extension dans le boot du provider"] --> B["Rendu de la vue"]
    B --> C{"Compilation nécessaire ?"}
    C -->|Oui| D["Le callback de directive<br>génère le code PHP"]
    D --> E["Enregistrement du résultat compilé"]
    C -->|Non| F["Utilisation du PHP enregistré"]
    E --> G["Exécution du PHP pour générer le HTML"]
    F --> G
    G --> H["Lecture de la configuration et des arguments à l'exécution"]
```

| API | Rôle du callback enregistré | Moment de l'exécution |
| - | - | - |
| `Blade::directive()` | Générer une chaîne de code PHP | Lors de la compilation de la directive ciblée |
| `Blade::if()` | Évaluer la condition | Lorsque le PHP généré appelle `Blade::check()` |

La compilation a également lieu avec `view:cache`. Concevez le callback de génération d'une directive de sorte qu'il ne récupère pas l'utilisateur courant, n'écrive pas en base de données et n'appelle pas d'API externe.

## Enregistrer sous un nom propre au package

À titre d'exemple, nous fournissons `@acmeCourierLabel($code)`, qui affiche un libellé configuré devant un code d'expédition. On suppose que le PSR-4 de Composer fait correspondre `Acme\Courier\` à `src/` et que le service provider est enregistré par [découverte automatique](/fr/advanced/package-discovery) ou manuellement.

```php src/CourierServiceProvider.php theme={null}
<?php

namespace Acme\Courier;

use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;

class CourierServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Blade::directive('acmeCourierLabel', function (string $expression): string {
            return "<?php echo e((string) config('courier.label', 'Tracking').': '.({$expression})); ?>";
        });

        Blade::if('acmeCourierEnabled', function (): bool {
            return (bool) config('courier.enabled', false);
        });
    }
}
```

Dans cet exemple, le contrat de configuration prévoit que `courier.label` est une chaîne et `courier.enabled` un booléen. Pour la distribution et la fusion du fichier de configuration, consultez [Fusion et cache de la configuration des packages](/fr/advanced/package-config-merging).

Effectuez l'enregistrement dans le `boot()` habituel du provider, sans l'entourer d'une condition `runningInConsole()`. La même extension est nécessaire à la fois pour le rendu HTTP et pour la commande Artisan `view:cache`. Évitez aussi de faire d'un provider qui n'enregistre que des extensions Blade un provider différé, qui ne démarre qu'à la résolution d'un autre service.

### Recevoir l'argument comme une expression, pas comme une valeur

```blade theme={null}
@acmeCourierLabel($code)
```

Avec ce template, le callback reçoit la chaîne `$code`. Le PHP généré prend la forme suivante.

```php theme={null}
<?php echo e((string) config('courier.label', 'Tracking').': '.($code)); ?>
```

`config()` et `$code` sont évalués au moment où ce PHP est exécuté. C'est différent d'une implémentation dans laquelle le callback lirait lui-même `config()` et renverrait une chaîne figée.

D'après l'implémentation examinée, `callCustomDirective()` retire les parenthèses extérieures, applique un trim à l'expression et la transmet au callback. Il ne convertit pas l'argument en valeur PHP et ne le découpe pas en arguments individuels. Cet exemple est exposé comme **une syntaxe qui reçoit une seule expression obligatoire**.

Si vous gérez plusieurs arguments, ne vous contentez pas d'un `explode()` sur les virgules. Les tableaux, les appels de méthode et les chaînes littérales peuvent eux aussi contenir des virgules. Si vous souhaitez gérer des attributs ou du HTML complexe, fournir un [composant Blade](/fr/blade) permet de mieux séparer les responsabilités.

<Warning>
  Les expressions d'un template sont du PHP écrit par des développeurs de confiance. Ne construisez pas la source d'un template à partir d'entrées utilisateur. Par ailleurs, l'`echo` d'une directive personnalisée ne bénéficie pas automatiquement de l'échappement habituel de `{{ }}`. Dans cet exemple, le PHP généré appelle explicitement `e()`.
</Warning>

### Les conflits de noms sont aussi un problème de compatibilité

`directive()` stocke les handlers dans un tableau dont la clé est le nom. Un même nom écrase l'enregistrement précédent, et `compileStatement()` choisit les directives personnalisées avant les méthodes de conversion intégrées. Les tests officiels contiennent d'ailleurs un cas où un enregistrement personnalisé écrase `foreach`.

Évitez les noms génériques comme `label` ou `enabled` ainsi que les noms intégrés, et ajoutez un préfixe propre au package. Traitez les noms et arguments utilisés dans les templates comme une API publique, et fournissez une procédure de migration lorsque vous les modifiez.

## Évaluer les conditions à l'exécution avec Blade::if

La condition enregistrée dans le provider ci-dessus s'utilise comme suit.

```blade theme={null}
@acmeCourierEnabled
    @acmeCourierLabel($code)
@else
    Le suivi des expéditions est désactivé.
@endacmeCourierEnabled
```

`Blade::if()` enregistre le callback de condition, puis les directives d'ouverture, `unless`, `else` et de fermeture. Dans cet exemple, la partie d'ouverture est convertie en PHP comme suit.

```php theme={null}
<?php if (\Illuminate\Support\Facades\Blade::check('acmeCourierEnabled')): ?>
```

Le callback de condition qui lit la configuration est appelé par `check()` à l'exécution. Le résultat true ou false n'est pas figé au moment de la compilation. Le callback de condition doit donc aussi être enregistré dans les processus HTTP qui utilisent des vues compilées.

Cette syntaxe sert à basculer l'affichage ; elle ne constitue pas une autorisation des opérations d'expédition. Appliquez également le contrôle d'accès au niveau des routes et des opérations.

## Une mise à jour du package ne régénère pas forcément les vues

D'après l'implémentation examinée, `Compiler::isExpired()` vérifie l'existence du cache et, selon la configuration, les dates de modification de la vue source et du fichier compilé. **Il ne suit pas les modifications des directives écrites dans le provider comme des fichiers dépendants.**

| Modification | Effet sur le PHP compilé |
| - | - |
| Modification du code renvoyé par `directive()` | L'ancien PHP subsiste, une recompilation est nécessaire |
| Modification du seul traitement du callback de condition de `Blade::if()` | Le `check()` déjà généré peut appeler le nouveau traitement, mais le nouveau code doit être chargé |
| Modification du nom de la directive ou du contrat de ses arguments | Les templates des utilisateurs doivent être corrigés et recompilés |
| Vues déjà publiées dans l'application | La mise à jour des vues du package ne met pas à jour les copies publiées |

La documentation officielle indique elle aussi de supprimer le cache avec `view:clear` après avoir modifié la logique d'une directive. Exécutez-la dans le processus de déploiement de l'application utilisatrice, une fois le package mis à jour et les vues de l'utilisateur alignées.

```bash theme={null}
php artisan view:clear
php artisan view:cache
```

Exécutez `view:cache` lorsque vous précompilez en production. Ne videz pas le cache à chaque fois depuis le `boot()` du package, et ne réécrivez pas sans autorisation le processus de déploiement de l'application utilisatrice lors de l'installation. Le rafraîchissement du cache de configuration et le rechargement des processus résidents suivent également la procédure de déploiement habituelle de l'environnement utilisateur.

## Vérifier séparément le résultat compilé et le résultat du rendu

Commencez par vérifier le PHP généré dans une application Laravel de test où le provider ci-dessus est enregistré. Voici une méthode à ajouter à un test Feature qui hérite de `Tests\TestCase`.

```php theme={null}
public function test_label_directive_compiles_to_runtime_lookup(): void
{
    $compiled = \Illuminate\Support\Facades\Blade::compileString(
        '@acmeCourierLabel($code)',
    );

    $this->assertSame(
        "<?php echo e((string) config('courier.label', 'Tracking').': '.(\$code)); ?>",
        $compiled,
    );
}
```

Ce test permet de vérifier le contrat de génération du PHP, mais pas l'échappement ni les branches conditionnelles à l'exécution. Dans un vrai package, ajoutez aussi des vérifications du rendu des vues et des mises à jour.

| Cas à vérifier | Résultat attendu |
| - | - |
| Passer au code d'expédition des caractères interprétés comme du HTML | Ils sont échappés par le `e()` généré |
| Utiliser la même vue compilée et modifier le libellé configuré avant le rendu | Le rendu suivant affiche la nouvelle valeur de configuration |
| Rendu avec `courier.enabled` à true puis à false | Seule la branche correspondante est affichée |
| Démarrage d'une nouvelle application après `view:cache` | L'extension est enregistrée et le résultat est identique à celui obtenu sans précompilation |
| Déploiement après modification du code généré par la directive | Le nouveau PHP est utilisé après la recréation du cache |
| Mise à jour de la version de Laravel prise en charge | Les tests de code généré, de rendu et d'utilisation du cache passent |

## Pages connexes

<Columns cols={2}>
  <Card title="Surcharger et mettre à jour les vues d'un package" icon="eye" href="/fr/advanced/package-views">
    Découvrez l'ordre de recherche des namespaces et comment maintenir les templates publiés.
  </Card>

  <Card title="Cache d'un package et intégration à optimize" icon="gears" href="/fr/advanced/package-optimization">
    Découvrez comment intégrer la création et la suppression d'un cache personnalisé au processus de déploiement.
  </Card>
</Columns>

## Sources primaires consultées

* [Documentation officielle de Laravel : Extending Blade et Custom if statements](https://github.com/laravel/docs/blob/12080c72699b99ec6573f7e79ff4834d9001b6bc/blade.md#extending-blade)
* [Documentation officielle de Laravel : vues et composants des packages](https://github.com/laravel/docs/blob/12080c72699b99ec6573f7e79ff4834d9001b6bc/packages.md#views)
* [BladeCompiler : directive(), callCustomDirective(), compileStatement(), if() et check()](https://github.com/laravel/framework/blob/v13.37.0/src/Illuminate/View/Compilers/BladeCompiler.php)
* [Compiler : évaluation du cache par isExpired()](https://github.com/laravel/framework/blob/v13.37.0/src/Illuminate/View/Compilers/Compiler.php)
* [BladeCustomTest : directives personnalisées, conditions et écrasement de la syntaxe intégrée](https://github.com/laravel/framework/blob/v13.37.0/tests/View/Blade/BladeCustomTest.php)


## Related topics

- [Sujets avancés](/fr/advanced/index.md)
- [Enregistrement et mise en cache des écouteurs d'événements d'un package](/fr/advanced/package-events.md)
- [Cache d'un package et intégration à optimize](/fr/advanced/package-optimization.md)
- [Enregistrement et cache des routes d'un package](/fr/advanced/package-routes.md)
- [Surcharger et mettre à jour les vues d'un package](/fr/advanced/package-views.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.