코드이그나이터4 마크다운 블로그 리팩토링 - 7 - 글 목록 서비스 레이어 분리하기

고은연·2021년 11월 10일
0

글 목록 서비스 레이어 분리하기

이번 챕터의 코드는 https://github.com/koeunyeon/ci4/commits/refacto-post-list 에 있습니다.

모델 반환 타입 변경하기

이제 글 목록 서비스의 마지막 메소드이므로, 글 모델의 반환 타입을 변경해도 다른 사이드 이펙트가 생기지 않는다고 판단할 수 있습니다. 따라서 모델의 반환 타입을 변경합니다.
app/Models/PostsModel.php

protected $returnType = "App\Entities\PostEntity";

서비스의 조회 메소드 변경하기

서비스의 조회 메소드 find() 에서 asObject 메소드를 통해 캐스팅했었죠. 이렇게요.
app/Services/PostService.php

return $postModel->asObject("App\Entities\PostEntity")->find($post_id);

이제 모델이 직접 엔티티를 반환함으로 캐스팅할 필요가 없어졌으므로 아래처럼 바꾸겠습니다.

return $postModel->find($post_id);

서비스에 목록 메소드 추가하기

이제 글 목록을 반환하는 서비스를 만들어 보겠습니다. PostService에 아래 메소드를 추가합니다.

public function post_list($page)
{
    $model = new PostsModel();
    $post_query = $model->orderBy("created_at", "desc");
    $post_list = $model->paginate(10, "default", $page); // (1)
    $pager = $post_query->pager;

    return [$pager, $post_list];
}

(1) 기존 Post 컨트롤러의 index() 엔드포인트에서 페이징을 하는 코드는 아래와 같았습니다.

$model->paginate(10);

이는 paginate 메소드의 두번째 파라미터부터는 기본 인수가 지정되어 있었기 때문인데요. 세번째 파라미터 $page는 입력되지 않을 경우 쿼리 스트링 page 값을 읽어서 처리하는 방식으로 동작합니다. 물론 PHP의 특성상 쿼리 스트링을 읽는 슈퍼 글로벌 변수 $_GET은 어디서든 접근할 수 있지만, 서비스 레이어는 HTTP 레이어에 가능한 관여하지 않는 것이 원칙이므로 post_list 메소드의 파라미터로 입력받도록 처리합니다.

컨트롤러 메소드 변경하기

컨트롤러 메소드 index()를 아래와 같이 변경합니다.

public function index()
{
    $page = $this->request->getGet("page") ?? 1; // (1)
    list($pager, $post_list) = PostService::factory()->post_list($page);

    return view("post/index", [
        'post_list' => $post_list,
        'pager' => $pager,
        'isLogin' => LoginHelper::isLogin()
    ]);
}

(1) 코드이그나이터4 컨트롤러에서 쿼리 스트링을 읽는 방법은 $this->request->getGet 입니다. 뭔가 이상한 것 같기도 하고 나름 일리는 있는것도 같은 메소드명이네요. 서비스에 현재 페이지를 전달하기 위해 사용합니다.

뷰 수정하기

이제 마지막으로 해야 할 것은 뷰를 수정하는 겁니다. 배열 대신 엔티티를 사용할 수 있도록 수정합시다.
app/Views/post/index.php

<?= $this->extend('/post/layout') ?>
<?= $this->section('content') ?>
<?php
function show_content($content)
{
    $content = strip_tags($content); // (1)
    if (mb_strlen($content) > 100) { // (2)
        $content = mb_substr($content, 0, 100); // (3)
    }
    return $content;
}

foreach ($post_list as $post) {
    ?>
    <div class="item mb-5">
    <div class="media">
        <div class="media-body">
            <h3 class="title mb-1">
                <a href="<?= site_url("/post/show/{$post->post_id}") ?>"><?= $post->title ?></a>
            </h3>
            <div class="meta mb-1">
                <span class="date"><?= $post->created_at ?></span>
                <div class="intro"><?= show_content($post->html_content) ?></div>
                <a class="more-link" href="<?= site_url("/post/show/{$post->post_id}/#content") ?>">Read more &rarr;</a>
            </div>
        </div>
    </div>
    <?php
}
?>
<?php $pager->setPath("/post"); ?>
<?= $pager->links() ?>
<?php if ($isLogin) : ?>
    <p style="text-align: right;">
        <a href="/post/create" class="btn btn-primary">글쓰기</a>
    </p>
<?php endif ?>
<?= $this->endSection() ?>
profile
중년 아저씨. 10 + n년차 백엔드 개발자. 스타트업과 창업, 솔로프리너와 1인 기업에 관심 많아요.

0개의 댓글