tenantId(); $query = ItemPage::where('tenant_id', $tenantId) ->where('is_active', 1); if ($itemType) { $query->where('item_type', strtoupper($itemType)); } // 각 페이지에 빈 sections 배열 설정 (호환성) return $query->get()->each(function ($page) { $page->setAttribute('sections', []); }); } /** * 페이지 생성 */ public function store(array $data): ItemPage { $tenantId = $this->tenantId(); $userId = $this->apiUserId(); $itemType = strtoupper($data['item_type']); // item_type으로 common_codes에서 source_table 조회 $sourceTable = $this->getSourceTableFromCommonCode($itemType); $page = ItemPage::create([ 'tenant_id' => $tenantId, 'page_name' => $data['page_name'], 'item_type' => $itemType, 'source_table' => $sourceTable, 'absolute_path' => $data['absolute_path'] ?? null, 'is_active' => true, 'created_by' => $userId, ]); // 신규 페이지는 섹션이 없으므로 빈 배열 설정 $page->setAttribute('sections', []); return $page; } /** * 페이지 수정 */ public function update(int $id, array $data): ItemPage { $tenantId = $this->tenantId(); $userId = $this->apiUserId(); $page = ItemPage::where('tenant_id', $tenantId) ->where('id', $id) ->first(); if (! $page) { throw new NotFoundHttpException(__('error.not_found')); } $page->update([ 'page_name' => $data['page_name'] ?? $page->page_name, 'absolute_path' => $data['absolute_path'] ?? $page->absolute_path, 'updated_by' => $userId, ]); // 페이지 수정은 섹션에 영향 없음 - entity_relationships 기반 조회는 init API 사용 $page->setAttribute('sections', []); return $page; } /** * 페이지 삭제 (Soft Delete) * * 독립 엔티티 아키텍처: 페이지만 삭제하고 연결된 섹션/필드는 unlink만 수행 */ public function destroy(int $id): void { $tenantId = $this->tenantId(); $userId = $this->apiUserId(); $page = ItemPage::where('tenant_id', $tenantId) ->where('id', $id) ->first(); if (! $page) { throw new NotFoundHttpException(__('error.not_found')); } // 잠금 체크: 이 페이지의 자식 관계 중 잠금된 것이 있는지 확인 $hasLockedChildren = EntityRelationship::where('parent_type', EntityRelationship::TYPE_PAGE) ->where('parent_id', $id) ->where('is_locked', true) ->exists(); if ($hasLockedChildren) { throw new BusinessException(__('error.page_has_locked_children')); } // 1. entity_relationships에서 이 페이지의 모든 자식 관계 해제 // (page→section, page→field 관계 삭제) // 주의: 잠금된 연결이 없는 상태에서만 진입 EntityRelationship::where('parent_type', EntityRelationship::TYPE_PAGE) ->where('parent_id', $id) ->where('is_locked', false) ->delete(); // 2. 페이지만 Soft Delete (섹션/필드는 독립 엔티티로 유지) $page->update(['deleted_by' => $userId]); $page->delete(); } /** * item_type에 해당하는 source_table을 common_codes.attributes에서 조회 */ private function getSourceTableFromCommonCode(string $itemType): ?string { $commonCode = \DB::table('common_codes') ->where('code_group', 'item_type') ->where('code', strtoupper($itemType)) ->first(); if (! $commonCode || ! $commonCode->attributes) { return null; } $attrs = json_decode($commonCode->attributes, true); return $attrs['source_table'] ?? null; } }