nulib-base/php/src/mail/MailTemplate.php

121 lines
3.5 KiB
PHP

<?php
namespace nulib\mail;
use nulib\cv;
use nulib\str;
use nulib\ValueException;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
class MailTemplate {
const SCHEMA = [
"subject" => "string",
"body" => "string",
"exprs" => "array",
];
function __construct(array $mail) {
$tsubject = $mail["subject"] ?? null;
$tbody = $mail["body"] ?? null;
$texprs = $mail["exprs"] ?? [];
$this->el = new ExpressionLanguage();
ValueException::check_null($this->subject = $tsubject, "subject");
ValueException::check_null($this->body = $tbody, "body");
$exprs = [];
# Commencer par extraire les expressions de la forme {name}
if (preg_match_all('/\{([a-zA-Z_][a-zA-Z0-9_.-]*)}/', $this->body, $mss, PREG_SET_ORDER)) {
foreach ($mss as $ms) {
$key = $ms[0];
$expr = str_replace("'", "\\'", $ms[1]);
$expr = "_helper.value('$expr')";
$exprs[$key] = $expr;
}
}
$index = 0;
foreach ($texprs as $key => $expr) {
$prefix = null;
$orig = $expr;
if (preg_match('/^\[([^]]*)]/', $expr, $ms)) {
# un préfixe spécifié de la forme [prefix]expr permet de reconnaitre les
# formes spéciales de expr (+, *, .) qui sont précédées de prefix
# exemple: [https://]+app.url permettra d'utiliser un texte markdown
# de la forme <https://+app.url> qui est correctement reconnu comme un
# url
$prefix = $ms[1];
$expr = substr($expr, strlen($ms[0]));
}
$mapKey = false;
if (str::del_prefix($expr, "+")) {
# config
$mapKey = "$prefix+$expr";
$expr = str_replace("'", "\\'", $expr);
$expr = "_helper.config('$expr')";
} elseif (str::del_prefix($expr, "*")) {
# session
$mapKey = "$prefix*$expr";
$expr = str_replace("'", "\\'", $expr);
$expr = "_helper.session('$expr')";
} elseif (str::del_prefix($expr, ".")) {
# session
$mapKey = "$prefix.$expr";
$expr = str_replace("'", "\\'", $expr);
$expr = "_helper.value('$expr')";
} elseif ($prefix !== null) {
# sinon remettre le préfixe
$expr = $orig;
}
if ($key === $index) {
$index++;
if ($mapKey !== false) {
$exprs[$mapKey] = $expr;
} else {
# clé normale: la correspondance est en minuscule
$exprs[$expr] = strtolower($expr);
}
} else {
$exprs[$key] = $expr;
}
}
uksort($exprs, function ($a, $b) {
return -cv::complen($a, $b);
});
$this->exprs = $exprs;
}
/** @var ExpressionLanguage */
protected $el;
protected $subject;
protected $body;
protected $exprs;
protected function _eval(string $template, ?array $data): string {
if ($data === null) return $template;
$el = $this->el;
foreach ($this->exprs as $key => $expr) {
$value = $el->evaluate($expr, $data);
if (is_array($value)) $value = str::join(" ", $value);
elseif (!is_string($value)) $value = strval($value);
$template = str_replace($key, $value, $template);
}
return $template;
}
function eval(?array $data, $convertMd=true): array {
if ($data !== null) {
$data["_helper"] = new MailTemplateHelper($data);
}
$subject = $this->_eval($this->subject, $data);
$body = $this->body;
if ($convertMd) $body = mdc::convert($body);
$body = $this->_eval($body, $data);
return [
"subject" => $subject,
"body" => $body,
];
}
}