이전 포스트에서는 web.php 라우팅 설정과 함께 글을 작성하는 페이지를 만들어 보았다.
이제는 사용자가 작성한 글을 실제로 데이터베이스에 저장해 볼 차례다.
라라벨 13의 최신 문법을 활용해 Post 모델에 Fillable 속성을 선언하고, 회원과 글 사이의 일대다(HasMany) 관계 정의를 거쳐 실제 저장(Store) 로직까지 완성해 보겠다.
이전 포스트
라라벨 web.php 라우팅 설정 및 CSRF 토큰을 활용한 글 작성 페이지 만들기
회원과 글의 관계 정의
app/Models/User.php에 추가할 코드
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
class 내부의 제일 아래쪽에 이 코드를 추가하자.
public function posts(): HasMany: User 모델에서posts()라는 이름으로 관계 메서드를 정의하며, 이 메서드는 라라벨의 일대다(HasMany) 관계 객체를 반환한다는 뜻이다.return $this->hasMany(Post::class);: '한 명의 회원(User)은 여러 개의 글(Post)을 가질 수 있다'라는 일대다(1:N) 관계를 선언하는 것이다. 이 코드가 있으면 컨트롤러에서$request->user()->posts()와 같은 문법으로 로그인한 유저의 글에 접근할 수 있다.
app/Models/User.php에 추가할 코드
use Illuminate\Database\Eloquent\Relations\HasMany;
마지막으로 상단에 이 코드도 추가해야 한다.
이전 포스트에서 이야기했던 것처럼 PHP Namespace Resolver라는 익스텐션을 VSCode에 설치했다면, public function posts(): HasMany에서 HasMany 부분에 마우스 오른쪽 클릭을 한 후 'Import Class'를 선택하면 자동으로 임포트Import 하는 코드가 생성된다.
Post 모델에 Fillable 정의
app/Models/Post.php에 추가할 코드
#[Fillable(['message'])]
class 위쪽에 이 코드를 넣도록 하자.
데이터베이스의 posts 테이블 컬럼 중에서, 사용자가 입력한 값을 대량 할당Mass Assignment 방식으로 한 번에 안전하게 저장할 수 있도록 허용(화이트리스트)하는 설정이다.
다르게 말하면, 모델의 대량 할당를 허용할 컬럼들을 정의하는 데 사용하는 코드다.
Mass Assignment는 여러 컬럼에 대한 값을 한 번에 모델에 할당하는 기능을 의미한다.
만약 이 설정을 하지 않으면 기본적으로 모든 속성이 대량 할당에 참여할 수 있기 때문에 보안상 좋지 않다.
그러나 #[Fillable([ ... ])]을 사용하여 어떤 컬럼들만이 대량 할당에 참여할 수 있는지 명시적으로 지정할 수 있다.
쉽게 설명하자면, 해커가 악의적으로 다른 컬럼을 조작해 데이터를 집어넣는 공격을 방어하기 위해, 오직 message 컬럼만 한 번에 저장될 수 있도록 락을 걸어둔 것이다.
app/Models/Post.php에 추가할 코드
use Illuminate\Database\Eloquent\Attributes\Fillable;
이것도 역시 Import 해야 한다.
방법은 위에서 설명했었으니 생략한다.
참고로 원래 Fillable을 정의하는 코드는 이전에는 다른 방식으로 작성했었는데, 올해의 최신 버전인 Laravel 13부터 이렇게 바뀌게 되었다.
이전 버전에서는 어떤 방식으로 작성했었는지는 그냥 넘어가도록 하겠다.
PostController의 store 메서드
PostController.php
public function store(Request $request)
{
$validated = $request->validate([
'message' => 'required|string|max:300',
]);
$request->user()->posts()->create($validated);
return redirect(route('posts.index'));
}
비어있던 store 메서드에 이렇게 코드를 추가한다.
이 저장 로직을 아래에서 나눠서 설명하겠다.
$validated = $request->validate([
'message' => 'required|string|max:300',
]);
- 유효성 검사Validation를 수행한다. 사용자가 보낸 데이터 중
message라는 값이 필수 입력(required)이며, 문자열(string)이어야 하고, 최대 300자(max:300) 이하여야 한다는 규칙을 적용했다. - 만약 이 조건에 맞지 않으면 더 이상 아래 코드로 내려가지 않고, 이전 포스트에서 말한 것처럼 에러 메시지(
$errors)를 들고 글쓰기 폼 화면으로 다시 되돌아간다.
$request->user()->posts()->create($validated);
$request->user(): 현재 이 글쓰기 요청을 보낸 '로그인한 사용자 정보'를 가져온다.->posts(): 아까 User.php 모델에 정의해 둔 일대다 관계를 호출한다. 라라벨은 이때 자동으로 이 유저의 고유 ID 값을 찾아내어 외래 키 파트너로 준비시킨다.->create($validated);: 유효성 검사를 마친 안전한 데이터($validated)를 활용해 posts 테이블에 데이터를 인서트Insert한다. 이때, user_id 컬럼에 현재 로그인한 유저의 ID가 자동으로 매핑되어 저장된다. 라라벨의 강점이 발휘되는 구간이다.
return redirect(route('posts.index'));
데이터 저장이 끝나면 마지막으로 브라우저에게 "이제 글 작성이 완료되었으니 posts.index 이름으로 정의된 라우트 주소(즉, /posts 글 목록 화면)로 이동Redirect해." 하고 명령을 내려 화면을 전환한다.
여기까지 코드를 수정하고 나면 이제 글을 저장할 수 있게 된다.
하지만 저장한 글을 표시하는 로직은 아직 구현하지 않은 상태라서 저장 후에도 화면에는 아무런 변화가 없다.
하지만 DB에는 이렇게 저장한 글이 제대로 남아있는 것을 확인할 수 있다.
VSCode를 DB 툴처럼! SQLTools 익스텐션 설치 및 도커 연결 가이드
캡처한 이미지 속의 익스텐션은 여기서 확인할 수 있다.
이렇게 유효성 검사를 통해 악성 데이터의 유입을 필터링하고, 최신 #[Fillable] 속성으로 대량 할당 공격까지 막아낸 안전한 글 저장 기능이 완성되었다.
아직 브라우저 화면에서는 리다이렉트된 후 아직 아무런 변화가 보이지 않지만, 데이터베이스 내부에는 사용자가 쓴 글들이 유저 ID와 매핑되어 저장되고 있는 것을 볼 수 있었다.
백엔드에서 데이터를 안전하게 받고 저장하는 과정을 마쳤으니, 다음 포스트에서는 이렇게 DB에 저장된 글들을 불러와 화면에 표시하는 글 목록 출력 기능을 구현해 보겠다.
0 Comments
댓글 쓰기
🔸 댓글은 블로그 운영자의 승인 후에 블로그에 표시됩니다.
🔸 비로그인 방문자 분께서는 '익명'보다 이름/URL로 댓글을 남겨주시면 감사하겠습니다. (URL은 생략 가능합니다.)
🔸 구글 로그인 방문자는 '알림 사용'에 체크를 하시면, 남겨주신 댓글에 대한 답글 알림을 메일로 받아볼 수 있습니다. 📩