56 lines
2.3 KiB
PHP
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) !== '';
|
|
}
|
|
}
|