/**
* Form fields whose default text looks like "#listKey: col1, col2, ..." become a table.
* Row 1 = the first person (top-level $wertePaare), then every entry in $wertePaare[listKey].
*/
private function insertTables(\DOMDocument $dom, array &$wertePaare, array $labels = []): void
{
// Collect first: getElementsByTagName is a live list
$anchors = [];
foreach ($dom->getElementsByTagName('ffData') as $ff) {
$config = $this->fieldDefaultText($ff);
if (!preg_match('/^\s*#\s*(\w+)\s*:\s*(.+)$/u', $config, $m)) {
continue; // normal field, leave it to fillIn
}
$p = $ff;
while ($p && $p->nodeName !== 'w:p') {
$p = $p->parentNode;
}
if ($p) {
$cols = preg_split('/\s*[,;]\s*/', trim($m[2]), -1, PREG_SPLIT_NO_EMPTY);
$anchors[] = [$m[1], $cols, $p];
}
}
foreach ($anchors as [$listKey, $cols, $p]) {
$rows = [];
// First person from the top-level values (skip if all columns are empty)
$first = [];
foreach ($cols as $c) {
$first[$c] = $wertePaare[$c] ?? '';
}
if (array_filter($first, fn($v) => $v !== '' && $v !== null)) {
$rows[] = $first;
}
// Additional persons
foreach ((array) ($wertePaare[$listKey] ?? []) as $row) {
$rows[] = (array) $row;
}
$parent = $p->parentNode;
if ($rows) {
$headers = [];
foreach ($cols as $c) {
$headers[$c] = $labels[$c] ?? $c;
}
$parent->insertBefore($this->buildTable($dom, ['headers' => $headers, 'rows' => $rows]), $p);
}
// Word needs a paragraph after a table at the end of a cell/document
$next = $p->nextSibling;
if ($next === null || $next->nodeName !== 'w:p') {
$parent->replaceChild($dom->createElement('w:p'), $p);
} else {
$parent->removeChild($p);
}
}
// Arrays must never reach the text-filling loops
foreach ($wertePaare as $k => $v) {
if (is_array($v)) {
unset($wertePaare[$k]);
}
}
}
/** Default text (Standardtext) of a legacy text form field */
private function fieldDefaultText(\DOMElement $ff): string
{
foreach ($ff->getElementsByTagName('default') as $d) {
if ($d->parentNode->nodeName === 'w:textInput') {
return $d->getAttribute('w:val');
}
}
return '';
}3 views