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

# Blade-Erweiterungen und Kompilierungscache in Paketen

> Erläutert anhand des BladeCompilers von Laravel 13 die Registrierung eigener Direktiven und Bedingungen, die Trennung von Kompilierzeit und Laufzeit sowie die Prüfung des View-Caches bei Paket-Updates.

Wenn ein Paket eine eigene Blade-Syntax bereitstellt, trennen Sie **die Umwandlung des Templates in PHP** von **der Ausführung des erzeugten PHP**. Wenn Sie aktuelle Konfigurationswerte zur Kompilierzeit einbetten, können gecachte Views weiterhin veraltete Werte anzeigen.

Diese Seite stützt sich auf die offizielle Laravel-Dokumentation `13.x` sowie die Implementierung von Framework `v13.37.0` und vertieft die [Grundlagen der Paketentwicklung](/de/advanced/package-development). Die gewöhnliche Template-Syntax finden Sie unter [Blade](/de/blade), Namespaces und das Veröffentlichen von Views unter [Paket-Views überschreiben und aktualisieren](/de/advanced/package-views).

## Registrierung, Kompilierung und Ausführung unterscheiden

Der an `Blade::directive()` übergebene Callback gibt nicht den anzuzeigenden Wert zurück, sondern **einen String mit dem zu erzeugenden PHP-Code**. Auch das Argument `$expression` ist kein ausgewerteter Wert, sondern der im Template geschriebene PHP-Ausdruck.

```mermaid theme={null}
flowchart TD
    A["Erweiterung in boot<br>des Providers registrieren"] --> B["View rendern"]
    B --> C{"Kompilierung nötig?"}
    C -->|Ja| D["PHP-Code im Callback<br>der Direktive erzeugen"]
    D --> E["Kompilierungsergebnis speichern"]
    C -->|Nein| F["Gespeichertes PHP verwenden"]
    E --> G["PHP ausführen und HTML erzeugen"]
    F --> G
    G --> H["Konfiguration und Argumente<br>zur Laufzeit lesen"]
```

| API | Aufgabe des registrierten Callbacks | Zeitpunkt der Ausführung |
| - | - | - |
| `Blade::directive()` | Erzeugt einen String mit PHP-Code | Beim Kompilieren der betreffenden Direktive |
| `Blade::if()` | Wertet die Bedingung aus | Wenn das erzeugte PHP `Blade::check()` aufruft |

Auch `view:cache` führt eine Kompilierung durch. Gestalten Sie den erzeugenden Callback einer Direktive so, dass er weder den aktuellen Benutzer abruft noch in die Datenbank schreibt oder externe APIs aufruft.

## Mit paketspezifischen Namen registrieren

