반응형

저번 시간엔 댓글에 이미지를 첨부하고 첨부한 이미지를 삭제하는걸 해봤다. 이번엔 등록한 댓글을 삭제하는 것을 해보려한다.

 

먼저 이미지가 있는 댓글과 없는 댓글을 등록한다. 삭제할때 이미지가 있는 경우도 있고 없는 경우도 있기때문에 이와 같이 준비해두는 것이 좋다.

 

위 화면은 댓글이 보이는 화면이다. 당연히 게시판의 내용을 보는 페이지다. 확인해보자.

 

/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="$('#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='memo_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;
          }
        }
      }
  });
}    

function memo_file_del(fid){

if(!confirm('삭제하시겠습니까?')){
return false;
}

var data = {
    fid : fid
};
    $.ajax({
        async : false ,
        type : 'post' ,
        url : '/memo_file_delete' ,
        data  : data ,
        dataType : 'json' ,
        error : function() {} ,
        success : function(return_data) {
            if(return_data.result=="no"){
                alert('삭제하지 못했습니다. 관리자에게 문의하십시오.');
                return;
            }else{
              $("#f_"+fid).hide();
              $("#file_table_id").val('');
              $("#upfile").hide();
              $("#filebutton").show();
            }
        }
});

}

function memo_del(memoid){

if(!confirm('삭제하시겠습니까?')){
  return false;
}

var data = {
    memoid : memoid
};
    $.ajax({
        async : false ,
        type : 'post' ,
        url : '/memo_delete' ,
        data  : data ,
        dataType : 'json' ,
        error : function() {} ,
        success : function(return_data) {
          if(return_data.result=="login"){
            alert('로그인 하십시오.');
            return;
          }else if(return_data.result=="my"){
            alert('본인이 작성한 글만 삭제할 수 있습니다.');
            return;
          }else if(return_data.result=="fail"){
            alert('삭제하지 못했습니다. 관리자에게 문의하십시오.');
            return;
          }else if(return_data.result=="nodata"){
            alert('변수값이 없거나 해당되는 메모가 없습니다.');
            return;
          }else{
            $("#memo_"+memoid).hide();
          }
        }
});

}

</script>

메모의 삭제버튼을 클릭하면 작동하는 memo_del()함수를 추가했다. ajax의 경로인 /memo_delete를 추가해보자. 라우트에 등록하고 컨트롤러에 등록해주면 된다. 혹시 이부분을 빼먹거나 실수를 하게 되면 404 not found 메세지를 보게 된다.

 

/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');
$routes->post('/memo_file_delete', 'MemoController::memo_file_delete');
$routes->post('/memo_delete', 'MemoController::memo_delete');

//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';
}

컨트롤러도 추가하자.

 

/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);
    }

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

    public function memo_delete()
    {
        if(!isset($_SESSION['userid'])){//로그인여부
            $retun_data = array("result"=>"login");
            return json_encode($retun_data);
            exit;
        }
        $db = db_connect();
        $memoid=$this->request->getVar('memoid');
        $query = "select * from memo where memoid=".$memoid;
        $rs = $db->query($query);
        if($memoid and $rs->getRow()->memoid){//memoid가 있는지 또는 메모가 테이블에 있는지
            if($rs->getRow()->userid==$_SESSION['userid']){//본인이 작성한 메모인지
                $query2= "delete from memo where memoid=".$memoid;
                if($rs2 = $db->query($query2)){//삭제했는지
                    $query3 = "select * from file_table where type='memo' and bid=".$rs->getRow()->bid." and memoid=".$memoid;
                    $rs3 = $db->query($query3);
                    if(isset($rs3->getRow()->filename) and unlink('uploads/'.$rs3->getRow()->filename)){
                        $query4= "delete from file_table where fid=".$rs3->getRow()->fid;
                        $rs4 = $db->query($query4);
                    }
                    $retun_data = array("result"=>"ok");
                    return json_encode($retun_data);
                    exit;
                }else{
                    $retun_data = array("result"=>"fail");
                    return json_encode($retun_data);
                    exit;
                }
            }else{
                $retun_data = array("result"=>"my");
                return json_encode($retun_data);
                exit;
            }
        }else{
            $retun_data = array("result"=>"nodata");
            return json_encode($retun_data);
            exit;
        }
       
       
    }

   
}

컨트롤러의 내용은 간단하다. 삭제하려는 사용자가 쓴 댓글이 맞는지 확인하고 삭제한다. 댓글에 이미지가 있으면 이미지 파일을 삭제하고 테이블에서 삭제하는 것이다. 간단하다.

 

다음 시간엔 댓글의 수정을 해보겠다. 댓글의 수정이 은근히 어렵다....ㅡ.ㅡ;;

반응형

+ Recent posts