반응형

이번엔 게시판에 댓글 다는 것을 해보자. 댓글이 뭔지 모르진 않겠지 설마.

 

댓글은 게시물의 내용을 보는 뷰페이지에 있다. 뷰 페이지를 수정해보자.

 

/app/Views/board_view.php

 

<h3 class="pb-4 mb-4 fst-italic border-bottom" style="text-align:center;">
        - 게시판 보기 -
      </h3>

      <article class="blog-post">
        <h2 class="blog-post-title"><?php echo $view->subject;?></h2>
        <p class="blog-post-meta"><?php echo $view->regdate;?> by <a href="#"><?php echo $view->userid;?></a></p>

        <hr>
       
        <p>
        <?php echo $view->content;?>
        </p>
        <br>
        <?php
        if(isset($view->fs)){
          $vfs = explode(",",$view->fs);
          foreach($vfs as $img){
            if(isset($img)){
          ?>
            <img src="<?php echo  base_url('/uploads/'.$img);?>">
          <?php
            }
          }
        }?>
        <hr>
        <p style="text-align:right;">
          <?php
          if(isset($_SESSION['userid'])==$view->userid){
          ?>
          <a href="/modify/<?php echo $view->bid;?>"><button type="button" class="btn btn-primary">수정</button><a>
          <a href="/delete/<?php echo $view->bid;?>"><button type="button" class="btn btn-warning">삭제</button><a>
          <?php }?>
          <a href="/board"><button type="button" class="btn btn-primary">목록</button><a>
        </p>
      </article>
      <hr>

    <div style="margin-top:30px;">
        <form class="row g-3">
          <input type="hidden" name="file_table_id" id="file_table_id" value="">
         
          <div class="col-md-8">
            <textarea class="form-control" placeholder="댓글을 입력해주세요." id="memo" style="height: 60px"></textarea>
          </div>
          <div class="col-md-2">
            <button type="button" class="btn btn-secondary" id="memo_button">댓글등록</button>
          </div>
          <div class="col-md-2" id="memo_image">
            <div class="btn btn-warning" id="filebutton" onclick="onclick=document.all.upfile.click()">사진첨부</div>
            <input type="file" name="upfile" id="upfile" style="display:none;" />
          </div>

        </form>
    </div>

    <div id="memo_place">
      <?php
        if(isset($memoArray)){
          foreach($memoArray as $ma){
        ?>
            <div class="card mb-4" id="memo_<?php echo $ma->memoid?>" style="max-width: 100%;margin-top:20px;">
            <div class="row g-0">
              <div class="col-md-12">
                <div class="card-body">
                  <p class="card-text">
                  <?php
                  if($ma->filename){
                  ?>
                  <img src="/uploads/<?php echo $ma->filename;?>" style="max-width:90%;">
                  <?php }?>
                  <br>  
                  <?php echo $ma->memo;?></p>
                  <p class="card-text"><small class="text-muted"><?php echo $ma->userid;?> / <?php echo $ma->regdate;?></small></p>
                  <p class="card-text" style="text-align:right"><button type="button" class="btn btn-secondary btn-sm memo_reply"  mid="<?php echo $ma->memoid?>">답글</button>
                  <?php if(isset($_SESSION['userid']) and $_SESSION['userid']==$ma->userid){?>
                    <a href="javascript:;" onclick="memo_modify(<?php echo $ma->memoid?>)"><button type="button" class="btn btn-secondary btn-sm">수정</button></a>&nbsp;<a href="javascript:;" onclick="memo_del(<?php echo $ma->memoid?>)"><button type="button" class="btn btn-secondary btn-sm">삭제</button></a>
                  <?php }?>
                  </p>
                </div>
              </div>
            </div>
          </div>
         
        <?php }
        }
        ?>
    </div>

