8.15. 목록 화면 만들기

메모를 쓰고 목록을 확인하고 삭제할 수 있는 페이지를 만든다.

<?php
// 로그인 체크
session_start();
if (isset($_SESSION['member_id']) === false){
    header("Location: /");
    exit();
}

// DB Require
require_once("inc/db.php");

$member_id = $_SESSION['member_id'];
$post_query = "select post_id, post_content from tbl_post where member_id = ? order by insert_date desc limit 10";
$post_data = db_select($post_query, array($member_id));

$last_post_id = count($post_data) > 0 ? $post_data[count($post_data) - 1]['post_id'] : "0";

?>
<!DOCTYPE html>
<html>
    <head>
        <title>php-memo 목록</title>

        <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
        <script type="text/javascript">
            function post_delete(post_id){                
                $.post("/delete.api.php", {'post_id' : post_id})
                .done(function(result){
                    if (result['result']){
                        alert('삭제되었습니다.');
                        $('#post_' + post_id).remove();
                    }
                });
            }

            function next_list(){
                var last_post_id = $('#last_post_id').val();
                $.post("/list.api.php", {'last_post_id' : last_post_id})
                .done(function(result){                    
                    if (result['result'] == false){
                        alert('글을 불러오는 데 실패했습니다.');
                        return;
                    }

                    if (result['post_data'].length == 0){
                        alert("더이상 글이 없습니다.");
                        return;
                    }

                    var ul_list_data = $('#ul_list_data');                    
                    for (var i=0;i<result['post_data'].length;i++) {
                        var post = result['post_data'][i];            
                        var append_li = '<li id="post_' + post['post_id'] + '">"';
                        append_li += post['post_content'];
                        append_li += '<input type="button" value="삭제" onclick="post_delete(\'' + post['post_id'] + '\');return false;" />';
                        append_li += "</li>";
                        ul_list_data.append(append_li);
                        $('#last_post_id').val(post['post_id']);
                    }
                });
            }
        </script>
    </head>
    <body>
        <?php require_once("inc/header.php"); ?>
        <h1>php-memo 목록</h1>
        <form method="POST" action="write.post.php">
            <p>
                <input type="text" id="post_content" name="post_content" style="width:100%" />
            </p>
            <p>
                <input type="submit" id="post_write" value="글 저장" />
            </p>
        </form>
        <ul id='ul_list_data'>
            <?php
            foreach($post_data as $post){                
            ?>
            <li id="post_<?= $post['post_id'] ?>">
                <?= $post['post_content'] ?>
                <input type="button" value="삭제" onclick="post_delete('<?= $post['post_id'] ?>');return false;" />
            </li>
            <?php
            }
            ?>
        </ul>
        <a href="#" id='more' onclick="next_list();">더보기</a>
        <input type='hidden' id='last_post_id' value="<?php echo $last_post_id ?>" />
    </body>
</html>

위 코드를 list.php 파일로 저장한다.


목록 페이지는 본인의 것만 볼 수 있으므로 로그인되어 있는지 확인한다.

// 로그인 체크
session_start();
if (isset($_SESSION['member_id']) === false){
    header("Location: /");
    exit();
}

 


세션에서 현재 로그인된 사용자의 PK를 가지고 온다.

$member_id = $_SESSION['member_id'];

글 쓰기 폼을 만든다. 이 폼은 write.post.php 페이지를 HTML Form을 이용한 POST 방식으로 호출한다.

<form method="POST" action="write.post.php">
    <p>
        <input type="text" id="post_content" name="post_content" style="width:100%" />
    </p>
    <p>
        <input type="submit" id="post_write" value="글 저장" />
    </p>
</form>

처음 페이지가 보여질 때 최신 메모 목록을 보여줘야 한다. 이를 위해 현재 로그인한 사용자의 최근 글 10개를 데이터베이스에서 가지고 온다.

$post_query = "select post_id, post_content from tbl_post where member_id = ? order by insert_date desc limit 10";
$post_data = db_select($post_query, array($member_id));

최신 메모 목록을 화면에 보여준다.

<ul id='ul_list_data'>
    <?php
    foreach($post_data as $post){                
    ?>
    <li id="post_<?= $post['post_id'] ?>">
        <?= $post['post_content'] ?>
        <input type="button" value="삭제" onclick="post_delete('<?= $post['post_id'] ?>');return false;" />
    </li>
    <?php
    }
    ?>
</ul>

메모 목록을 foreach 구문으로 하나씩 반복한다.

foreach($post_data as $post)

HTML에서 id는 항목을 구별하는 식별자다. 각 메모마다 post_ 문자열 + tbl_post.post_id 값을 붙여 유일한 HTML 식별자를 만들어낸다. 이 식별자는 개별 글 삭제 기능 구현에 쓰인다.

<li id="post_<?= $post['post_id'] ?>">

이 코드가 html에서 보일 때는 이렇게 보여진다.

<li id="post_6">

<?=  <?php echo 와 같은 뜻이다. 곧바로 다음에 나오는 내용을 출력한다.

<?= $post['post_content'] ?>

위 코드는 데이터베이스에 저장된 메모 내용을 출력한다.


개별 글 삭제 기능 호출하기
개별 글 삭제는 HTML Form 방식이 아니라 Ajax를 이용해 비동기로 처리한다. 따라서 화면 깜박임 없이 기능 처리가 가능하다.

