on
[라라벨] 댓글과 대댓글 페이지네이션 구현하기
[라라벨] 댓글과 대댓글 페이지네이션 구현하기
댓글과 대댓글 DB설계는 각자 상황에 맞게 컬럼을 바꾸거나 추가해서 사용하시길 바랍니다.
댓글과 대댓글 구성은 위의 링크를 참고해주세요.
댓글과 대댓글 구성을 한 후에는 페이지네이션이 필수라고 생각합니다.
댓글과 대댓글이 한 게시글에 1000개 10000개 그이상이 되는데 모든 정보를 한번에 제공하면 처리하는데 속도가 느릴뿐만 아니라 사용자 역시 모든 댓글정보를 보고싶지않은데 보게 되는 경우가 발생합니다.
이를 위해서 라라벨에서 페이지네이션을 제공하지만 만들고 있는 웹사이트는 프론트와 백이 따로 구성되어있습니다.
제가 맡은 백 부분만 라라벨을 사용하다보니 라라벨에서 제공하는 블레이드템블릿을 활용하지못하게 되어 제가 직접 페이지네이션 구현을 하게 되었습니다.
페이지네이션 구현하기
우선 프론트에서 요청을 게시글 번호와 페이지번호를 요청해야합니다.
http://example.com/1/1 이면 게시글 1번에 게시글의 댓글 1페이지를 제공해달라고 요청하는겁니다.
댓글 1페이지는 댓글을 6개씩 요청하기로 했고 대댓글은 댓글의 개수에 영향을 주지않도록 구성했습니다.
댓글 6개에 포함된 대댓글이 아무리많아도 최대 6개만 제공하는거죠.
가장먼저 댓글 테이블에서 게시글 번호와 class가 0(댓글만 class값 0)인것 개수 파악을 해줍니다.
페이지네이션을 위한 댓글 최소개수 부터 최대개수까지 충족하는지 확인하기 위해서 입니다.
public function comments_list($postNum,$page) { //댓글 테이블에서 게시글 번호와 class가 0(댓글)인것 개수 파악 $contentCount = DB::table('comments') ->where(['postNum'=> $postNum,'class'=> 0])->count(); }
페이지당 댓글 최소개수가 충족이되면 페이지네이션을 하기위한 데이터를 가져오는 쿼리문을 실행하는거죠.
비교[하단의 코드내부 if문]는 (페이지번호 -1)*(페이징할 댓글개수) +1 로 해주면 됩니다.
ex) 페이지 번호 1 페이징할 댓글개수 6 이면 1개이상이면 데이터가져오기 허가!
페이지 번호 2 페이징할 댓글 개수 6일땐 7개 이상이면 데이터가져오기 허가!
//public function comments_list($postNum,$page) // { //페이지네이션 페이지마다 최소요구개수를 충족하는지 판단 불충분할때 false 전달 if ($contentCount<(($page-1)*6+1)) { $data = array( 'key' => false ); return json_encode($data,JSON_UNESCAPED_UNICODE); } //}
페이지네이션을 할 수 있는 데이터들이 있다면
페이지네이션하기위한 내부 댓글 인덱스 번호들을 가지고 옵니다.
가져와야하는 댓글들에 대댓글들이 몇개나 포함 되어있는지 확인하기 위해서요
//public function comments_list($postNum,$page) //{ //페이지네이션 내부 댓글 인덱스번호(배열형태) $indexNums = DB::table('comments') ->where(['postNum'=> $postNum,'class'=> 0]) ->offset(($page-1)*6)->limit(6) ->pluck('indexComments'); // 페이지네이션번호마다 댓글에 종속된느 대댓글(class값 1) 인덱스번호(배열) $replyCount = DB::table('comments') ->where(['postNum'=> $postNum,'class'=> 1]) ->whereIn('groupNum',$indexNums) ->pluck('indexComments'); //}
offset와 limit는 쿼리에서 반환되는 결과의 갯수를 제한하거나, 주어진 갯수만큼 결과반환하는 메소드입니다.
pluck 메소드에 대한 사용방법입니다.
pluck() {#collection-method} pluck 메소드는 주어진 키에 대한 모든 값을 반환합니다: $collection = collect([ ['product_id' => 'prod-100', 'name' => 'Desk'], ['product_id' => 'prod-200', 'name' => 'Chair'], ]); $plucked = $collection->pluck('name'); $plucked->all(); // ['Desk', 'Chair']
whereIn 메소드는 주어진 배열 안에 포함 된 주어진 키/값을 사용하여 컬렉션을 필터링하는 메소드입니다.
대댓글을 먼저 조회하고 이 대댓글 사이에서 페이지네이션되어야하는 댓글인덱스를 그룹번호로 조회해서 해당되는 대댓글 인덱스를 배열로 만듭니다.
// 댓글과 대댓글 인덱스 배열 하나로 합치기 $array =Arr::collapse([$indexNums, $replyCount]);
배열을 합쳐주고 그룹번호, 댓글 대댓글 정렬순서 인덱스번호에 맞게 정렬해서 프론트(웹페이지)로 전달해주면 됩니다. 이렇게 보내고 나서 프론트에서 class가 1인것들만 위치 조정해서 페이지에 보여주면 됩니다.
전체 페이지네이션 코드입니다.
public function comments_list($postNum,$page) { //댓글 테이블에서 게시글 번호와 class가 0(댓글)인것 개수 파악 $contentCount = DB::table('comments') ->where(['postNum'=> $postNum,'class'=> 0])->count(); //페이지네이션 페이지마다 최소요구개수를 충족하는지 판단 if ($contentCount<(($page-1)*6+1)) { $data = array( 'key' => false ); return json_encode($data,JSON_UNESCAPED_UNICODE); } //페이지네이션 내부 댓글 인덱스번호(배열형태) $indexNums = DB::table('comments') ->where(['postNum'=> $postNum,'class'=> 0]) ->offset(($page-1)*6)->limit(6) ->pluck('indexComments'); // 페이지네이션번호마다 포함되는 대댓글 개수파악 $replyCount = DB::table('comments') ->where(['postNum'=> $postNum,'class'=> 1]) ->whereIn('groupNum',$indexNums) ->pluck('indexComments'); //배열 합치기 $array =Arr::collapse([$indexNums, $replyCount]); $content = DB::table('comments')->where('postNum', $postNum) ->whereIn('groupNum',$array) ->orderBy('groupNum','asc') ->orderBy('indexComments','asc') ->orderBy('order','asc') ->get(); return json_encode($content,JSON_UNESCAPED_UNICODE); }
아직 댓글 대댓글 1000개 10000개 작성하지않아서 성능이 어떨지는 잘 모르겠습니다.
몇십개 정도는 잘 전달되어 댓글과 대댓글들이 끊김없이 보여집니다.
쿼리빌더로 작성되어있는데 SQL사용하려면 조금만 수정해서 사용하면 됩니다.
무한 대댓글은 class 부분만 손대주면 동일한 방식으로 표현되리라 생각됩니다.
아직 제 웹사이트에 무한 대댓글 적용은 생각하지않고 있어서 대댓글 까지만 구현했습니다.
from http://xerar.tistory.com/45 by ccl(A) rewrite - 2020-04-18 16:28:25