45
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
<?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) !== '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user