This commit is contained in:
2025-12-07 01:51:03 +01:00
parent cb9deabe91
commit 610389a5e6

View File

@@ -1,6 +1,8 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
use DOMDocument;
use DOMXPath;
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles; use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;
// 💡 NEUE KORREKTUR: Starte Output Buffering so früh wie möglich, um Whitespace/Errors // 💡 NEUE KORREKTUR: Starte Output Buffering so früh wie möglich, um Whitespace/Errors
@@ -659,6 +661,10 @@ class ApiKernel
if ($html === '' && !empty($row['json_content'])) { if ($html === '' && !empty($row['json_content'])) {
$html = '<p>(Dieses Template enthält noch keine HTML-Inhalte.)</p>'; $html = '<p>(Dieses Template enthält noch keine HTML-Inhalte.)</p>';
} }
$renderCache = [];
$renderStack = [];
$html = $this->renderHtmlWithReferences($html, $auth, $renderCache, $renderStack);
$html = $this->prepareEmailHtml($html); $html = $this->prepareEmailHtml($html);
if (!$this->dispatchTestMail($recipient, $subject, $html)) { if (!$this->dispatchTestMail($recipient, $subject, $html)) {
@@ -867,4 +873,119 @@ class ApiKernel
$summary['total'] = array_sum($summary); $summary['total'] = array_sum($summary);
return $summary; return $summary;
} }
private function normalizeResourceKind(string $kind): ?string
{
$kind = strtolower(trim($kind));
$map = [
'template' => 'templates',
'templates' => 'templates',
'section' => 'sections',
'sections' => 'sections',
'block' => 'blocks',
'blocks' => 'blocks',
'snippet' => 'snippets',
'snippets' => 'snippets',
];
return $map[$kind] ?? null;
}
private function resolveHtmlColumn(array $columns, string $kindKey): ?string
{
$candidates = ($kindKey === 'snippets')
? ['content', 'html', 'body', 'markup']
: ['html', 'body', 'markup', 'content'];
return $this->firstExisting($columns, $candidates);
}
private function fetchResourceHtml(string $kind, int $id, array $auth, array &$cache, array &$stack): ?string
{
$kindKey = $this->normalizeResourceKind($kind);
if (!$kindKey || $id <= 0) return null;
$cacheKey = $kindKey . ':' . $id;
if (array_key_exists($cacheKey, $cache)) return $cache[$cacheKey];
if (!empty($stack[$cacheKey])) return null;
$table = $this->tableMap[$kindKey] ?? null;
if (!$table) return null;
[$idCol, $allCols] = $this->resolveIdCol($kindKey);
[$tw, $tp] = $this->tenantWhere($auth);
$sql = "SELECT * FROM `$table` WHERE `$idCol` = :id" . $tw . " LIMIT 1";
$stmt = $this->pdo->prepare($sql);
$stmt->bindValue(':id', $id);
foreach ($tp as $k => $v) $stmt->bindValue($k, $v);
$stmt->execute();
$row = $stmt->fetch();
if (!$row) {
$cache[$cacheKey] = null;
return null;
}
$htmlCol = $this->resolveHtmlColumn($allCols, $kindKey);
$html = $htmlCol && isset($row[$htmlCol]) ? (string)$row[$htmlCol] : '';
$stack[$cacheKey] = true;
$html = $this->renderHtmlWithReferences($html, $auth, $cache, $stack);
unset($stack[$cacheKey]);
$cache[$cacheKey] = $html;
return $html;
}
private function renderHtmlWithReferences(string $html, array $auth, array &$cache, array &$stack): string
{
$trimmed = trim($html);
if ($trimmed === '') return $html;
if (!class_exists(DOMDocument::class)) return $html;
$flags = 0;
if (defined('LIBXML_HTML_NOIMPLIED')) {
$flags |= LIBXML_HTML_NOIMPLIED;
}
if (defined('LIBXML_HTML_NODEFDTD')) {
$flags |= LIBXML_HTML_NODEFDTD;
}
$doc = new DOMDocument('1.0', 'UTF-8');
libxml_use_internal_errors(true);
$wrapper = '<div id="lib-ref-root">' . $html . '</div>';
$loaded = @$doc->loadHTML('<?xml encoding="utf-8"?>' . $wrapper, $flags);
libxml_clear_errors();
if (!$loaded) return $html;
$xpath = new DOMXPath($doc);
$nodes = $xpath->query('//*[@data-lib-kind and @data-lib-id]');
if ($nodes !== false) {
foreach ($nodes as $node) {
/** @var \DOMElement $node */
$kind = $node->getAttribute('data-lib-kind');
$refId = (int)$node->getAttribute('data-lib-id');
if (!$kind || $refId <= 0) continue;
$replacement = $this->fetchResourceHtml($kind, $refId, $auth, $cache, $stack);
if ($replacement === null) continue;
while ($node->firstChild) {
$node->removeChild($node->firstChild);
}
$fragment = $doc->createDocumentFragment();
if (@$fragment->appendXML($replacement)) {
$node->appendChild($fragment);
} else {
$node->appendChild($doc->createTextNode($replacement));
}
}
}
$root = $doc->getElementById('lib-ref-root');
if (!$root) return $html;
$output = '';
foreach ($root->childNodes as $child) {
$output .= $doc->saveHTML($child);
}
return $output;
}
} }