Als Beispiel stellen wir `@acmeCourierLabel($code)` bereit, das vor einem Sendungscode ein konfiguriertes Label anzeigt. Vorausgesetzt wird, dass `Acme\Courier\` per PSR-4 in Composer auf `src/` abgebildet ist und der Provider per [automatischer Erkennung](/de/advanced/package-discovery) oder manuell registriert wird.

```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);
        });
    }
}
```

In diesem Beispiel gilt als Konfigurationsvertrag, dass `courier.label` ein String und `courier.enabled` ein Boolean ist. Zum Ausliefern und Zusammenführen von Konfigurationsdateien siehe [Paketkonfiguration zusammenführen und cachen](/de/advanced/package-config-merging).

Registrieren Sie die Erweiterungen in `boot()` eines gewöhnlichen Providers und umschließen Sie sie nicht mit einer `runningInConsole()`-Bedingung. Dieselben Erweiterungen werden sowohl beim Rendern über HTTP als auch beim Artisan-Befehl `view:cache` benötigt. Vermeiden Sie es außerdem, einen Provider, der nur Blade-Erweiterungen registriert, als Deferred Provider zu gestalten, der erst bei der Auflösung eines anderen Service startet.

### Argumente als Ausdruck statt als Wert empfangen

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

Bei diesem Template erhält der Callback den String `$code`. Das erzeugte PHP sieht folgendermaßen aus:

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

`config()` und `$code` werden erst ausgewertet, wenn dieses PHP ausgeführt wird. Das unterscheidet sich von einer Implementierung, bei der der Callback selbst `config()` liest und einen festen String zurückgibt.

Das untersuchte `callCustomDirective()` entfernt die äußeren runden Klammern, trimmt den Ausdruck und übergibt ihn an den Callback. Es wandelt das Argument weder in einen PHP-Wert um noch zerlegt es ihn in einzelne Argumente. Dieses Beispiel veröffentlichen wir als **Syntax, der genau ein erforderlicher Ausdruck übergeben wird**.

Wenn Sie mehrere Argumente verarbeiten, zerlegen Sie den Ausdruck nicht einfach mit `explode()` an Kommas. Auch Arrays, Methodenaufrufe und String-Literale können Kommas enthalten. Wenn Sie Attribute oder komplexes HTML verarbeiten möchten, lassen sich die Zuständigkeiten leichter trennen, indem Sie die Funktion als [Blade-Komponente](/de/blade) bereitstellen.

<Warning>
  Ausdrücke in Templates sind PHP, das von vertrauenswürdigen Entwicklern geschrieben wird. Setzen Sie Template-Quelltext nicht aus Benutzereingaben zusammen. Außerdem erhält ein `echo` in einer eigenen Direktive nicht automatisch die Maskierung von gewöhnlichem `{{ }}`. In diesem Beispiel ruft das erzeugte PHP ausdrücklich `e()` auf.
</Warning>

### Auch Namenskollisionen sind ein Kompatibilitätsproblem

`directive()` speichert den Handler in einem Array mit dem Namen als Schlüssel. Bei gleichem Namen wird die vorherige Registrierung überschrieben, und `compileStatement()` wählt eigene Direktiven vor den eingebauten Umwandlungsmethoden. Auch die offiziellen Tests enthalten einen Fall, in dem `foreach` durch eine eigene Registrierung überschrieben wird.

Vermeiden Sie allgemeine Namen wie `label` oder `enabled` sowie eingebaute Namen und verwenden Sie ein paketspezifisches Präfix. Behandeln Sie die Namen und Argumente, die Nutzer in ihren Templates verwenden, als öffentliche API und stellen Sie bei Änderungen eine Migrationsanleitung bereit.

## Bedingungen mit Blade::if zur Laufzeit auswerten

Die im obigen Provider registrierte Bedingung können Sie wie folgt verwenden:

```blade theme={null}
@acmeCourierEnabled
    @acmeCourierLabel($code)
@else
    Die Sendungsverfolgung ist deaktiviert.
