TIP게시판

제목 ci 답변형 게시판입니다.
글쓴이 개발사랑 작성시각 2013/02/06 14:14:42
댓글 : 20 추천 : 0 스크랩 : 0 조회수 : 19353   RSS
제가 이해한 로직이 맞는지도 점검할겸 글을 올립니다.
잘못되었으면 말씀해주세요.
일전에 다른분이 올려주신 소스에 답글과 spac_editor 등을 추가했습니다.
아 코드이그나이터를 이용해서 만들었습니다.
액티브레코드도 부분 부분 사용했습니다.

먼저 4가지의 필드가 필요합니다.
no = int로서 순차적으로 증가되는 각 필드의 고유값
list_number = 실제 정렬된 순서를 지정하는 필드
depth = 답글의 깊이를 정함
parent = 원본글의 no 값(저도 다른곳의 포스트를 보고 만들었는데 실제로서는 이 필드는 거의 필요가 없는듯 합니다.)

일단 리스트 출력상에서는 list_number asc로 출력합니다.

새글 기입시
등록된 글이 없이 처음일시 list_number에 무조건 1을 기입하도록 합니다.
새글등록시 이미 등록된 글에 가장 최신 list_number에 -1을 해 list_number를 등록하게 되어 있습니다.
이때 로직상 -1 이거나 0으로 되면 1로 세팅해서 업데이트 시킵니다.
그 이외에는 새 글 기입시 등록된 글보다 no값이 작은 경우 무조건 list_number를 +1시키고
새글은 등록된 글 중 가장 작은 list_number 값을 추출해 그 값에 -1을 해 입력시킵니다.
이때 parent_id는 원본글의 값 depth는 1로 세팅합니다.

답변글 등록시
parent_id는 원본글의 값 depth는 원본글의 depth에서 +1를 해 처리합니다.
list_number는 원본글의 list_number보다 큰 경우 전부 +1을 해주고 새글의 list_number는 원본글의 list_number에서
+1을 해 처리합니다. 그러면 원본글의 list_number보다 큰 경우와 원본글 사이에 숫자가 하나남는 상황이 생기고
그 숫자로 답글이 처리되어 list_number asc를 하면 답글이 원본글의 바로 밑에 출력됩니다.
아래는 소스입니다. 저도 정리한다고 남기는글인데 두서 없네요 혹시 의문사항이 생기시면 답글 바랍니다.


새글 기입시 (주석참고)
$this->title = $_POST['title'];
$this->memo = $_POST['memo'];
$this->name = $_POST['name'];
$this->img01 = $_FILES['userfile']['name'];
$this->ip = $_SERVER["REMOTE_ADDR"];
$this->date = date("Y-m-d H:i:s",time());

/*
$this->db->select_max('thread');
$result_set = $this->db->get('board');

$thread_array = $result_set->result_array();

print_r($thread_array);
exit;
*/
$this->db->insert('board', $this);

// 핵심은 list_number 필드에 있다.
// 그런데 데이터 많으면 부하걸리겠다. list_number를 계속 업데이트 해주어야 한다.

// 삽입된 원글의 아이디값을 추출한다.
$id = $this->db->insert_id();

// 원글보다 먼저 등록된 글들의 list_number를 다 1씩 증가시킨다.
// 왜냐하면 답글이 아니고 신규글이기 때문에 제일 위에 정렬된다.
$this->db->query("update board set list_number=list_number+1 where no <".$id);

// 가장작은 리스트 넘버의 값을 추출해서 거기에 -1를 한 값이 최종글의 번호가 된다.
// 게시판 리스트 정렬시에는 가장 작은 값이 위에 오게된다.
$res = $this->db->query("select min(list_number) as list_number_min from board");

$board_array = $res->result_array();

$num_rows = $res->num_rows();

$set_list_number = $board_array[0]['list_number_min'] - 1;