<script>
  $("#memo_button").click(function () {
        var file_table_id = $("#file_table_id").val();
        var data = {
            memo : $('#memo').val() ,
            bid : <?php echo $view->bid;?>,
            file_table_id : file_table_id
        };

        if(!data.memo){
          alert('댓글을 입력하세요.');
          return false;
        }
        $.ajax({
            async : false ,
            type : 'post' ,
            url : '/memo_write' ,
            data  : data ,
            dataType : 'html' ,
            error : function() {} ,
            success : function(return_data) {
              if(return_data=="login"){
                alert('로그인 하십시오.');
                return;
              }else if(return_data=="memo"){
                alert('댓글을 입력하세요.');
                return;
              }else{
                $('#memo').val('')
                $("#file_table_id").val('');
                $("#f_"+file_table_id).hide();
                $("#filebutton").show();
                $("#memo_place").prepend(return_data);
              }
            }
        });
    });

$("#upfile").change(function(){

  var files = $('#upfile').prop('files');
  for(var i=0; i < files.length; i++) {
      attachFile(files[i]);
  }

  $('#upfile').val('');

});  

function attachFile(file) {
  var formData = new FormData();
  formData.append("savefile", file);
  $.ajax({
      url: '/save_image_memo',
      data: formData,
      cache: false,
      contentType: false,
      processData: false,
      dataType : 'json' ,
      type: 'POST',
      success: function (return_data) {
        if(return_data.result=='success'){
            $("#file_table_id").val(return_data.fid);
            var html = "<div class='col' id='f_"+return_data.fid+"'><div class='card h-100'><img src='/uploads/"+return_data.savename+"' class='card-img-top'><div class='card-body'><button type='button' class='btn btn-warning' onclick='file_del("+return_data.fid+")'>삭제</button></div></div></div>";
            $("#upfile").hide();
            $("#filebutton").hide();
            $("#memo_image").append(html);
        }else{
          if(return_data.data=="login"){
            alert('로그인 하십시오.');
            return;
          }
        }
      }
  });
}    

</script>

기존에 있던 board_view.php 파일에 댓글을 입력할 부분과 입력 후 표시될 부분을 작업해 주었다. 거기에 댓글을 입력하고 처리하는 ajax 부분도 추가했다.

 

ajax부분에 보면 url이 있다. 경로가 있으니 라우트를 추가해야한다. 추가해보자.

 

/app/Config/Routes.php

 

<?php

namespace Config;

// Create a new instance of our RouteCollection class.
$routes = Services::routes();

// Load the system's routing file first, so that the app and ENVIRONMENT
// can override as needed.
if (is_file(SYSTEMPATH . 'Config/Routes.php')) {
    require SYSTEMPATH . 'Config/Routes.php';
}

/*
 * --------------------------------------------------------------------
 * Router Setup
 * --------------------------------------------------------------------
 */
$routes->setDefaultNamespace('App\Controllers');
$routes->setDefaultController('Home');
$routes->setDefaultMethod('index');
$routes->setTranslateURIDashes(false);
$routes->set404Override();
// The Auto Routing (Legacy) is very dangerous. It is easy to create vulnerable apps
// where controller filters or CSRF protection are bypassed.
// If you don't want to define all routes, please use the Auto Routing (Improved).
// Set `$autoRoutesImproved` to true in `app/Config/Feature.php` and set the following to true.
// $routes->setAutoRoute(false);

/*
 * --------------------------------------------------------------------
 * Route Definitions
 * --------------------------------------------------------------------
 */

// We get a performance increase by specifying the default
// route since we don't have to scan directories.

//게시판
$routes->get('/', 'Home::index');
$routes->get('/board', 'Board::list');
$routes->get('/boardWrite', 'Board::write');
$routes->match(['get', 'post'], 'writeSave', 'Board::save');
$routes->get('/boardView/(:num)', 'Board::view/$1');
$routes->get('/modify/(:num)', 'Board::modify/$1');
$routes->get('/delete/(:num)', 'Board::delete/$1');
$routes->post('/save_image', 'Board::save_image');
$routes->post('/file_delete', 'Board::file_delete');

//댓글
$routes->match(['get', 'post'], '/memo_write', 'MemoController::memo_write');
$routes->post('/save_image_memo', 'MemoController::save_image_memo');