@endacmeCourierEnabled
```

`Blade::if()` speichert den Bedingungs-Callback und registriert anschließend Direktiven für den Beginn sowie für `unless`, `else` und das Ende. Der Beginn in diesem Beispiel wird in folgendes PHP umgewandelt:

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

Der Bedingungs-Callback, der die Konfiguration prüft, wird zur Laufzeit von `check()` aufgerufen. Das Ergebnis true oder false wird nicht zur Kompilierzeit festgeschrieben. Auch in HTTP-Prozessen, die kompilierte Views verwenden, muss der Bedingungs-Callback registriert sein.

Diese Syntax schaltet lediglich die Anzeige um und ist keine Autorisierung für Versandoperationen. Setzen Sie die Zugriffskontrolle zusätzlich auf Ebene der Routen bzw. Operationen um.

## Views werden bei Paket-Updates nicht unbedingt automatisch neu erzeugt

Das untersuchte `Compiler::isExpired()` prüft, ob ein Cache vorhanden ist, und vergleicht je nach Konfiguration die Änderungszeiten der Quell-View und der kompilierten Datei. **Änderungen an Direktiven, die im Provider definiert sind, werden dabei nicht als abhängige Dateien verfolgt.**

| Änderung | Auswirkung auf das kompilierte PHP |
| - | - |
| Den von `directive()` zurückgegebenen Code ändern | Veraltetes PHP bleibt erhalten, daher ist eine Neukompilierung nötig |
| Nur die Verarbeitung im Bedingungs-Callback von `Blade::if()` ändern | Das erzeugte `check()` kann die neue Verarbeitung aufrufen, der neue Code muss aber geladen werden |
| Namen oder Argumentvertrag einer Direktive ändern | Anpassung der Templates durch die Nutzer und Neukompilierung nötig |
| Views wurden bereits in die Anwendung veröffentlicht | Ein Update der Views im Paket allein aktualisiert die veröffentlichten Kopien nicht |

Auch die offizielle Dokumentation empfiehlt, nach Änderungen an der Logik einer Direktive den Cache mit `view:clear` zu löschen. Führen Sie dies im Deployment-Ablauf der nutzenden Anwendung aus, nachdem das aktualisierte Paket und die Views der Nutzer aufeinander abgestimmt sind.

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

Führen Sie `view:cache` aus, wenn Sie in der Produktion vorab kompilieren. Löschen Sie den Cache nicht bei jedem Aufruf von `boot()` des Pakets und ändern Sie bei der Installation nicht ungefragt den Deployment-Ablauf der nutzenden Anwendung. Auch das Aktualisieren des Konfigurationscaches und das Neuladen langlebiger Prozesse richten sich nach dem üblichen Deployment-Ablauf der jeweiligen Umgebung.

## Kompilierungsergebnis und Rendering-Ergebnis getrennt prüfen

Prüfen Sie zunächst in einer Test-Laravel-Anwendung, in der der obige Provider registriert ist, das erzeugte PHP. Die folgende Methode fügen Sie einem Feature-Test hinzu, der von `Tests\TestCase` erbt.

```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,
    );
}
```

Dieser Test bestätigt den Vertrag für das erzeugte PHP, prüft aber weder die Maskierung noch die Verzweigung zur Laufzeit. Ergänzen Sie in einem echten Paket auch Prüfungen für das Rendern von Views und für Updates.

| Prüffall | Erwartetes Ergebnis |
| - | - |
| Sendungscode mit Zeichen übergeben, die als HTML interpretiert werden | Werden durch das erzeugte `e()` maskiert |
| Dieselbe kompilierte View verwenden und die Label-Konfiguration vor dem Rendern ändern | Das nächste Rendern zeigt den neuen Konfigurationswert |
| Mit `courier.enabled` auf true bzw. false rendern | Nur der jeweils passende Zweig wird angezeigt |
| Nach `view:cache` eine neue Anwendung starten | Die Erweiterungen sind registriert, und das Ergebnis entspricht dem ohne Vorabkompilierung |
| Den erzeugten Code einer Direktive ändern und deployen | Nach dem Neuaufbau des Caches wird das neue PHP verwendet |
| Unterstützte Laravel-Version aktualisieren | Die Tests für erzeugten Code, Rendering und Cache-Nutzung sind erfolgreich |

## Verwandte Seiten

<Columns cols={2}>
  <Card title="Paket-Views überschreiben und aktualisieren" icon="eye" href="/de/advanced/package-views">
    Erläutert die Suchreihenfolge von Namespaces und die Pflege veröffentlichter Templates.
  </Card>

  <Card title="Paket-Caches in optimize integrieren" icon="gears" href="/de/advanced/package-optimization">
    Erläutert, wie Sie Aufbau und Löschen eigener Caches in den Deployment-Ablauf integrieren.
  </Card>
</Columns>

## Herangezogene Primärquellen

* [Offizielle Laravel-Dokumentation: Extending Blade und Custom if statements](https://github.com/laravel/docs/blob/12080c72699b99ec6573f7e79ff4834d9001b6bc/blade.md#extending-blade)
* [Offizielle Laravel-Dokumentation: Views und Komponenten in Paketen](https://github.com/laravel/docs/blob/12080c72699b99ec6573f7e79ff4834d9001b6bc/packages.md#views)
* [BladeCompiler: directive(), callCustomDirective(), compileStatement(), if() und check()](https://github.com/laravel/framework/blob/v13.37.0/src/Illuminate/View/Compilers/BladeCompiler.php)
* [Compiler: Cache-Prüfung mit isExpired()](https://github.com/laravel/framework/blob/v13.37.0/src/Illuminate/View/Compilers/Compiler.php)
* [BladeCustomTest: Eigene Direktiven, Bedingungen und Überschreiben eingebauter Syntax](https://github.com/laravel/framework/blob/v13.37.0/tests/View/Blade/BladeCustomTest.php)


## Related topics

- [Weiterführende Themen](/de/advanced/index.md)
- [CHANGELOG und Release-Management für Pakete](/de/advanced/package-changelog.md)
- [Paket-Views überschreiben und aktualisieren](/de/advanced/package-views.md)
- [Öffentliche Paket-Assets veröffentlichen und aktualisieren](/de/advanced/package-assets.md)
- [Middleware-Registrierung und Geltungsbereich in Paketen](/de/advanced/package-middleware.md)


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