if($set_list_number == -1 || $set_list_number == 0)
{
$set_list_number = 1;
}

$data = array(
'list_number' => $set_list_number,
'depth' => 1,
'parent' => $id
);

$this->db->where('no', $id);
$this->db->update('board', $data);

답글 기입시(주석참고)
$this->title = $_POST['title'];
$this->memo = $_POST['memo'];
$this->name = $_POST['name'];
$this->img01 = $_FILES['userfile']['name'];
$this->ip = $_SERVER["REMOTE_ADDR"];
$this->date = date("Y-m-d H:i:s",time());
/*
$this->db->select_max('thread');
$result_set = $this->db->get('board');

$thread_array = $result_set->result_array();

print_r($thread_array);
exit;
*/
$this->db->insert('board', $this);

$id = $this->db->insert_id();

// 답글의 원본글의 정보를 추출한다.
$this->db->select('*');
$this->db->from('board');
$this->db->where('no', $_POST['no']);
$query = $this->db->get();

$sel_board_array = $query->result();
$depth = $sel_board_array[0]->depth + 1;

// 원본글의 list_number보다 큰 먼저 정렬된글들의 list_number를 전부더해 답글의 밑에 보이도록 한다.
// 이때 list_number가 작은글들은 업데이트 되지 않는다 왜냐하면 list_number가 큰 글들을 전부 +1 업데이트 시키고
// 원본글과 +1 시킨 글 사이에 답글의 list_number가 위치할것이기 때문이다.
$this->db->query("update board set list_number=list_number+1 where list_number >".$sel_board_array[0]->list_number);

$set_list_number = $sel_board_array[0]->list_number + 1;

if($set_list_number == -1 || $set_list_number == 0)
{
$set_list_number = 1;
}

$data = array(
'list_number' => $set_list_number,
'depth' => $depth,
'parent' => $sel_board_array[0]->no
);

$this->db->where('no', $id);
$this->db->update('board', $data);


// $res_set = $sel_board_array[0]->res + 1;
// $rev_set = $sel_board_array[0]->rev + 1;

// $this->db->set('res', 'res+1');
// $this->db->where('ref', $_POST['ref']);
// $this->db->where('res >', $sel_board_array[0]->res);
// $this->db->update('board');

// $this->db->query("update board set res=res+1 where ref ='".$_POST['ref']."' and res > ".$sel_board_array[0]->res);
// $this->db->query("update board set ref=".$_POST['no'].", rev = ".$rev_set.", res=".$res_set." where no = ".$id);

// $this->db->query();

/*
$data = array(
'ref' => $_POST['no'],
'res' => $res_set,
'rev' => $rev_set
);

$this->db->where('ref', $id);
$this->db->where('res >', $sel_board_array[0]->res);
$this->db->update('board', $data);
*/
첨부파일 board.zip (8.6 KB)
 다음글 ci 1.7 -> ci 2.1.3 업그레이드 방법 (3)
 이전글 HMVC 사용시 Form_validation callb... (1)

댓글

변종원(웅파) / 2013/02/06 14:44:10 / 추천 0
소스 공개 감사합니다.

주석에 보니 list_number 를 계속 업데이트 하는데 주석에 쓰신 것처럼
데이터가 많이지면 느려질 수 밖에 없습니다.

업데이트 하지 않는 로직들도 있으니 그걸 적용해서 만드시는게 좋을 것 같습니다.

로직은 머리 아프긴 합니다. 전에 게시판 답글 무한depth, 덧글 무한depth 구현하느라 
머리 아팠던 기억이 나네요.

개발사랑 / 2013/02/06 16:21:20 / 추천 0

예를 들면 어떤 로직이 있을까요? 좋은 곳 있으면 포스트 부탁드립니다.

변종원(웅파) / 2013/02/06 17:17:13 / 추천 0
네이버나 phpschool에서 검색해보시면 로직들 좀 나옵니다.
필드는 거의 비슷합니다. 3개의 필드로 되어있고 업데이트형이냐 비업데이트형이냐로 나뉘구요.
소수점 방식도 있고...

