CodeIgniter 4로 블로그 만들기 #06 — 시더로 더미 데이터 생성
지난 회차에서 posts 테이블을 만들었습니다. 하지만 테이블은 비어 있죠. 목록 화면과 상세 화면을 만들려면 보여 줄 데이터가 필요합니다. 매번 손으로 글을 하나하나 입력하는 건 번거롭고, 화면을 새로 갈아엎을 때마다 데이터가 날아가면 곤란합니다.
이번 회차의 목표는 시더(Seeder)로 현실적인 더미 글을 한 번에 채우는 것입니다.
시더란
시더는 개발·테스트 단계에서 미리 정해 둔 데이터를 DB에 밀어 넣는 스크립트입니다. php spark db:seed 한 줄이면 그럴듯한 더미 글이 채워지고, 언제든 같은 상태를 재현할 수 있습니다. 특히 뒤에서 만들 Feature 테스트는 매번 마이그레이션 후 시더를 돌려 깨끗한 데이터로 검증하는데, 그때 이 시더가 그대로 쓰입니다.
한 가지 짚어 둘 점은, 아직 PostModel이 없다는 것입니다. 모델은 다음 회차(ep07)에서 만듭니다. 그래서 이번에는 모델 대신 쿼리 빌더로 직접 insert합니다. 커리큘럼의 회차 순서를 지키기 위해 미래 회차의 코드를 미리 끌어오지 않는 원칙입니다.
이번 회차 목표
PostSeeder로 강좌 흐름을 담은 더미 글 6건을 넣는다.- 시더를 반복 실행해도 유니크 제약에 걸리지 않게 한다.
created_at을 하루씩 벌려 최신순 정렬을 확인할 수 있게 한다.DatabaseSeeder에서PostSeeder를 호출하도록 연결한다.
PostSeeder 작성
시더는 app/Database/Seeds/에 둡니다. PostSeeder.php를 만들고, run() 메서드 안에서 넣을 글들을 배열로 준비합니다.
<?php
namespace App\Database\Seeds;
use CodeIgniter\Database\Seeder;
class PostSeeder extends Seeder
{
public function run()
{
$posts = [
[
'title' => 'CodeIgniter 4로 블로그 만들기를 시작하며',
'slug' => 'codeigniter4-blog-start',
'body' => "이 블로그는 CodeIgniter 4를 한 회차씩 쌓아 올리며 만들어 갑니다.\n\n첫 글에서는 왜 프레임워크를 쓰는지, 그리고 앞으로 어떤 기능을 차례로 붙여 갈지 가볍게 정리해 둡니다. 라우팅과 뷰부터 시작해 모델·인증·댓글까지, 작은 단위로 커밋하며 나아갑니다.",
],
// ... 라우팅, 공통 레이아웃, 첫 테스트, 마이그레이션, 시더 주제의 글 5건 더
];
여기서 눈여겨볼 점은 더미 글이 아무 의미 없는 로렘 입숨이 아니라는 것입니다. 각 글은 이 강좌가 실제로 다루는 주제(라우팅, 공통 레이아웃, 테스트, 마이그레이션, 시더)를 담고 있습니다. 이렇게 하면 목록·상세 화면을 만들 때 실제 블로그처럼 자연스럽게 보입니다. body에는 \n\n으로 문단을 나눠 뒀는데, 이건 나중에 상세 화면(ep09)에서 nl2br로 줄바꿈을 살릴 때 요긴합니다.
반복 실행에도 안전하게
시더에서 흔히 겪는 문제가 있습니다. 두 번 실행하면 같은 slug를 또 넣으려다 유니크 제약(ep05에서 걸어 둔)에 걸려 에러가 나는 것이죠. 이걸 막기 위해, 이번에 넣을 slug들만 먼저 지우고 시작합니다.
// 시더를 반복 실행해도 슬러그 유니크 제약에 걸리지 않도록,
// 이번에 넣을 슬러그만 먼저 비운다(실제 글은 건드리지 않음).
$slugs = array_column($posts, 'slug');
$this->db->table('posts')->whereIn('slug', $slugs)->delete();
array_column으로 넣을 글들의 slug만 뽑아, whereIn으로 그 slug들만 지웁니다. 테이블 전체를 비우는 게 아니라는 점이 중요합니다. 나중에 실제로 쓴 글이 있어도 시더가 그걸 건드리지 않습니다.
최신순 정렬이 눈에 보이게
목록 화면은 최신 글이 위로 오도록 정렬할 예정입니다. 그런데 시더가 글 6건을 순식간에 넣으면 created_at이 전부 거의 같은 시각이 되어, 정렬이 제대로 됐는지 눈으로 확인하기 어렵습니다. 그래서 작성 시각을 하루씩 벌려 넣습니다.
foreach ($posts as $i => $post) {
// 최신 글이 위로 오도록 작성 시각을 하루씩 벌려 둔다
$createdAt = date('Y-m-d H:i:s', strtotime("-{$i} days"));
$this->db->table('posts')->insert([
'user_id' => null,
'title' => $post['title'],
'slug' => $post['slug'],
'body' => $post['body'],
'created_at' => $createdAt,
'updated_at' => $createdAt,
]);
}
배열 인덱스 $i를 이용해 첫 글은 오늘, 두 번째는 어제, 세 번째는 그저께… 이렇게 하루씩 과거로 밀어냅니다. 결과적으로 배열 맨 앞의 글이 가장 최신이 됩니다. 이 정렬 규칙은 뒤에서 페이지네이션 테스트(ep08)의 판정 기준으로도 그대로 쓰입니다("1페이지=최신 5건, 2페이지=가장 오래된 1건").
user_id는 아직 null입니다. 작성자 연결은 인증을 도입하는 이후의 일입니다.
DatabaseSeeder에 연결
php spark db:seed DatabaseSeeder로 한 번에 모든 시더를 돌리려면, 대표 시더인 DatabaseSeeder가 PostSeeder를 호출하게 해야 합니다. appstarter에는 이 파일이 기본 포함되어 있지 않으므로 새로 만듭니다.
<?php
namespace App\Database\Seeds;
use CodeIgniter\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run()
{
$this->call('PostSeeder');
}
}
$this->call('PostSeeder') 한 줄로 연결됩니다. 앞으로 시더가 더 생기면(예: 댓글 시더) 여기에 $this->call(...)을 추가하기만 하면 됩니다. DatabaseSeeder는 모든 시더를 한데 묶는 입구 역할을 합니다.
실행과 검증
php spark db:seed DatabaseSeeder
에러 없이 끝나면 성공입니다. 명령을 두 번, 세 번 반복해도 유니크 제약에 걸리지 않고 잘 돌아가는지 확인해 보세요. 앞에서 slug를 먼저 지우도록 해 뒀기 때문에 몇 번을 돌려도 항상 같은 6건으로 유지됩니다.
마무리 — 커밋과 태그
git add .
git commit -m "feat: 글 시더로 더미 데이터"
git tag ep06
다음 회차
이제 테이블과 데이터가 모두 준비됐습니다. 다음 글에서는 드디어 PostModel과 Post 엔티티를 만들고, 글 목록 화면을 그립니다. 모델이 DB를 읽어 엔티티로 감싸 주고, 컨트롤러가 그걸 뷰에 넘기는 CI4의 데이터 흐름을 처음으로 완성합니다. 첫 Feature 테스트도 함께 붙입니다.
이번 회차 요약
- 다루는 파일:
app/Database/Seeds/PostSeeder.php(생성),app/Database/Seeds/DatabaseSeeder.php(생성·연결)- 핵심: PostModel이 아직 없어 쿼리 빌더로 직접 insert. slug만 먼저 비워 반복 실행에 안전하게,
created_at을 하루씩 벌려 최신순 정렬을 확인 가능하게.DatabaseSeeder가 시더들의 입구.
댓글 0
아직 댓글이 없습니다.