refactor:문서양식 섹션/컬럼 저장 시 ID 보존 upsert 방식 적용

- sections, columns는 삭제→재생성 대신 ID 보존 upsert로 변경
- document_data.section_id, column_id FK 참조 깨짐 방지
- 요청에 없는 섹션/컬럼/항목만 선택적 삭제

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 03:41:13 +09:00
parent 0f5c509bed
commit 555a502d0c

View File

@@ -617,19 +617,18 @@ public function getCommonCodes(string $group): JsonResponse
}
/**
* 관계 데이터 저장
* 관계 데이터 저장 (ID 보존 upsert 방식)
*
* sections/columns는 기존 ID를 보존하여 document_data 참조가 깨지지 않도록 함.
* 나머지(approval_lines, basic_fields 등)는 단순 관계라 삭제→재생성.
*/
private function saveRelations(DocumentTemplate $template, array $data, bool $deleteExisting = false): void
{
// 기존 데이터 삭제 (수정 시)
// 단순 관계: 삭제 → 재생성 (document_data가 참조하지 않는 테이블)
if ($deleteExisting) {
$template->approvalLines()->delete();
$template->basicFields()->delete();
// sections는 cascade로 items도 함께 삭제됨
$template->sections()->delete();
$template->columns()->delete();
$template->sectionFields()->delete();
// links는 cascade로 linkValues도 함께 삭제됨
$template->links()->delete();
}
@@ -661,20 +660,42 @@ private function saveRelations(DocumentTemplate $template, array $data, bool $de
}
}
// 섹션 및 항목
if (! empty($data['sections'])) {
// 섹션 및 항목: ID 보존 upsert (document_data.section_id 참조 보호)
if (isset($data['sections'])) {
$incomingIds = collect($data['sections'])->pluck('id')->filter()->toArray();
// 요청에 없는 섹션만 삭제 (cascade로 items도 삭제)
if ($deleteExisting) {
$template->sections()->whereNotIn('id', $incomingIds)->each(function ($section) {
$section->items()->delete();
$section->delete();
});
}
foreach ($data['sections'] as $sIndex => $section) {
$newSection = DocumentTemplateSection::create([
'template_id' => $template->id,
$sectionData = [
'title' => $section['title'] ?? '',
'image_path' => $section['image_path'] ?? null,
'sort_order' => $sIndex,
]);
];
if (! empty($section['id']) && $template->sections()->where('id', $section['id'])->exists()) {
$existing = $template->sections()->where('id', $section['id'])->first();
$existing->update($sectionData);
$savedSection = $existing;
} else {
$savedSection = DocumentTemplateSection::create(array_merge(
['template_id' => $template->id],
$sectionData
));
}
// 섹션 항목 upsert
if (isset($section['items'])) {
$itemIncomingIds = collect($section['items'])->pluck('id')->filter()->toArray();
$savedSection->items()->whereNotIn('id', $itemIncomingIds)->delete();
if (! empty($section['items'])) {
foreach ($section['items'] as $iIndex => $item) {
DocumentTemplateSectionItem::create([
'section_id' => $newSection->id,
$itemData = [
'category' => $item['category'] ?? '',
'item' => $item['item'] ?? '',
'standard' => $item['standard'] ?? '',
@@ -688,24 +709,46 @@ private function saveRelations(DocumentTemplate $template, array $data, bool $de
'regulation' => $item['regulation'] ?? '',
'field_values' => $item['field_values'] ?? null,
'sort_order' => $iIndex,
]);
];
if (! empty($item['id']) && $savedSection->items()->where('id', $item['id'])->exists()) {
$savedSection->items()->where('id', $item['id'])->update($itemData);
} else {
DocumentTemplateSectionItem::create(array_merge(
['section_id' => $savedSection->id],
$itemData
));
}
}
}
}
}
// 컬럼
if (! empty($data['columns'])) {
// 컬럼: ID 보존 upsert (document_data.column_id 참조 보호)
if (isset($data['columns'])) {
$incomingIds = collect($data['columns'])->pluck('id')->filter()->toArray();
if ($deleteExisting) {
$template->columns()->whereNotIn('id', $incomingIds)->delete();
}
foreach ($data['columns'] as $index => $column) {
DocumentTemplateColumn::create([
'template_id' => $template->id,
$colData = [
'label' => $column['label'] ?? '',
'width' => $column['width'] ?? '100px',
'column_type' => $column['column_type'] ?? 'text',
'group_name' => $column['group_name'] ?? null,
'sub_labels' => $column['sub_labels'] ?? null,
'sort_order' => $index,
]);
];
if (! empty($column['id']) && $template->columns()->where('id', $column['id'])->exists()) {
$template->columns()->where('id', $column['id'])->update($colData);
} else {
DocumentTemplateColumn::create(array_merge(
['template_id' => $template->id],
$colData
));
}
}
}