시간이 되면 전에 만든 게시판 로직 올려보겠습니다.
개발사랑 / 2013/02/06 17:47:57 / 추천 0

네 감사합니다. 꼭 좀 부탁드립니다!

변종원(웅파) / 2013/02/07 13:03:13 / 추천 0
board table

id               auto increment
board_pid 게시판 원글, 답글 번호 
reply_order 답글의 정렬용. 원글일 경우 0
is_delete 삭제여부 필드 Y 이면 삭제된 글임
is_list 삭제는 됐지만 리스트에 보여줄 필요가 있는 경우(원글이 삭제된 답글입니다. 구현용) Y이면 is_delete가 Y이더라도 리스트에 보여준다.
          완전히 안보이는 경우는 is_delete='Y' and id_list='N'인 경우임.
 
 
1. 입력시 
board_pid는 원글일 경우 기존 max값+1 하여 입력, 답글일 경우는 원글의 board_pid입력
reply_order는 원글일 경우 0, 답글일 경우는 기존 reply_order+1
 
 
2. 리스트 select 시의 주요 항목
 
where (is_delete='N' and .is_list = 'Y') or (is_delete='Y' and is_list = 'Y')
 
order by board_pid desc, reply_order asc, id desc
 
 
 
 
 
board_comments

id      auto increment
comment_id  원 게시글의 번호
board_id   원 게시글의 번호
comment_order   AAA형태 (알파벳 3개 기본, 3개씩 추가)
 
1. 입력시 comment_id와 comment_order 구하는 방식
$this->db->select_max('comment_id');
$this->db->select_max('comment_order');
$this->db->where('length(comment_order)', 3);
$this->db->where('board_id', $post['no']);
$query = $this->db->get($this->comment_table);

@$comment_nos = $query->row() ;

$comment_id = @$comment_nos->comment_id + 1 ;
$comment_order = @$comment_nos->comment_order;

if($comment_order == '')
{
     $comment_order_no = 'AAA';
}
else
{
   $comment_order_no = $this->depth_check2($comment_order,'');
}
 
 
2. 댓글 리스트
comment_id desc, LENGTH(comment_order) asc
 
 

 
참고함수 : AAA 에서 AAB로 올려주는 역할, AAZ에서 +1하면 ABA로.  depth는 AAA는 1depth, AAAAAA일 경우 2depth
function depth_check2($depth, $type)
     {
          if($type == 'level') {
               $now_article = $depth."AAA";
          }
        else
        {
               $length = strlen($depth);
               $cot = $length / 3;
               if($cot > 0)
               {
                    $odepth = substr($depth, 0, $length-3);
                    $depth = substr($depth, $length-3, 3);
                    $length = strlen($depth);
               }

            $pre = substr($depth,0,1);

               $mid = substr($depth,1,1);

               $last = substr($depth, $length-1,1);

               $temp1 = ord($pre); //문자를 숫자로
               $temp2 = ord($mid); //문자를 숫자로
               $temp3 = ord($last); //문자를 숫자로

               if($temp3 >= 90)
               { //Z 이하이면
                    $temp3 = "65";
                    $temp2 ++;
                    if($temp2 >= 90)
                    {
                         $temp2 = "65";
                         $temp1 ++;
                         if($temp1 >= 90)
                         {
                              $temp1 = "90";
                         }
                    }
               }
               else
               {
                    $temp3 ++;
               }

               if($cot > 0)
               {
                    $now_article = $odepth.chr($temp1).chr($temp2).chr($temp3); //증가시킨 값을 넣기
               }
               else
               {
                    $now_article = chr($temp1).chr($temp2).chr($temp3); //증가시킨 값을 넣기
               }
          }

          return $now_article;
 
     } 
