exec("SET NAMES 'utf8mb4'"); // --------------------------------------------------------- // 1. 요청 JSON 읽기 // - 프런트에서 fetch + JSON body로 전달 // --------------------------------------------------------- $raw = file_get_contents('php://input'); $req = json_decode($raw, true); $contentId = trim((string)($req['content_id'] ?? '')); $isChecked = trim((string)($req['is_checked'] ?? '')); // --------------------------------------------------------- // 2. 기본 유효성 검사 // --------------------------------------------------------- if ($memberId === '' || $sysCompCode === '') { response_json([ 'success' => false, 'message' => '로그인 정보가 없습니다.' ]); } if ($contentId === '') { response_json([ 'success' => false, 'message' => 'content_id가 없습니다.' ]); } // --------------------------------------------------------- // 3. 체크값 정규화 // - 현재 운영 중 프런트는 Y/N을 보낼 수 있고, // 향후 1/0으로 바뀔 가능성도 있으므로 둘 다 허용 // - 최종적으로 DB 저장용 is_active 값은 '1' / '0' 으로 맞춘다. // --------------------------------------------------------- if ($isChecked === 'Y' || $isChecked === '1') { $activeValue = '1'; } elseif ($isChecked === 'N' || $isChecked === '0') { $activeValue = '0'; } else { response_json([ 'success' => false, 'message' => '유효하지 않은 요청입니다.' ]); } // --------------------------------------------------------- // 4. 기존 북마크 이력 존재 여부 확인 // - member_id + sys_comp_code + content_id 조합 기준 // --------------------------------------------------------- $stmtCheck = $pdo->prepare(" SELECT COUNT(*) AS cnt FROM edu_content_wishlist WHERE member_id = :member_id AND sys_comp_code = :sys_comp_code AND content_id = :content_id "); $stmtCheck->execute([ ':member_id' => $memberId, ':sys_comp_code' => $sysCompCode, ':content_id' => $contentId, ]); $exists = (int)$stmtCheck->fetchColumn(); // --------------------------------------------------------- // 5. INSERT / UPDATE 처리 // // [기존 row 있음] // - is_active만 update // - updated_at 갱신 // - 체크(활성화) 시 favorited_at도 NOW()로 갱신 // // [기존 row 없음] // - 신규 insert // - created_at / updated_at 저장 // - 체크 상태가 1이면 favorited_at도 NOW() 저장 // // ※ 실제 delete 하지 않고 soft delete 방식 유지 // --------------------------------------------------------- if ($exists > 0) { if ($activeValue === '1') { // 체크 ON $stmtUpdate = $pdo->prepare(" UPDATE edu_content_wishlist SET is_active = :is_active, favorited_at = NOW(), updated_at = NOW() WHERE member_id = :member_id AND sys_comp_code = :sys_comp_code AND content_id = :content_id "); } else { // 체크 OFF $stmtUpdate = $pdo->prepare(" UPDATE edu_content_wishlist SET is_active = :is_active, updated_at = NOW() WHERE member_id = :member_id AND sys_comp_code = :sys_comp_code AND content_id = :content_id "); } $stmtUpdate->execute([ ':is_active' => $activeValue, ':member_id' => $memberId, ':sys_comp_code' => $sysCompCode, ':content_id' => $contentId, ]); } else { if ($activeValue === '1') { // 신규 체크 ON insert $stmtInsert = $pdo->prepare(" INSERT INTO edu_content_wishlist ( member_id, sys_comp_code, content_id, is_active, favorited_at, created_at, updated_at ) VALUES ( :member_id, :sys_comp_code, :content_id, :is_active, NOW(), NOW(), NOW() ) "); } else { // 신규 체크 OFF 요청이 들어온 경우도 예외 없이 기록은 남김 // (운영상 불필요하다면 이 분기는 막아도 됨) $stmtInsert = $pdo->prepare(" INSERT INTO edu_content_wishlist ( member_id, sys_comp_code, content_id, is_active, created_at, updated_at ) VALUES ( :member_id, :sys_comp_code, :content_id, :is_active, NOW(), NOW() ) "); } $stmtInsert->execute([ ':member_id' => $memberId, ':sys_comp_code' => $sysCompCode, ':content_id' => $contentId, ':is_active' => $activeValue, ]); } // --------------------------------------------------------- // 6. saved 탭 카운트만 재계산 // - 북마크 토글은 saved 상태만 변경하므로 // watching / completed 카운트는 여기서 건드리지 않는다. // --------------------------------------------------------- $stmtSavedCount = $pdo->prepare(" SELECT COUNT(*) FROM edu_content_wishlist cw WHERE cw.member_id = :saved_member_id AND cw.sys_comp_code = :saved_sys_comp_code AND cw.is_active = '1' "); $stmtSavedCount->execute([ ':saved_member_id' => $memberId, ':saved_sys_comp_code' => $sysCompCode, ]); $savedCount = (int)$stmtSavedCount->fetchColumn(); // --------------------------------------------------------- // 7. 성공 응답 반환 // --------------------------------------------------------- response_json([ 'success' => true, 'content_id' => $contentId, 'is_checked' => $activeValue, 'counts' => [ 'saved' => $savedCount, ] ]); } catch (Throwable $e) { response_json([ 'success' => false, 'message' => '북마크 처리 중 오류가 발생했습니다.', 'error' => $e->getMessage(), ]); }