PHP/Modern PHP

[PHP] 게시판 만들기 with MVC - 3부 View(List & Create)

DSeung 2023. 12. 27. 01:04

 

 

이전글 : [PHP] 게시판 만들기 with MVC - 1부 Migration

이전글 : [PHP] 게시판 만들기 with MVC - 2부 Routing

 

List

이전 포스팅에서 더미로 "index"만 넣었던 index.php 수정합시다.

Model/Post가 없으므로 에러가 발생할 겁니다.

bbs/view/index.php

<?php
use Model\Post;

$post = new Post();
?>
<!doctype html>
<?php
include "part/header.php";
?>
<body>
<div class="m-4">
    <h3><a href="/bbs">자유게시판</a></h3>

    <div id="write_btn" class="mb-4">
        <p class="d-inline">자유롭게 글을 쓸 수 있는 게시판입니다.</p>
        <a href="./create">
            <button class="btn btn-primary float-right">글쓰기</button>
        </a>
    </div>

    <!--검색-->
    <div class="container mt-4 mb-3">
        <form action="" method="get">
            <div class="row">
                <div class="col-md-6 offset-md-3">
                    <div class="form-inline full-width-form">
                        <div class="form-group mb-2 flex-fill">
                            <label for="searchInput" class="sr-only">검색</label>
                            <input name="search" type="text" class="form-control w-100" id="searchInput"
                                   placeholder="Search"
                                   value="<?= $_GET['search'] ?? '' ?>">
                        </div>
                        <button id="searchSubmit" type="submit" class="btn btn-primary mb-2">검색</button>
                    </div>
                </div>
            </div>
        </form>
    </div>

    <!-- 게시물 목록 테이블 -->
    <table class="table table-bordered">
        <thead>
        <tr class="text-center">
            <th width="80">번호</th>
            <th width="300">제목</th>
            <th width="100">글쓴이</th>
            <th width="80">추천수</th>
            <th width="80">조회수</th>
            <th width="100">작성일</th>
        </tr>
        </thead>
        <tbody>
        <?php
        $startPage = 0;
        $perPage = 10;
        $searchWord = $_GET['search'] ?? '';

        // 게시글 목록 가져오기
        $posts = $post->getPosts($searchWord, $startPage, $perPage);

        if ($posts) {
            $bonusIdx = 0;
            foreach ($posts as $postInfo) {
                /// 30 글자 초과시 ... 저리
                $title = $postInfo["title"];
                if (strlen($title) > 30) {
                    // mb_substr: 한글이 깨지지 않도록 해줌
                    $title = str_replace($postInfo["title"], mb_substr($postInfo["title"], 0, 30, "utf-8") . "...", $postInfo["title"]);
                }
                ?>

                <tr>
                    <td><?= $postInfo['idx']?></td>
                    <td>
                        <a href="./read?idx=<?= $postInfo['idx'] ?>">
                            <?= $title . " [" . $postInfo['reply_count'] . "]"; ?>
                            <?php if ($postInfo['is_new']) { ?>
                                <span class="badge badge-primary">new</span>
                            <?php } ?>
                        </a>
                    </td>
                    <td><?= $postInfo['name'] ?></td>
                    <td><?= $postInfo['thumbs_up'] ?></td>
                    <td><?= $postInfo['views'] ?></td>
                    <td><?= $postInfo['created_at'] ?></td>
                </tr>
                <?php
            }
        } else {
            echo "<tr><td colspan='6' class='text-center'>게시글이 없습니다.</td></tr>";
        }
        ?>
        </tbody>
    </table>
</div>
</body>
</html>

 

Model

이제 데이터베이스와 연결된 기능을 담을 Model에 해당하는 Post를 만들도록 합시다.

이 Model로 Contorller에서 DB 작업을 하거나 View에서 바로 Model를 통해 데이터를 가져와 뿌릴 수 있습니다.

 

모든 Model이 상속할 BaseModel을 만듭시다.

bbs/Model/BaseModel.php

<?php
namespace Model;

use DB\Connection;

class BaseModel
{
    protected $conn;

    public function __construct()
    {
        $this->conn = new connection();
        $this->conn = $this->conn->getConnection();
    }
}

 

이제 Post Table과 매핑될 Post Model을 만들어 줍시다.

bbs/Model/Post.php

<?php

namespace Model;

use PDO;
use PDOException;

class Post extends BaseModel
{
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Post 목록을 가져옵니다.
     * @param $search string 검색어
     * @param $start int 시작할 데이터의 인덱스
     * @param $perPage int 페이지마다 보여줄 데이터 수
     * @return array|false
     */
    public function getPosts(string $search, int $start, int $perPage)
    {
        try {
            $query = "select p.*,
        (SELECT COUNT(*) FROM replies r WHERE r.post_idx = p.idx) AS reply_count,
        CASE WHEN TIMESTAMPDIFF(MINUTE, p.created_at, NOW()) <= 1440 THEN 1
        ELSE 0 END AS is_new
        from posts p
        where p.title like :search
        order by idx desc limit :start, :perPage";
            $stmt = $this->conn->prepare($query);
            $stmt->bindValue('search', '%' . ($search ?? '') . '%');
            $stmt->bindParam('start', $start, PDO::PARAM_INT);
            $stmt->bindParam('perPage', $perPage, PDO::PARAM_INT);
            $stmt->execute();
            return $stmt->fetchAll();
        } catch (PDOException  $e) {
            error_log($e->getMessage());
            return [];
        }
    }
}

 

Model을 정상적으로 추가했다면 아래와 같이 페이지가 나오게 됩니다.

 

Create

이제 글 쓰기 페이지를 추가합시다.

bbs/view/create.php

<!doctype html>
<?php
include "part/header.php";
?>
<body>
<div class="m-4">
    <div class="container mt-5">
        <h3 class="d-inline"><a href="/bbs">자유게시판</a></h3>/<h4 class="d-inline">글 작성</h4>
        <p class="mt-1">글을 작성하는 공간입니다.</p>

        <form action="/bbs/post/create" method="post">
            <div class="form-group">
                <label for="title">제목</label>
                <input type="text" class="form-control" name="title" placeholder="제목을 입력하세요">
            </div>

            <div class="form-row">
                <div class="form-group col-md-6">
                    <label for="name">Name</label>
                    <input type="text" class="form-control" name="name" placeholder="Name을 입력해주세요.">
                </div>
                <div class="form-group col-md-6">
                    <label for="password">Password</label>
                    <input type="password" class="form-control" name="pw" placeholder="Password를 입력해주세요.">
                </div>
            </div>

            <div class="form-group">
                <label for="content">내용</label>
                <textarea class="form-control" name="content" rows="5" placeholder="내용을 입력하세요"></textarea>
            </div>

            <button type="submit" class="btn btn-primary">글쓰기</button>
        </form>
    </div>

</div>
</body>
</html>

 

페이지를 추가했으니 Route에서 연결해 줍시다.

조건문을 하나 추가합니다.

bbs/Route/PostRoute.php

<?php

namespace Route;

class PostRoute extends BaseRoute
{
    function routing($url): bool
    {
        // 게시글 목록에 대한 라우팅
        if ($this->routeCheck($url, "post/list", "GET")) {
            return $this->requireView('index');
        } else if ($this->routeCheck($url, "post/create", "GET")) {
            return $this->requireView('create');
        }else {
            return false;
        }
    }
}

 

이제 List 페이지에서 글쓰기를 누르면 다음과 같이 글쓰기 페이지가 나옵니다.

반응형