orderBy('group_key'); if (!empty($params['q'])) { $kw = $params['q']; $q->where(function ($w) use ($kw) { $w->where('group_key', 'like', "%{$kw}%") ->orWhere('name', 'like', "%{$kw}%"); }); } $data = $q->paginate($per, ['*'], 'page', $page); return ApiResponse::response('result', $data); } /** * [POST] 옵션 그룹 생성 */ public static function store(array $params = []) { $tenantId = self::tenantId(); if (!$tenantId) { return ApiResponse::error('활성 테넌트가 없습니다.', 400); } $v = Validator::make($params, [ 'group_key' => [ 'required','string','max:64','alpha_dash', Rule::unique('tenant_option_groups', 'group_key') ->where(fn ($q) => $q->where('tenant_id', $tenantId)), ], 'name' => ['required','string','max:100'], 'description' => ['nullable','string','max:255'], ]); if ($v->fails()) { return ApiResponse::error($v->errors()->first(), 422); } $data = $v->validated(); $data['tenant_id'] = $tenantId; $item = TenantOptionGroup::create($data); return ApiResponse::response('result', $item->toArray()); } /** * [GET] 옵션 그룹 단건 조회 */ public static function show(int $id) { $tenantId = self::tenantId(); if (!$tenantId) { return ApiResponse::error('활성 테넌트가 없습니다.', 400); } if (!$id) { return ApiResponse::error('id가 올바르지 않습니다.', 422); } $item = TenantOptionGroup::where('tenant_id', $tenantId)->find($id); if (!$item) { return ApiResponse::error('옵션 그룹을 찾을 수 없습니다.', 404); } return ApiResponse::response('result', $item->toArray()); } /** * [PATCH] 옵션 그룹 수정 */ public static function update(int $id, array $params = []) { $tenantId = self::tenantId(); if (!$tenantId) { return ApiResponse::error('활성 테넌트가 없습니다.', 400); } if (!$id) { return ApiResponse::error('id가 올바르지 않습니다.', 422); } $item = TenantOptionGroup::where('tenant_id', $tenantId)->find($id); if (!$item) { return ApiResponse::error('옵션 그룹을 찾을 수 없습니다.', 404); } $v = Validator::make($params, [ 'group_key' => [ 'sometimes','string','max:64','alpha_dash', Rule::unique('tenant_option_groups', 'group_key') ->where(fn ($q) => $q->where('tenant_id', $tenantId)) ->ignore($item->id), ], 'name' => ['sometimes','string','max:100'], 'description' => ['nullable','string','max:255'], ]); if ($v->fails()) { return ApiResponse::error($v->errors()->first(), 422); } $data = $v->validated(); if (empty($data)) { return ApiResponse::error('수정할 항목이 없습니다.', 422); } $item->fill($data)->save(); return ApiResponse::response('result', $item->toArray()); } /** * [DELETE] 옵션 그룹 삭제 * - 참조 무결성 검사: * 1) tenant_option_values에 값이 남아있으면 삭제 불가 * 2) tenant_field_settings.option_group_id에서 참조 중이면 삭제 불가 */ public static function destroy(int $id) { $tenantId = self::tenantId(); if (!$tenantId) { return ApiResponse::error('활성 테넌트가 없습니다.', 400); } if (!$id) { return ApiResponse::error('id가 올바르지 않습니다.', 422); } $item = TenantOptionGroup::where('tenant_id', $tenantId)->find($id); if (!$item) { return ApiResponse::error('옵션 그룹을 찾을 수 없습니다.', 404); } // 1) 옵션 값 존재 여부 $hasValues = TenantOptionValue::where('group_id', $item->id)->exists(); if ($hasValues) { return ApiResponse::error('해당 그룹에 옵션 값이 존재하여 삭제할 수 없습니다.', 409); } // 2) 필드 설정에서 참조 여부 $isReferenced = TenantFieldSetting::where('tenant_id', $tenantId) ->where('option_group_id', $item->id) ->exists(); if ($isReferenced) { return ApiResponse::error('필드 설정에서 참조 중인 그룹은 삭제할 수 없습니다.', 409); } $item->delete(); return ApiResponse::response('result', ['deleted' => true]); } }