Ajax 기능을 편하게 이용하기 위해 jQuery라는 자바스크립트 라이브러리를 사용할 것이다.
jQueryCDN https://code.jquery.com/ 에서 jQuery를 불러온다. 참고로 CDN은 Content Delivery Network의 약자로 정적인 컨텐츠를 빠르게 불러오기 위해 모아놓은 웹 저장소라고 이해하면 편하다.

<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>

자바스크립트 영역을 시작한다. 자바스크립트는 클라이언트, 즉 웹 브라우저에서 실행되는 프로그래밍 언어다.

<script type="text/javascript">

비동기로 글을 삭제하는 글 삭제 API를 호출하는 함수를 만든다. 글 삭제 API 의 주소는 /delete.api.php다.

function post_delete(post_id){                
    $.post("/delete.api.php", {'post_id' : post_id})
    .done(function(result){
        if (result['result']){
            alert('삭제되었습니다.');
            $('#post_' + post_id).remove();
        }
    });
}

($.post) 코드로 POST 메소드를 이용해서 /delete.api.php 페이지를 호출한다. 이 때 파라미터 이름과 값은 {'post_id' : post_id} 이다.

$.post("/delete.api.php", {'post_id' : post_id})

정상적으로 서버가 값을 리턴하면 리턴한 결과가 result 변수에 담긴다.

.done(function(result){

result.result == true 이면 삭제되었다는 알림을 보낸다.

if (result['result']){
    alert('삭제되었습니다.');

html에서도 글이 삭제되었다는 것을 표시해야 하므로 HTML ID로 글 항목을 찾아 삭제한다.

$('#post_' + post_id).remove();

자바스크립트 영역을 닫을 때는 </script> 로 표기한다.

</script>

글 삭제 함수를 호출하는 HTML 버튼을 그린다.

<input type="button" value="삭제" onclick="post_delete('<?= $post['post_id'] ?>');return false;" />

위 코드가 HTML로 표현되면 아래와 같다.

<input type="button" value="삭제" onclick="post_delete('6');return false;" />

더보기 기능 넣기
더보기 버튼을 클릭하면 현재 html에 렌더링된 항목보다 오래된 글을 서버에서 비동기로 가지고 온다.
이 기능을 구현하기 위해서는 현재 HTML에 렌더링된 마지막 메모가 무엇인지 클라이언트가 알고 있어야 한다.


페이지가 처음 렌더링될 때 마지막 메모 PK를 가지고 온다.

$last_post_id = count($post_data) > 0 ? $post_data[count($post_data) - 1]['post_id'] : "0";

마지막 메모 ID는 글이 0개 초과일 경우 배열의 마지막 항목($post_data[count($post_data) - 1]) 의 post_id 이며, 글이 0개일 때는 0이다. tbl_post.post_id 는 UNSIGNED BIGINT 타입이므로 1보다 작은 수는 없기 때문에 가장 작은 값으로 설정하는 것이다.

마지막 메모 ID는 보이지 않는 숨김 태그에 넣어둔다.

<input type='hidden' id='last_post_id' value="<?php echo $last_post_id ?>" />

더보기 버튼을 클릭했을 경우 글 목록 API를 호출하는 함수를 만든다. 글 목록 API 주소는 list.api.php 이며 파라미터는 last_post_id다.

function next_list(){
    var last_post_id = $('#last_post_id').val();
    $.post("/list.api.php", {'last_post_id' : last_post_id})
    .done(function(result){                    
        if (result['result'] == false){
            alert('글을 불러오는 데 실패했습니다.');
            return;
        }

        if (result['post_data'].length == 0){
            alert("더이상 글이 없습니다.");
            return;
        }

        var ul_list_data = $('#ul_list_data');                    
        for (var i=0;i<result['post_data'].length;i++) {
            var post = result['post_data'][i];            
            var append_li = '<li id="post_' + post['post_id'] + '">"';
            append_li += post['post_content'];
            append_li += '<input type="button" value="삭제" onclick="post_delete(\'' + post['post_id'] + '\');return false;" />';
            append_li += "</li>";
            ul_list_data.append(append_li);
            $('#last_post_id').val(post['post_id']);
        }
    });
}

숨김 태그에 설정된 마지막 메모 ID를 읽어들인다.

var last_post_id = $('#last_post_id').val();

더보기 데이터를 서버에 비동기로 요청한다.

$.post("/list.api.php", {'last_post_id' : last_post_id})

더이상 불러올 데이터가 없을 경우 알림창을 보여준다.

if (result['post_data'].length == 0){
    alert("더이상 글이 없습니다.");
    return;
}

서버에서 반환한 JSON 데이터로 목록에 HTML을 추가한다.

var ul_list_data = $('#ul_list_data');                    
for (var i=0;i<result['post_data'].length;i++) {
    var post = result['post_data'][i];            
    var append_li = '<li id="post_' + post['post_id'] + '">"';
    append_li += post['post_content'];
    append_li += '<input type="button" value="삭제" onclick="post_delete(\'' + post['post_id'] + '\');return false;" />';
    append_li += "</li>";
    ul_list_data.append(append_li);
    $('#last_post_id').val(post['post_id']);
}

참고로 위 자바스크립트 코드는 아래의 PHP 코드와 동일한 HTML을 그린다.

<?php
foreach($post_data as $post){                
?>
<li id="post_<?= $post['post_id'] ?>">
    <?= $post['post_content'] ?>
    <input type="button" value="삭제" onclick="post_delete('<?= $post['post_id'] ?>');return false;" />
</li>
<?php
}
?>