renderPageOpen($page); foreach ($blocks as $block) { $html .= $this->renderBlock($block, $data); } $html .= $this->renderPageClose(); return $html; } /** * 개별 블록 렌더링 */ public function renderBlock(array $block, array $data = []): string { $type = $block['type'] ?? ''; $props = $block['props'] ?? []; return match ($type) { 'heading' => $this->renderHeading($props, $data), 'paragraph' => $this->renderParagraph($props, $data), 'table' => $this->renderTable($props, $data), 'columns' => $this->renderColumns($props, $data), 'divider' => $this->renderDivider($props), 'spacer' => $this->renderSpacer($props), 'text_field' => $this->renderTextField($props, $data), 'number_field' => $this->renderNumberField($props, $data), 'date_field' => $this->renderDateField($props, $data), 'select_field' => $this->renderSelectField($props, $data), 'checkbox_field' => $this->renderCheckboxField($props, $data), 'textarea_field' => $this->renderTextareaField($props, $data), 'signature_field' => $this->renderSignatureField($props, $data), default => "", }; } /** * 데이터 바인딩 치환 */ protected function resolveBinding(string $text, array $data): string { return preg_replace_callback('/\{\{(.+?)\}\}/', function ($matches) use ($data) { $key = trim($matches[1]); if ($key === 'today') { return now()->format('Y-m-d'); } return data_get($data, $key, $matches[0]); }, $text); } // ===== 렌더링 메서드 ===== protected function renderPageOpen(array $page): string { $size = $page['size'] ?? 'A4'; $orientation = $page['orientation'] ?? 'portrait'; return '
'; } protected function renderPageClose(): string { return '
'; } protected function renderHeading(array $props, array $data): string { $level = min(max(intval($props['level'] ?? 2), 1), 6); $text = e($this->resolveBinding($props['text'] ?? '', $data)); $align = e($props['align'] ?? 'left'); $sizes = [1 => '1.5em', 2 => '1.25em', 3 => '1.1em', 4 => '1em', 5 => '0.9em', 6 => '0.85em']; $size = $sizes[$level]; return "{$text}"; } protected function renderParagraph(array $props, array $data): string { $text = e($this->resolveBinding($props['text'] ?? '', $data)); $text = nl2br($text); $align = e($props['align'] ?? 'left'); return "

{$text}

"; } protected function renderTable(array $props, array $data): string { $headers = $props['headers'] ?? []; $rows = $props['rows'] ?? []; $showHeader = $props['showHeader'] ?? true; $html = ''; if ($showHeader && ! empty($headers)) { $html .= ''; foreach ($headers as $header) { $html .= ''; } $html .= ''; } $html .= ''; foreach ($rows as $row) { $html .= ''; foreach ($row as $cell) { $value = $this->resolveBinding($cell ?? '', $data); $html .= ''; } $html .= ''; } $html .= '
'.e($header).'
'.e($value).'
'; return $html; } protected function renderColumns(array $props, array $data): string { $count = intval($props['count'] ?? 2); $children = $props['children'] ?? []; $width = round(100 / $count, 2); $html = '
'; for ($i = 0; $i < $count; $i++) { $html .= '
'; $colChildren = $children[$i] ?? []; foreach ($colChildren as $child) { $html .= $this->renderBlock($child, $data); } $html .= '
'; } $html .= '
'; return $html; } protected function renderDivider(array $props): string { $style = ($props['style'] ?? 'solid') === 'dashed' ? 'dashed' : 'solid'; return "
"; } protected function renderSpacer(array $props): string { $height = max(intval($props['height'] ?? 20), 0); return "
"; } protected function renderTextField(array $props, array $data): string { $label = e($props['label'] ?? ''); $binding = $props['binding'] ?? ''; $value = $binding ? e($this->resolveBinding($binding, $data)) : ''; $required = ! empty($props['required']) ? ' *' : ''; return "
{$value}
"; } protected function renderNumberField(array $props, array $data): string { $label = e($props['label'] ?? ''); $unit = e($props['unit'] ?? ''); $unitDisplay = $unit ? " ({$unit})" : ''; return "
"; } protected function renderDateField(array $props, array $data): string { $label = e($props['label'] ?? ''); $binding = $props['binding'] ?? ''; $value = $binding ? e($this->resolveBinding($binding, $data)) : ''; return "
{$value}
"; } protected function renderSelectField(array $props, array $data): string { $label = e($props['label'] ?? ''); $options = $props['options'] ?? []; return "
".e(implode(' / ', $options)).'
'; } protected function renderCheckboxField(array $props, array $data): string { $label = e($props['label'] ?? ''); $options = $props['options'] ?? []; $html = "
"; foreach ($options as $opt) { $html .= ''; } $html .= '
'; return $html; } protected function renderTextareaField(array $props, array $data): string { $label = e($props['label'] ?? ''); $rows = max(intval($props['rows'] ?? 3), 1); $height = $rows * 24; return "
"; } protected function renderSignatureField(array $props, array $data): string { $label = e($props['label'] ?? '서명'); return "
서명 영역
"; } }