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 .= '| '.e($header).' | ';
}
$html .= '
';
}
$html .= '';
foreach ($rows as $row) {
$html .= '';
foreach ($row as $cell) {
$value = $this->resolveBinding($cell ?? '', $data);
$html .= '| '.e($value).' | ';
}
$html .= '
';
}
$html .= '
';
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 "";
}
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 = "';
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 "";
}
}