Web/PHP

[라라벨] 댓글과 대댓글 페이지네이션 구현하기

_sparrow 2020. 4. 18. 16:22
반응형

댓글과 대댓글 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 부분만 손대 주면 동일한 방식으로 표현되리라 생각됩니다.

아직 제 웹사이트에 무한 대댓글 적용은 생각하지 않고 있어서 대댓글 까지만 구현했습니다.

반응형