update email template
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Email;
|
||||
|
||||
use App\Exceptions\InvalidTemplateVariableException;
|
||||
use App\Models\Template;
|
||||
|
||||
/**
|
||||
* Render Template subject/message: chỉ thay thế placeholder dạng {{key}} đã khai báo
|
||||
* trong metadata.variables. Không eval(), không compile Blade/PHP.
|
||||
*/
|
||||
class EmailTemplateRenderer
|
||||
{
|
||||
private const PLACEHOLDER_PATTERN = '/\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/';
|
||||
|
||||
/**
|
||||
* @return array{subject: string, html: string}
|
||||
*/
|
||||
public function render(Template $template, array $data): array
|
||||
{
|
||||
$variables = $template->variables();
|
||||
|
||||
$this->assertKnownVariables($template->scenario ?? $template->name ?? 'unknown', (string) $template->subject, $variables);
|
||||
$this->assertKnownVariables($template->scenario ?? $template->name ?? 'unknown', (string) $template->message, $variables);
|
||||
|
||||
return [
|
||||
'subject' => $this->replace((string) $template->subject, $variables, $data),
|
||||
'html' => $this->replace((string) $template->message, $variables, $data),
|
||||
];
|
||||
}
|
||||
|
||||
private function assertKnownVariables(string $scenario, string $content, array $variables): void
|
||||
{
|
||||
$used = $this->extractPlaceholders($content);
|
||||
$invalid = array_values(array_diff($used, array_keys($variables)));
|
||||
|
||||
if ($invalid !== []) {
|
||||
throw new InvalidTemplateVariableException($scenario, $invalid);
|
||||
}
|
||||
}
|
||||
|
||||
private function extractPlaceholders(string $content): array
|
||||
{
|
||||
preg_match_all(self::PLACEHOLDER_PATTERN, $content, $matches);
|
||||
|
||||
return array_values(array_unique($matches[1]));
|
||||
}
|
||||
|
||||
private function replace(string $content, array $variables, array $data): string
|
||||
{
|
||||
return preg_replace_callback(self::PLACEHOLDER_PATTERN, function (array $match) use ($variables, $data) {
|
||||
$key = $match[1];
|
||||
$definition = $variables[$key] ?? [];
|
||||
$value = $data[$key] ?? $definition['example'] ?? '';
|
||||
|
||||
return $this->formatValue((string) $value, $definition['type'] ?? 'string');
|
||||
}, $content) ?? $content;
|
||||
}
|
||||
|
||||
private function formatValue(string $value, string $type): string
|
||||
{
|
||||
return match ($type) {
|
||||
// html: nội dung tin cậy do Email Builder sinh ra sẵn (đã được builder escape khi build).
|
||||
'html' => $value,
|
||||
'url' => filter_var($value, FILTER_VALIDATE_URL) ? htmlspecialchars($value, ENT_QUOTES, 'UTF-8') : '',
|
||||
default => htmlspecialchars($value, ENT_QUOTES, 'UTF-8'),
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user