이전 포스트에서는 데이터베이스의 글을 효율적으로 나누어 보여주는 페이지네이션Pagination 기능을 구현하고, 스타일을 깔끔하게 커스텀하는 방법까지 알아보았다.
이전 포스트
Laravel 글 목록 페이지네이션 기능 구현 및 디자인 변경
오늘의 포스트는 새로운 것을 배우지 않고, 이전에 다른 포스트에서 다뤘던 내용을 다시 정리해 보겠다.
이전에 다른 포스트들에서 Post 모델과 User 모델 간의 릴레이션 설정을 했었는데, 이것에 대해서 더 자세히 설명해보려고 한다.
모델 간의 관계성(Relationship) 설정
Post 모델에 Fillable 정의 후 새 글 저장 기능 구현
라라벨 N+1 문제 해결, Eager Loading으로 데이터베이스 글 목록 출력하기
이전에 작성한 이 두 포스트에서 모델 간의 릴레이션 설정을 했었다.
app/Models/User.php에 추가한 코드
<?php
// 생략
use Illuminate\Database\Eloquent\Relations\HasMany;
// 생략
class User extends Authenticatable
{
// 생략
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}
코드에 대한 설명은 다음과 같다.
public function posts(): HasMany: User 모델에서posts()라는 이름으로 관계 메서드를 정의하며, 이 메서드는 라라벨의 일대다(HasMany) 관계 객체를 반환한다는 뜻이다.return $this->hasMany(Post::class);: '한 명의 회원(User)은 여러 개의 글(Post)을 가질 수 있다'라는 일대다(1:N) 관계를 선언하는 것이다. 이 코드가 있으면 컨트롤러에서$request->user()->posts()와 같은 문법으로 로그인한 유저의 글에 접근할 수 있다.use Illuminate\Database\Eloquent\Relations\HasMany;: 임포트Import 하는 코드를 잊으면 안 된다. 이 코드가 없다면 에러가 발생한다.
app/Models/Post.php에 추가한 코드
<?php
// 생략
use Illuminate\Database\Eloquent\Relations\BelongsTo;
// 생략
class Post extends Model
{
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
User 모델에서 Post 모델에 대한 릴레이션 설정을 했다면, Post 모델에서도 릴레이션 설정을 해서 양방향을 모두 설정해줘야 한다.
public function user(): BelongsTo: Post 모델에서user()라는 이름으로 관계 메서드를 정의하며, 이 메서드는 라라벨의 일대다 역관계(BelongsTo) 객체를 반환한다는 뜻이다.return $this->belongsTo(User::class);: '하나의 글(Post)은 특정 한 명의 회원(User)에게 속해 있다'라는 관계를 정의하는 것이다. 이 코드가 있어야만 화면단에서$post->user->name처럼 글을 통해 작성자의 이름에 접근할 수 있게 된다.use Illuminate\Database\Eloquent\Relations\BelongsTo;: 임포트Import는 항상 잊지 말자.
양쪽에 다 설정하는 것이 일반적인가?
위와 같이 두 모델에서 양방향을 모두 설정해 두는 것이 라라벨 실무 개발의 표준이자 정석이다.
기술적인 강제성은 없지만, 실무에서는 99% 양쪽 모두에 관계를 정의한다.
웹 애플리케이션을 만들다 보면 비즈니스 로직에 따라 데이터를 조회하는 출발점이 완전히 달라진다.
예를 들어,
- 출발점이 '글'일 때: "이 글을 쓴 회원의 프로필을 보여줘" → Post 모델에
belongsTo가 있어야 함 ($post->user) - 출발점이 '회원'일 때: "마이페이지에서 이 회원이 작성한 모든 글 목록을 보여줘" → User 모델에
hasMany가 있어야 함 ($user->posts)
만약 한쪽에만 설정을 해두면, 반대 방향으로 데이터를 조회해야 하는 컴포넌트를 개발할 때 라라벨의 편의 기능을 쓰지 못하고 과거 방식의 무거운 쿼리를 직접 짜야 하는 낭비가 발생한다.
세 모델의 릴레이션 설정
'User 모델'과 '글을 저장하는 Article 모델'과 '댓글을 저장하는 Comment 모델'이 있다고 가정하자.
이렇게 3개의 모델의 릴레이션 설정을 한다면 어떻게 하면 될까?
User 모델과 Article 모델의 릴레이션 설정 코드는 생략하겠다. (위에서 이미 했었으니까. Post 모델의 이름이 Article로 바뀌었을 뿐이다.)
여기서 Comment 모델이 추가된다면 각 모델에 코드를 어떻게 추가하면 되는지 살펴보자.
app/Models/User.php
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}
한 명의 회원은 여러 개의 댓글을 남길 수 있다는 관계 설정을 해두었다.
app/Models/Article.php
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}
하나의 Article에는 여러 개의 댓글이 달릴 수 있다는 설정을 해두었다.
app/Models/Comment.php
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function article(): BelongsTo
{
return $this->belongsTo(Article::class);
}
하나의 Comment에는 한 명의 작성자만 존재할 수 있고, 하나의 Article에만 달릴 수 있다는 설정을 해두었다.
여기서도 HasMany와 BelongsTo 라이브러리를 상단에 임포트하는 것을 잊지 말자.
이 임포트 코드에 대해서는 설명하지 않아도 당연히 해야 하는 것으로 여기고 앞으로는 되돌록 설명을 생략하려고 한다.
이런 식으로 모델의 관계를 유기적으로 연결해 두면,
- 특정 댓글 하나를 기준으로
$comment->article->title을 적어 댓글이 달린 원본 글의 제목을 바로 가져오거나, $comment->user->name을 통해 댓글 작성자의 이름을 단 한 줄로 출력
하는 등의 작업을 쉽게 할 수 있게 된다.
다음 포스트

0 Comments
댓글 쓰기
🔸 댓글은 블로그 운영자의 승인 후에 블로그에 표시됩니다.
🔸 비로그인 방문자 분께서는 '익명'보다 이름/URL로 댓글을 남겨주시면 감사하겠습니다. (URL은 생략 가능합니다.)
🔸 구글 로그인 방문자는 '알림 사용'에 체크를 하시면, 남겨주신 댓글에 대한 답글 알림을 메일로 받아볼 수 있습니다. 📩