변종원(웅파) / 2013/02/07 13:08:38 / 추천 0
개발사랑/

게시판 리스트의 답글은 무한depth는 아니고 1depth만 구현이 됐네요. (댓글 로직 적용하면 무한 가능)
대신 원글을 삭제했을 경우 원글이 삭제됐습니다 라고 표기하고 답글을 아래에 표현할 수 있게
처리했습니다. (네이버 카페 처럼)

로직 보니 댓글 무한 depth이긴 하나 AAA 형태로 AAAAAAAAAAAAA...... 무한대로 길어질 수 없는터라
실제적으로는 long text 필드 길이만큼 구현이 가능합니다.

보기가 좀 어려울 수 있는데 보시고 궁금한 사항은 올려주세요. 
개발사랑 / 2013/02/07 13:57:00 / 추천 0

네 감사합니다! 잘 볼게요!  답글도 무한 depth인거는 올려주실 수 없을런지요!?ㅋ 말씀을 들어보니 게시판 답글이 무한이 아니라고 하신거 같아 문의합니다 맞나요?ㅋ

변종원(웅파) / 2013/02/07 14:06:12 / 추천 0
개발사랑/ depth 필드만 넣으면 될건데요? ^^
꾸숑 / 2013/02/07 15:08:47 / 추천 0
개발사랑// 저 같은 경우에는 딱 코드 5줄?로 답글을 구현했습니다.
 CI를 사용하니 코드 길이가 확 줄어 드네요...
http://www.codeigniter-kr.org/source/view/665/page/1/
이곳 자료를 보면

application/views/write_form_view.php
   $query = $this->db->query("select MAX(gnum) as gnum from 테이블명");
   $gnum = current( $query->row_array());
   $gnum += 1;

application/views/comment_form_view.php
   $query = $this->db->query("select MAX(depth) as depth from 테이블명 where depth like '$depth%' and gnum=$gnum");
   $depth = $depth.chr(ord(substr($depth, -1)) +1);

application/models/board_model.php  //24줄
  $this->db->order_by('gnum desc, depth asc');


이렇게 되어 있습니다. 제가 길게 설명할 실력은 않되지만 참고하세요
제대로 작동 됩니다.
개발사랑 / 2013/02/08 09:02:14 / 추천 0
네 감사합니다!
개발사랑 / 2013/02/08 15:04:56 / 추천 0
구현중 모르는 부분이 생겨 글 드립니다. 답변 부탁드립니다. ㅠㅠ
comment_id desc 하면 나중에 작성한 답글이 무조건 위로 올라가지 않나요? 그리고 이미 고유의 id가 자동증가되게 되어 있는데 comment_id가 의미가 있나요?
변종원(웅파) / 2013/02/08 15:25:26 / 추천 0
개발사랑/ 네 id는 사실 중복입니다
개발사랑 / 2013/02/08 15:49:16 / 추천 0

다시 의문이 생겨 글 드립니다 ㅠㅠ 답변 감사드립니다.
올려주신 댓글은 1depth만 구현되는거 같은데요 주석에 보면 level값으로 깊이를 조정하는게 나와있습니다.
2depth이상일때 처리하는 부분도 올려주실 수 있을지요? 아니면 제가 이해를 못하고 있는건지 모르겠습니다.
확인부타드립니다. 감사합니다.

변종원(웅파) / 2013/02/08 16:04:38 / 추천 0
개발사랑/ 아래 함수에 $type에 level을 주면 레벨업(depth 업)이 됩니다.

function depth_check2($depth, $type)
     {
          if($type == 'level') {
               $now_article = $depth."AAA";
          }
개발사랑 / 2013/02/08 16:06:21 / 추천 0
다시 의문이 생겨 글 드립니다. ㅠㅠ
id 값으로 desc를 하면 답글이라도 무조건 최상위로 올라가는데요 이 부분 어떻게 처리해야 할지요?