이전 포스트에서 대량의 게시글을 불러올 때 발생하는 N+1 문제를 즉시 로딩Eager Loading 기법으로 해결하면서 글 목록을 표시해 보았다.
하지만 아무리 Eager Loading으로 쿼리를 최적화했더라도 데이터베이스에 수천, 수만 개의 글이 쌓인 상태에서 모든 데이터를 한 번에 가져오는 get() 메서드를 고수한다면 결국 서버 메모리가 버티지 못하고 터지게 될 거다.
오늘은 데이터베이스에 부하를 주지 않도록 데이터를 딱 원하는 개수만큼 쪼개어 가져오는 페이지네이션Pagination 기능을 구현하고, 어색한 기본 번역 UI를 한국 정서에 맞게 깔끔한 디자인으로 커스텀하는 방법까지 알아보겠다.
이전 포스트
라라벨 N+1 문제 해결, Eager Loading으로 데이터베이스 글 목록 출력하기
글 목록 페이징 하기 (페이지네이션 기능 구현)
이전 포스트에서 컨트롤러의 index 메서드에서 글을 가져올 때 get()이라는 코드를 사용했다.
하지만 이건 이전에 미리 언급했듯이 모든 데이터를 한꺼번에 가져오기 때문에 나중에 데이터가 많아질 때 문제가 생긴다.
그래서 예고한 대로 페이지네이션 기능을 써보도록 하겠다.
PostController.php의 수정 후 코드
public function index()
{
return view('posts.index', [
'posts' => Post::with('user')->latest()->paginate(3),
]);
}
코드의 마지막에 get()이 있던 부분을 paginate(3)으로 수정했다.
기존의 get() 메서드는 조건에 맞는 모든 레코드를 가져와 컬렉션Collection 객체로 반환했던 반면, paginate(3) 메서드는 데이터베이스에 자동으로 LIMIT 3 OFFSET 0 형태의 SQL 구문을 날려 정확히 3개의 데이터만 끊어서 가져온다.
즉, 이 괄호 안의 숫자로 한 페이지당 몇 개의 글을 표시할 것인지 설정할 수 있다.
그리고 반환하는 객체의 타입이 일반 컬렉션에서 LengthAwarePaginator(길이 인식 페이지네이션) 인스턴스로 변경된다.
이 인스턴스 내부에는 현재 페이지 번호, 전체 페이지 수, 총 게시글 수 등의 메타데이터가 자동으로 계산되어 담기게 된다.
resources/views/posts/index.blade.php에 추가할 코드
<div class="container p-6">
{{$posts->links()}}
</div>
@endforeach의 바로 아래쪽에 이 코드를 추가하자.
컨트롤러로부터 전달받은 페이지네이션 인스턴스($posts)의 links() 메서드를 호출하여 페이지 이동용 HTML 마크업(버튼 내비게이션)을 화면에 자동 렌더링하는 코드다.
라라벨을 사용하지 않는다면 개발자가 '이전', '다음', '번호 링크'를 위한 코드를 직접 만들어야 하는데, 라라벨이 현재 페이지 상태를 추적하여 동적인 내비게이션 바를 생성해 준다.
직접 구현하려면 꽤 복잡한 페이지네이션 기능이 이렇게 간단하게 구현이 되었다.
라라벨 만세!!
그런데 거슬리는 부분이 있다.
한국어로 굉장히 어색하게 쓰여있는 '보기 1에 3의 4 결과'라는 텍스트다.
사용자 정의 페이지네이션 뷰 파일 생성
make bash #컨테이너 안으로 들어간다.
php artisan vendor:publish --tag=laravel-pagination
VSCode의 터미널에서 이 명령어들을 실행한다.
이 명령어는 라라벨 프레임워크 내부(vendor 폴더)에 숨겨져 있는 페이지네이션 HTML 템플릿(뷰) 파일들을 사용자가 직접 커스텀할 수 있도록 resources/views/vendor/pagination 디렉토리로 꺼내오는 명령어다.
라라벨 성능 최적화를 위한 Laravel Debugbar 설치 및 다크모드 설정하기
이전에도 비슷한 명령어를 사용한 적이 있다.
그러면 resources/views/vendor/pagination 폴더가 생기고, 그 안에 이렇게 9개의 파일들이 생성된다. (버전에 따라 달라질 수도 있다.)
9개나 되는 너무 많은 파일들이 생성되어 당황스럽다.
하지만 resources/views/vendor/pagination 폴더에서 내가 사용하지 않는 뷰 파일들은 그냥 삭제하면 된다.
위에 링크한 포스트에서도 설명했었지만, 실제 파일은 최상위에 있는 vendor 폴더 안 깊숙한 곳에 숨겨져 있다.
resources 하위에 복사해 온 9개의 파일 중 내가 쓰지 않을 파일들을 지우더라도, 라라벨은 커스텀 파일이 없으면 원래 시스템(vendor)에 있던 기본 파일을 사용한다.
참고로 나중에 다룰 예정인 LIVEWIRE를 사용할 경우에는 사용자 정의 페이지네이션 뷰 파일을 생성하는 명령어가 지금과 다르다.
그건 그때 다시 설명하는 걸로!
페이지네이션 뷰 파일 수정
tailwind.blade.php의 수정 전 코드
<p class="text-sm text-gray-700 leading-5 dark:text-gray-600">
{!! __('Showing') !!}
@if ($paginator->firstItem())
<span class="font-medium">{{ $paginator->firstItem() }}</span>
{!! __('to') !!}
<span class="font-medium">{{ $paginator->lastItem() }}</span>
@else
{{ $paginator->count() }}
@endif
{!! __('of') !!}
<span class="font-medium">{{ $paginator->total() }}</span>
{!! __('results') !!}
</p>
이 문제를 해결하는데 필요한 파일은 tailwind.blade.php 뿐이다.
'Showing'이 '보기'로 번역되고, 'to'는 '에', 'of'는 '의', 'results'는 '결과'로 번역이 됐다.
그래서 '보기 1에 3의 4 결과'라는 이상한 텍스트가 출력되고 있었던 거다.
라라벨(Laravel) 초기 세팅: 타임존 설정 및 한글화
보통은 lang 폴더에서 텍스트를 수정하면 된다.
그런데 이건 한글과 영어의 문법이 달라서 여기서 수정할 수 있는 수준이 아니다.
tailwind.blade.php의 수정 후 코드
<p class="text-sm text-gray-700 leading-5 dark:text-gray-600">
총
<span class="font-medium">{{ $paginator->total() }}</span>
개의 글 중
@if ($paginator->firstItem())
<span class="font-medium">{{ $paginator->firstItem() }}</span>
~
<span class="font-medium">{{ $paginator->lastItem() }}</span>
@else
{{ $paginator->count() }}
@endif
개 표시 중
</p>
이렇게 수정하면 아래의 이미지처럼 바뀐다.
어색하지 않게 제대로 수정이 되기는 했지만, 사실 페이지네이션에 이런 거추장스러운 텍스트를 표시하는 웹사이트는 거의 본 적이 없다.
그냥 주석 처리해서 없애버리는 편이 낫다.
역시 차라리 이쪽이 더 깔끔하고 좋다.
그런데 페이지네이션 버튼이 왼쪽으로 정렬되었다.
이전처럼 오른쪽으로 정렬하고 싶다면 이렇게 수정하자.
tailwind.blade.php의 수정 전 코드
<div class="hidden sm:flex-1 sm:flex sm:gap-2 sm:items-center sm:justify-between">
이 부분을
tailwind.blade.php의 수정 후 코드
<div class="hidden sm:flex sm:items-center sm:justify-end">
이렇게 수정하면 된다.
완성이다!
버튼도 원래의 위치에 있으면서 텍스트만 사라졌다.
라라벨이 기본으로 제공하는 페이지네이션 기능은 정말 유용하지만, 영미권 기준의 문장 구조로 설계되어 있어서 한글화 시 문장이 어색해 보이는 단점이 있었다.
하지만 이렇게 vendor:publish 명령어를 통해 감춰져 있던 뷰 파일을 밖으로 꺼내오면, 원하는 대로 디자인이나 정렬을 바꾸고 거추장스러운 요소를 숨기는 등의 커스터마이징이 가능해진다. 😎
Database: Pagination | Laravel 13.x - The clean stack for Artisans and agents
이번 포스트에서 다룬 기본 기능 외에, 라라벨이 제공하는 다양한 페이지네이션 API는 이 공식 문서를 통해 확인할 수 있다.
예를 들면 번호 없이 '이전'과 '다음' 버튼만 생성하는 경량형 페이지네이션인 simplePaginate() 메서드라던지, 그 외에도 여러 가지 기능들이 있다.




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