Files
2026-09-30 16:27:32 +02:00

56 lines
2.3 KiB
PHP

<?php
namespace App\Signature;
/**
* Moteur de rendu des templates de signature (sans dépendance au framework).
*
* Syntaxe :
* {{variable}} valeur échappée HTML
* {{{variable}}} valeur brute (réservé aux blocs générés par le serveur, ex. banniere)
* {{#if variable}} … {{/if}} bloc conservé si la variable est non vide (imbrication possible)
* {{#unless variable}} … {{/unless}} bloc conservé si la variable est vide
*
* Une variable inconnue est traitée comme vide : une ligne « Mobile : {{mobile}} »
* entourée de {{#if mobile}} disparaît donc proprement quand le champ n'est pas renseigné.
*/
final class TemplateRenderer
{
private const BLOCK = '/\{\{#(if|unless)\s+([a-z0-9_]+)\s*\}\}((?:(?!\{\{#(?:if|unless)\s).)*?)\{\{\/\1\}\}/is';
/** @param array<string, scalar|null> $vars */
public function render(string $template, array $vars): string
{
$vars = array_change_key_case($vars, CASE_LOWER);
// Blocs conditionnels, du plus interne vers l'extérieur.
$guard = 0;
while (preg_match(self::BLOCK, $template) && $guard++ < 50) {
$template = preg_replace_callback(self::BLOCK, function (array $m) use ($vars) {
$filled = $this->filled($vars[strtolower($m[2])] ?? null);
$keep = strtolower($m[1]) === 'if' ? $filled : ! $filled;
return $keep ? $m[3] : '';
}, $template);
}
// Valeurs brutes puis échappées.
$template = preg_replace_callback('/\{\{\{\s*([a-z0-9_]+)\s*\}\}\}/i', fn ($m) => (string) ($vars[strtolower($m[1])] ?? ''), $template);
return preg_replace_callback('/\{\{\s*([a-z0-9_]+)\s*\}\}/i', fn ($m) => htmlspecialchars((string) ($vars[strtolower($m[1])] ?? ''), ENT_QUOTES | ENT_HTML5, 'UTF-8'), $template);
}
/** Liste des variables utilisées par un template (aide à l'édition). */
public function variables(string $template): array
{
preg_match_all('/\{\{\{?\s*(?:#(?:if|unless)\s+)?([a-z0-9_]+)\s*\}?\}\}/i', $template, $m);
return array_values(array_unique(array_map('strtolower', $m[1])));
}
private function filled(mixed $v): bool
{
return $v !== null && trim((string) $v) !== '';
}
}