//member
$routes->get('/login', 'MemberController::login');
$routes->get('/logout', 'MemberController::logout');
$routes->match(['get', 'post'], '/loginok', 'MemberController::loginok');
/*
 * --------------------------------------------------------------------
 * Additional Routing
 * --------------------------------------------------------------------
 *
 * There will often be times that you need additional routing and you
 * need it to be able to override any defaults in this file. Environment
 * based routes is one such time. require() additional route files here
 * to make that happen.
 *
 * You will have access to the $routes object within that file without
 * needing to reload it.
 */
if (is_file(APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php')) {
    require APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php';
}

라우트에 경로를 추가해줬다. 또하나 컨트롤러를 댓글용으로 새로 지정해줬다. 컨트롤러의 이름은 MemoController 이다. 같은 이름의 컨트롤러 파일을 만들어보자.

 

/app/Controllers/MemoController.php

 

<?php

namespace App\Controllers;
use App\Models\BoardModel;//사용할 모델을 반드시 써줘야한다.

class MemoController extends BaseController
{
    public function memo_write()
    {
        if(!isset($_SESSION['userid'])){
            return "login";
            exit;
        }
       
        $db = db_connect();
        $memo=$this->request->getVar('memo');
        $bid=$this->request->getVar('bid');
        $file_table_id=$this->request->getVar('file_table_id');

        $sql="INSERT INTO memo
            (bid, userid, memo, status)
            VALUES(".$bid.", '".$_SESSION['userid']."', '".$memo."', 1)";
        $rs = $db->query($sql);
        $insertid=$db->insertID();
        //error_log ('['.__FILE__.']['.__FUNCTION__.']['.__LINE__.']['.date("YmdHis").']'.print_r($file_table_id,true)."\n", 3, './php_error_'.date("Ymd").'.log');
        if(!empty($file_table_id)){//첨부한 파일이 있는 경우에만
            $uq="update file_table set bid=".$bid.", memoid=".$insertid." where fid=".$file_table_id;
            $uqs = $db->query($uq);
            $fquery="select * from file_table where status=1 and fid=".$file_table_id;
            $rs2 = $db->query($fquery);
            $imgarea = "<img src='/uploads/".$rs2->getRow()->filename."' style='max-width:90%'>";
        }else{
            $imgarea="";
        }

        $return_data = "<div class=\"card mb-4\" id=\"memo_".$insertid."\" style=\"max-width: 100%;margin-top:20px;\">
                <div class=\"row g-0\">
                    <div class=\"col-md-12\">
                    <div class=\"card-body\">
                    <p class=\"card-text\">".$imgarea."<br>".$memo."</p>
                    <p class=\"card-text\"><small class=\"text-muted\">".$_SESSION['userid']." / now</small></p>
                    <p class=\"card-text\" style=\"text-align:right\"><a href=\"javascript:;\" onclick=\"memo_modify(".$insertid.")\"><button type=\"button\" class=\"btn btn-secondary btn-sm\">수정</button></a>&nbsp;<a href=\"javascript:;\" onclick=\"memo_del(".$insertid.")\"><button type=\"button\" class=\"btn btn-secondary btn-sm\">삭제</button></a></p>
                    </div>
                </div>
                </div>
            </div>";
        return $return_data;
    }

    public function save_image_memo()
    {
        $db = db_connect();

        if(!isset($_SESSION['userid'])){
            $retun_data = array("result"=>"fail", "data"=>"login");
            return json_encode($retun_data);
            exit;
        }
       
        $file = $this->request->getFile('savefile');
            if($file->getName()){
                $filename = $file->getName();
                //$filepath = WRITEPATH. 'uploads/' . $file->store();
                $newName = $file->getRandomName();
                $filepath = $file->store('memo/', $newName);
            }

            if(isset($filepath)){
                $sql2="INSERT INTO file_table
                        (bid, userid, filename, type)
                        VALUES('', '".$_SESSION['userid']."', '".$filepath."', 'memo')";
                $rs2 = $db->query($sql2);
                $insertid=$db->insertID();                
            }

        $retun_data = array("result"=>"success", "fid"=>$insertid, "savename"=>$filepath);
        return json_encode($retun_data);
    }
}

 

MemoController.php 라는 파일을 새로 만들었다. 물론 기존에 있던 Board에 추가해줘도 된다. 하지만 너무 많아지면 가독성이 떨어지고 함수 찾기가 힘들어진다. 적당히 알아서 조절하자.

이렇게 댓글입력하는 부분이 보이면 된다. 이제 여기에 댓글을 입력하고 댓글을 등록해보자.

 

댓글을 입력하면 이 컨트롤러에서 memo 테이블에 저장을 하고 view 에 뿌려줄 html을 리턴해 준다.

 

 

이렇게 들어가면 성공이다. ajax를 사용했으므로 이 경우에는 댓글을 등록해도 화면이 새로고침되거나 다른 페이지로 갔다 오거나 하지 않고 그대로 화면에 보이게 된다. 이렇게 됐다면 성공이다.

 

이제 리스트를 보자.

 

/app/Views/board_list.php

 

    <table class="table">
        <thead>
            <tr>
            <th scope="col">번호</th>
            <th scope="col">글쓴이</th>
            <th scope="col">제목</th>
            <th scope="col">등록일</th>
            </tr>
        </thead>
        <tbody id="board_list">
            <?php
            $idNumber = $total - ($page-1)*$perPage;
            foreach($list as $ls){
            ?>
                <tr>
                    <th scope="row"><?php echo $idNumber--;?></th>
                    <td><?php echo $ls->userid;?></td>
                    <td><a href="/boardView/<?php echo $ls->bid;?>"><?php echo $ls->subject;?></a>
                    <?php if($ls->filecnt){?>
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-card-image" viewBox="0 0 16 16">
                        <path d="M6.002 5.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/>
                        <path d="M1.5 2A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13zm13 1a.5.5 0 0 1 .5.5v6l-3.775-1.947a.5.5 0 0 0-.577.093l-3.71 3.71-2.66-1.772a.5.5 0 0 0-.63.062L1.002 12v.54A.505.505 0 0 1 1 12.5v-9a.5.5 0 0 1 .5-.5h13z"/>
                        </svg>
                    <?php }?>
                    <?php if($ls->memocnt){?>
                        <span <?php if((time()-strtotime($ls->memodate))<=86400){ echo "style='color:red;'";}?>>
                            [<?php echo $ls->memocnt;?>]
                        </span>
                    <?php }?>
                    <?php if($ls->newid){?>
                        <span class="badge bg-danger">New</span>
                    <?php }?>
                    </td>
                    <td><?php echo $ls->regdate;?></td>
                </tr>
            <?php }?>
        </tbody>
        </table>
        <!-- 페이징 -->
        <div style="padding-top:30px;">
            <?= $pager_links ?>
        </div>
        <p style="text-align:right;">
            <a href="/boardWrite"><button type="button" class="btn btn-primary">등록</button><a>
            <?php
            if(isset($_SESSION['userid'])){
            ?>
                <a href="/logout"><button type="button" class="btn btn-warning">로그아웃</button><a>
            <?php }else{?>
                <a href="/login"><button type="button" class="btn btn-warning">로그인</button><a>
            <?php }?>
        </p>

 

목록에 new버튼이 나타나고 댓글갯수가 표시되면 성공이다. 만약 이렇게 나오지 않는다면 컨트롤러를 다시 살펴보자.

 

/app/Controllers/Board.php

 

<?php

namespace App\Controllers;
use App\Models\BoardModel;//사용할 모델을 반드시 써줘야한다.

class Board extends BaseController
{
    public function list()
    {
        $db = db_connect();
        $page    = $this->request->getVar('page') ?? 1;//현재 페이지, 없으면 1
        $perPage = 10;//한 페이지당 출력할 게시물 수
        $startLimit = ($page-1)*$perPage;//쿼리의 limit 시작 부분
        $sql = "select b.*, if((now() - regdate)<=86400,1,0) as newid
        ,(select count(*) from memo m where m.status=1 and m.bid=b.bid) as memocnt
        ,(select m.regdate from memo m where m.status=1 and m.bid=b.bid order by m.memoid desc limit 1) as memodate
        ,(select count(*) from file_table f where f.type='board' and f.status=1 and f.bid=b.bid) as filecnt
        from board b where 1=1";
        $order = " order by bid desc";
        $limit = " limit $startLimit, $perPage";
        $query = $sql.$order.$limit;
        $rs = $db->query($query);
        $rs2 = $db->query($sql);
        $total = $rs2->getNumRows();//전체 게시물수

        $data['list'] = $rs->getResult();
        $data['total'] = $total;
        $data['page'] = $page;
        $data['perPage'] = $perPage;

        $pager = service('pager');//페이저를 호출한다.
        $pager_links = $pager->makeLinks($page, $perPage, $total, 'default_full');
        $data['pager_links'] = $pager_links;//페이징을 구현될 부분을 리턴한다.

        return render('board_list', $data);//view에 리턴
    }

    public function write()
    {
        if(!isset($_SESSION['userid'])){
            echo "<script>alert('로그인하십시오.');location.href='/login'</script>";
            exit;
        }
        return render('board_write');  
    }

    public function save()
    {
        if(!isset($_SESSION['userid'])){
            echo "<script>alert('로그인하십시오.');location.href='/login'</script>";
            exit;
        }
        $db = db_connect();
        $bid=$this->request->getVar('bid');//bid값이 있으면 수정이고 아니면 등록이다.
        $subject=$this->request->getVar('subject');
        $content=$this->request->getVar('content');
        $file_table_id=$this->request->getVar('file_table_id');

        if($bid){
            $query = "select * from board where bid=".$bid;
            $rs = $db->query($query);
            if($_SESSION['userid']==$rs->getRow()->userid){
                $sql="update board set subject='".$subject."', content='".$content."' where bid=".$bid;
                $rs = $db->query($sql);
                if(isset($file_table_id)){//첨부한 이미지가 있으면
                    $fti=explode(',',$file_table_id);
                    foreach($fti as $fi){
                        if(isset($fi)){
                            $sql2="update file_table set bid=".$bid." where fid=".$fi;
                            $rs2 = $db->query($sql2);                
                        }
                    }
                }
                return $this->response->redirect(site_url('/boardView/'.$bid));
            }else{
                echo "<script>alert('본인이 작성한 글만 수정할 수 있습니다.');location.href='/login';</script>";
                exit;
            }
        }

        //$file = $this->request->getFile('upfile');//첨부한 파일의 정보를 가져온다.
        $files = $this->request->getFileMultiple("upfile"); //다중 업로드 파일 정보
        $filepath = array();
        foreach($files as $file){
            if($file->getName()){//파일 정보가 있으면 저장한다.
                $filename = $file->getName();//기존 파일명을 저장할때 필요하다. 여기서는 사용하지 않는다.
                //$filepath = WRITEPATH. 'uploads/' . $file->store(); 매뉴얼에 나와있는 파일 저장 방법이다.여기서는 안쓴다.
                $newName = $file->getRandomName();//서버에 저장할때 파일명을 바꿔준다.
                $filepath[] = $file->store('board/', $newName);//CI4의 store 함수를 이용해 저장한다. 저장한 파일의 경로와 파일명을 리턴, 배열로 저장한다.
            }
        }

        $sql="insert into board (userid,subject,content) values ('".$_SESSION['userid']."','".$subject."','".$content."')";
        $rs = $db->query($sql);
        $insertid=$db->insertID();
        foreach($filepath as $fp){//배열로 저장한 파일 저장 정보를 디비에 입력한다.
            if(isset($fp)){
                $sql2="INSERT INTO file_table
                        (bid, userid, filename, type)
                        VALUES('".$insertid."', '".$_SESSION['userid']."', '".$fp."', 'board')";
                $rs2 = $db->query($sql2);                
            }
        }

        if(isset($file_table_id)){//첨부한 이미지가 있으면
            $fti=explode(',',$file_table_id);
            foreach($fti as $fi){
                if(isset($fi)){
                    $sql2="update file_table set bid=".$insertid." where fid=".$fi;
                    $rs2 = $db->query($sql2);                
                }
            }
        }

        return $this->response->redirect(site_url('/boardView/'.$insertid));
    }

    public function view($bid = null)
    {
        $db = db_connect();
        $query = "select b.*,(select GROUP_CONCAT(filename) from file_table f where f.bid=b.bid and f.type='board') as fs from board b where b.bid=".$bid;
        $rs = $db->query($query);
        $data['view'] = $rs->getRow();

        //메모
        $query2="select *, m.userid, m.regdate, m.memoid from memo m
                left join file_table f on m.memoid=f.memoid and f.type='memo'
                where m.status=1 and m.bid=".$bid." order by ifnull(m.pid,m.memoid) desc, m.memoid asc";
        $rs2 = $db->query($query2);
        $data['memoArray'] = $rs2->getResult();
        return render('board_view', $data);  
    }

    public function modify($bid = null)
    {
        $db = db_connect();
        $query = "select * from board b where b.bid=".$bid;
        $rs = $db->query($query);
        if($_SESSION['userid']==$rs->getRow()->userid){
            $data['view'] = $rs->getRow();
            $query3 = "select * from file_table where type='board' and bid=".$bid;
            $rs3 = $db->query($query3);
            $data['fs']=$rs3->getResult();
            return render('board_write', $data);  
        }else{
            echo "<script>alert('본인이 작성한 글만 수정할 수 있습니다.');location.href='/login';</script>";
            exit;
        }
       
    }

    public function delete($bid = null)
    {

        $db = db_connect();
        $query = "select * from board where bid=".$bid;
        $rs = $db->query($query);
        if($_SESSION['userid']==$rs->getRow()->userid){
            $query3 = "select * from file_table where type='board' and bid=".$bid;
            $rs3 = $db->query($query3);
            $fs=$rs3->getResult();
            foreach($fs as $f3){
                unlink('uploads/'.$f3->filename);
            }
            $query4 = "delete from file_table where type='board' and bid=".$bid;
            $rs4 = $db->query($query4);
            $query2 = "delete from board where bid=".$bid;
            $rs2 = $db->query($query2);
            return $this->response->redirect(site_url('/board'));
        }else{
            echo "<script>alert('본인이 작성한 글만 삭제할 수 있습니다.');location.href='/login';</script>";
            exit;
        }
    }

    public function save_image()
    {
        $db = db_connect();
       
        $file = $this->request->getFile('savefile');
            if($file->getName()){
                $filename = $file->getName();
                //$filepath = WRITEPATH. 'uploads/' . $file->store();
                $newName = $file->getRandomName();
                $filepath = $file->store('board/', $newName);
            }

            if(isset($filepath)){
                $sql2="INSERT INTO file_table
                        (bid, userid, filename, type)
                        VALUES('', '".$_SESSION['userid']."', '".$filepath."', 'board')";
                $rs2 = $db->query($sql2);
                $insertid=$db->insertID();                
            }

        $retun_data = array("result"=>"success", "fid"=>$insertid, "savename"=>$filepath);
        return json_encode($retun_data);
    }

    public function file_delete()
    {
        $db = db_connect();
        $fid=$this->request->getVar('fid');
        $file_table_id=$this->request->getVar('file_table_id');
        $query = "select * from file_table where fid=".$fid;
        $rs = $db->query($query);
        if(unlink('uploads/'.$rs->getRow()->filename)){
            $query2= "delete from file_table where fid=".$fid;
            $rs2 = $db->query($query2);
            $file_table_id=str_replace(",".$fid,'',$file_table_id);
        }
       
       
        $retun_data = array("result"=>"ok", "file_table_id"=>$file_table_id);
        return json_encode($retun_data);
    }
}

컨트롤러를 수정했는데도 안된다면 처음부터 다시해보자. 안되면 될때까지~ 

 

 

반응형

+ Recent posts