value] 형태 * @param int|null $recordId 수정 시 레코드 ID * @return array 저장된 데이터 */ public function saveData(string $sourceTable, array $fieldValues, ?int $recordId = null): array { // 해당 테이블의 필드 매핑 정보 조회 $fields = ItemField::where('tenant_id', $this->tenantId()) ->where('source_table', $sourceTable) ->get() ->keyBy('id'); $columnData = []; // DB 컬럼 직접 저장 $jsonData = []; // JSON (attributes/options) 저장 foreach ($fieldValues as $fieldId => $value) { $field = $fields->get($fieldId); if (! $field) { // 시스템 필드가 아닌 커스텀 필드 $customField = ItemField::find($fieldId); if ($customField) { $jsonPath = $customField->json_path ?? "attributes.{$customField->field_key}"; data_set($jsonData, $jsonPath, $value); } continue; } if ($field->isColumnStorage()) { // DB 컬럼에 직접 저장 $columnData[$field->source_column] = $this->castValue($value, $field); } else { // JSON 필드에 저장 $jsonPath = $field->json_path ?? "attributes.{$field->field_key}"; data_set($jsonData, $jsonPath, $value); } } // JSON 데이터 병합 if (! empty($jsonData['attributes'])) { $columnData['attributes'] = json_encode($jsonData['attributes']); } if (! empty($jsonData['options'])) { $columnData['options'] = json_encode($jsonData['options']); } // 공통 컬럼 추가 $columnData['tenant_id'] = $this->tenantId(); $columnData['updated_by'] = $this->apiUserId(); if ($recordId) { // 수정 DB::table($sourceTable) ->where('tenant_id', $this->tenantId()) ->where('id', $recordId) ->update($columnData); return array_merge(['id' => $recordId], $columnData); } else { // 생성 $columnData['created_by'] = $this->apiUserId(); $id = DB::table($sourceTable)->insertGetId($columnData); return array_merge(['id' => $id], $columnData); } } /** * 필드 타입에 따른 값 변환 */ private function castValue($value, ItemField $field) { return match ($field->field_type) { 'number' => is_numeric($value) ? (float) $value : null, 'checkbox' => filter_var($value, FILTER_VALIDATE_BOOLEAN), 'date' => $value ? date('Y-m-d', strtotime($value)) : null, default => $value, }; } /** * 레코드 조회 시 필드 매핑 적용 * * @param string $sourceTable 대상 테이블 (products, materials 등) * @param int $recordId 레코드 ID * @return array 필드 ID => 값 형태의 데이터 */ public function getData(string $sourceTable, int $recordId): array { $record = DB::table($sourceTable) ->where('tenant_id', $this->tenantId()) ->where('id', $recordId) ->first(); if (! $record) { return []; } // 필드 매핑 정보 조회 $fields = ItemField::where('tenant_id', $this->tenantId()) ->where('source_table', $sourceTable) ->get(); $result = []; $attributes = json_decode($record->attributes ?? '{}', true); $options = json_decode($record->options ?? '{}', true); foreach ($fields as $field) { if ($field->isColumnStorage()) { $result[$field->id] = $record->{$field->source_column} ?? null; } else { $jsonPath = $field->json_path ?? "attributes.{$field->field_key}"; $result[$field->id] = data_get( ['attributes' => $attributes, 'options' => $options], $jsonPath ); } } return $result; } /** * 페이지 기반으로 레코드 저장 * * @param int $pageId ItemPage ID * @param array $fieldValues [field_id => value] 형태 * @param int|null $recordId 수정 시 레코드 ID * @return array 저장된 데이터 */ public function saveDataByPage(int $pageId, array $fieldValues, ?int $recordId = null): array { $page = \App\Models\ItemMaster\ItemPage::find($pageId); if (! $page || ! $page->source_table) { throw new \InvalidArgumentException("Invalid page or source_table not defined for page: {$pageId}"); } return $this->saveData($page->source_table, $fieldValues, $recordId); } /** * 페이지 기반으로 레코드 조회 * * @param int $pageId ItemPage ID * @param int $recordId 레코드 ID * @return array 필드 ID => 값 형태의 데이터 */ public function getDataByPage(int $pageId, int $recordId): array { $page = \App\Models\ItemMaster\ItemPage::find($pageId); if (! $page || ! $page->source_table) { throw new \InvalidArgumentException("Invalid page or source_table not defined for page: {$pageId}"); } return $this->getData($page->source_table, $recordId); } }