
PHP에서 좋아요 기능 구현하기
•
2024-10-12 21:59
PHP를 이용해 웹사이트를 구현하는 도중 좋아요 기능이 필요할거 같아
직접 구현해보기로 했습니다!
1. 좋아요 테이블 만들기
처음에는 마냥 게시물마다 누가 눌렀는지 멤버의 아이디를 게시물 마다 새겨넣는 방식으로 업데이트 해주는게 편할거 같다고 생각했는데
이게 점점 쌓이면 쌓일수록 데이터도 커지고 유지보수에 여러모로 문제점이 많아 보였습니다...ㅠ
그래서 좋아요 테이블에서 현재 게시물의 ID 값을 좋아요 테이블에서 찾아 좋아요수를 업데이트 하는 방법을 이용해보기로 했습니다.
<?php
// 최상위 경로
$rootPath = $_SERVER['DOCUMENT_ROOT'];
// MySQL 연결
include $rootPath ."/src/components/common/component_connect.php";
$sql = "
CREATE TABLE boardLikes(
likeID int(10) unsigned NOT NULL auto_increment,
postID int(10) NOT NULL,
memberID int(10) NOT NULL,
regTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (likeID)
)DEFAULT CHARSET=utf8;
";
$result = $connect ->query($sql);
if ($result) {
echo "좋아요의 테이블 생성을 성공 하였습니다.";
} else {
echo "테이블 생성에 실패 하였습니다.".$connect->error;
}
?>
2. 좋아요 업데이트 관련 API 만들기
좋아요를 구현하려고 했으나 새로고침 없이 하고자 했기 때문에 단순 눌렀을때 form을 통한 방식이 아닌 다른 방식이 필요했습니다,
그래서 좋아요를 업데이트 해주는 api를 만들어 관련 api 호출을 통해 해결 하고자 하였습니다.
<?php
// 1. SQL 쿼리를 미리 준비 (prepare()).
// 2. 쿼리의 변수 자리에 바인딩할 값을 지정 (bind_param()).
// 3. 준비된 쿼리를 실행 (execute()).
// 최상위 경로
$rootPath =$_SERVER['DOCUMENT_ROOT'];
// MySQL 연결
include$rootPath ."/src/components/common/component_connect.php";
include$rootPath ."/src/components/common/component_session.php";
header('Content-Type: application/json');
$data = json_decode(file_get_contents("php://input"),true);
$postID = $data['postID'];
$memberID = $data['memberID'];
// 먼저 로그인한 사용자가 이 게시물에 이미 좋아요를 눌렀는지 확인
$sql ="SELECT*FROM boardLikes WHERE memberID = ? AND postID = ?";
$result =$connect->prepare($sql);
// i: 정수 (integer)
// s: 문자열 (string)
// d: 실수 (double)
// b: 바이너리 데이터 (blob)
$result ->bind_param("ii",$memberID,$postID);
$result ->execute();
$result =$result ->get_result();
$isAvailiable =$result -> num_rows >0;
// 이미 좋아요를 눌렀다면, 좋아요 취소
// 좋아요를 누르지 않았다면, 새로 좋아요 추가
$sql = $isAvailiable ?"
DELETE FROM boardLikes WHERE memberID = ? AND postID = ?
":"
INSERT INTO boardLikes (memberID, postID) VALUES (?, ?)
";
$result = $connect->prepare($sql);
$result -> bind_param("ii",$memberID,$postID);
$result -> execute();
$message = $isAvailiable ? [
'success'=>true,'message'=>'좋아요 취소됨','stat'=>0
] : [
'success'=>true,'message'=>'좋아요 추가됨','stat'=>1
];
echo json_encode($message);
?>
3. 클릭 했을때 API를 호출하는 스크립트 구현
클릭하였을때 API를 호출하는 부분을 구현해보고자 합니다.
const postID = document.querySelector("#postID").value;
const memberID = document.querySelector("#memberID").value;
try{
const response = await fetch("/src/api/controller_like.php",{
method:"POST",
headers:{
'Content-Type':'application/json',
},
body:JSON.stringify({
memberID: memberID,
postID: postID,
}),
});
const result = await response.json();
return result.success && result.stat;
} catch(error) {
console.error("반영 중 실패:", error);
}
4. 클릭 했을때 좋아요 수 업데이트 및 연속 호출 방지
이제 좋아요를 클릭했을때 위에서 작성했던 API 호출 및 연속 호출 방지를 해주었어요.
저의 경우 요소를 선택할때 모든 .like 요소를 잡은 이유는
다른 페이지에서 여러 게시물을 리스트업 하였을때 해당 게시물에 바로 바로 좋아요를 클릭해 개별적으로 업데이트 하기 위해 사용했어요.
순서 : 좋아요 수 반영 -> 추가 이벤트 호출 막음 -> 1초 후 이벤트 호출 막음 처리 해제
const elementsLike = document.querySelectorAll(".like");
elementsLike.forEach((e,i)=>{
// 변수 : 이벤트 호출 방시 상태
let isNeedPrevent =false;
// 함수 : 좋아요 상태 업데이트
const setLikeCount=(stat,element,value)=>{
stat ? e.classList.add("active"): e.classList.remove("active");
element.innerText = stat ? value +1: value -1;
}
// 함수 : 이벤트 호출 방지 상태 업데이트
const setStatePrevent=()=>{
isNeedPrevent = !isNeedPrevent;
console.log("막기 상태", isNeedPrevent);
}
// 클릭 이벤트 : 좋아요 수 반영 -> 이벤트 호출 막음 설정 -> 이벤트 호출 막음 해제
e.addEventListener("click", async() => {
const elementLikeCount = e.querySelector(".countLike");
if(!isNeedPrevent && elementLikeCount){
const value = parseInt(elementLikeCount.innerText);
let result = await getLike();
setLikeCount(result, elementLikeCount, value);
setStatePrevent();
setTimeout(() => setStatePrevent(),1000);
}
})
});
5. html 작성
이제 마지막이네요!
클릭해 함수를 작동시키고 표시해줄 버튼을 하단과 같이 만들어 두었습니다.
<button type='button' class='item like'>
<img src='/src/assets/images/icon/ico-like-stroke.svg' alt='좋아요'>
<p class='countLike'>{$countLikes}</p>
</button>
6. SCSS으로 스타일 입히기
저의 경우엔 SCSS로 스타일 처리를 하는것이 편해 주로 이용하고 있어요
.like 에 .active 가 붙었을때 이미지의 경로를 변경해주었습니다.
또한 클릭했을때 심심하지 않게 눌렸을때(active) 크기를 조금 작게 변경해주었으며,
마우스를 가져다 올려두었을때 배경(background) 의 색상을 변경해 조금 꾸며보았어요.
> .item {
&:active {
transform:scale(0.95);
}
&:hover {
background: blue;
}
&.like {
&.active {
> img {
background-image:url('/src/assets/images/icon/ico-like-fill.svg');
}
}
}
}
마무리
이런 과정을 거쳐 좋아요 기능을 만들어 보았습니다,
만들고 나니 조금은 감정을 표현 할 수 있는 수단이 늘어 기분이 좋네요 ㅎㅎㅎ
생각보다 복잡한 과정을 거치게 될줄 알았으나
다행히 너무 큰 어려움 없이 구현하였네요
제가 구현한 방식은 아무래도 많이 다듬어져 있지 않은 방식이라
다른분들이 구현한 방식이 더 좋고 안정적인 방법일거라 생각합니다.
참고용으로만 봐주세요!