이번 챕터의 코드는 https://github.com/koeunyeon/ci4/commits/refacto-post-edit-delete 에 있습니다.
글 수정은 글 생성 + 글 조회 기능이 합쳐져 있죠. 이미 엔티티의 역할은 정해져 있기 때문에 서비스와 뷰, 컨트롤러를 수정하겠습니다.
글 서비스에 아래의 메소드를 추가합니다.
app/Services/PostService.php
public function update($post, $new_post_data)
{
$post->fill($new_post_data); // (1)
$postModel = new PostsModel();
$isSuccess = $postModel->save($post); // (2)
return [$isSuccess, $postModel->errors()];
}
(1) 기존에 존재하는 PostEntity
타입 변수 $post
에 HTTP로 입력받은 배열 $new_post_data
를 채웁니다. 저장하기 전의 데이터는 $new_post_data
에 의해 대체됩니다.
(2) 모델을 통해 데이터를 저장합니다. $post
에는 이미 주 키에 해당하는 post_id
항목이 존재하므로 update
가 실행됩니다.
글 수정 컨트롤러의 edit
메소드를 아래처럼 변경합니다. 특별한 부분은 없으니 설명은 생략하겠습니다.
app/Controllers/Post.php
public function edit($post_id)
{
if (LoginHelper::isLogin() === false) {
return $this->response->redirect("/post");
}
$postService = PostService::factory();
$post = $postService->find($post_id);
if (!$post) {
return $this->response->redirect("/post");
}
if ($postService->isAuthor($post, LoginHelper::memberId()) === false){
return $this->response->redirect("/post");
}
if ($this->request->getMethod() === "get") {
return view("/post/create",[
'post_data' => $post
]);
}
list($isSuccess, $errors) = $postService->update($post, $this->request->getPost());
if ($isSuccess){
$this->response->redirect("/post/show/$post_id");
}else{
return view("/post/create",[
'post_data' => $post,
'errors' => $errors
]);
}
}
글 생성 뷰를 엔티티를 사용하도록 수정해 보겠습니다. 글 조회 뷰와 마찬가지로 배열[]
문법을 객체 ->
문법으로 변경합니다.
app/Views/post/create.php
<?= $this->extend('/post/layout') ?>
<?= $this->section('content') ?>
<h2 class="title mb-2">글쓰기</h2>
<form method="POST">
<div class="form-group"> <!-- (1) -->
<label for="title">제목을 알려주세요</label> <!-- (2) -->
<input type="text" class="form-control" id="title" name="title" value="<?= $post_data->title ?? "" ?>" placeholder="제목" required /> <!-- (3) -->
<small id="titlehelp" class="form-text text-muted">제목은 4-100글자 사이입니다.</small> <!-- (4) -->
</div>
<div class="form-group">
<label for="content">내용을 입력하세요</label>
<textarea name="content" class="form-control" id="content" rows="10" required><?= $post_data->content ?? "" ?></textarea> <!-- (5) -->
</div>
<p style="text-align: right;">
<input type="submit" class="btn btn-primary" value="저장">
<a href="/post/" class="btn btn-info">취소</a>
</p>
<?php
if (isset($errors)) {
echo "<ul>";
foreach ($errors as $val) {
echo "<li>$val</li>";
}
echo "</ul>";
}
?>
</form>
<?= $this->endSection() ?>
글 수정은 글 생성과 뷰를 공유하죠. 따라서 글 수정 엔드포인트가 엔티티를 사용해서 뷰에 데이터를 전달하면, 글 생성 엔드포인트도 엔티티를 사용하도록 변경해야 합니다.
다행히도 글 생성에는 엔티티를 사용하는 곳이 한 곳만 있네요. 바로 유효성 검사에 실패할 경우 사용자가 입력한 데이터를 다시 보여주는 부분입니다. Post
컨트롤러의 create
엔드포인트 일부를 수정하겠습니다. 기존 코드는 아래와 같습니다.
app/Controllers/Post.php
return view("/post/create", [
'post_data' => $this->request->getPost(),
'errors' => $errors
]);
배열을 PostEntity
타입으로 바꿉시다. 변경된 코드는 아래와 같습니다.
$postEntity = new PostEntity();
$postEntity->fill($this->request->getPost());
return view("/post/create", [
'post_data' => $postEntity,
'errors' => $errors
]);
이어서 글 삭제도 레이어를 분리해 보겠습니다. 삭제의 경우에는 특별히 post
객체를 뷰에 전달하거나 하는 일이 없기 때문에 모든 객체 관리를 서비스에 넣는 방법으로 해 볼께요.
글 삭제 기능을 작성합니다. 구체적으로 글을 찾고, 작성자인지 검사하고, 삭제하는 비즈니스의 흐름이 작성되어 있습니다.
app/Services/PostService.php
public function delete($post_id, $member_id)
{
$post = $this->find($post_id);
if (!$post) {
return false;
}
if ($this->isAuthor($post, $member_id) === false) { // (1)
return false;
}
$postModel = new PostsModel();
$postModel->delete($post->post_id);
return true;
}
(1) 작성자인지 확인하는 메소드는 내부의 is_author
메소드를 사용해서 검사합니다. 이렇게 메소드 하나를 만들어 놓으면 내부적으로 작성자인지 확인하는 구현 스펙이 변경되어도 한군데만 수정하면 되기 때문에 수정 공수가 적게 들어갑니다.
글 삭제 엔드포인트는 무척 간단해집니다.
app/Controllers/Post.php
public function delete()
{
if (LoginHelper::isLogin() === false) { // (1)
return $this->response->redirect("/post");
}
if ($this->request->getMethod() !== "post"){
return $this->response->redirect("/post");
}
$post_id = $this->request->getPost('post_id');
PostService::factory()->delete($post_id, LoginHelper::memberId());
return $this->response->redirect("/post");
}
로그인 여부 확인과 HTTP 메소드 체크 등 HTTP 레이어에서 처리해야 할 일을 제외하고 모든 비즈니스 로직은 단 한줄, PostService
를 통해 일어납니다.
PostService::factory()->delete($post_id, LoginHelper::memberId());