이전 포스트에서는 마이그레이션 파일을 직접 수정해서 컬럼들을 추가하고, 실제 DB에 반영하는 과정을 알아보았다.
오늘은 라라벨의 리소스 라우팅을 설정하고, 보안을 위한 @csrf 토큰이 적용된 글 작성 페이지를 내비게이션 메뉴에 연결하는 것까지 구현해 보겠다.
이전 포스트
마이그레이션 파일에 컬럼을 추가하고 DB에 테이블 생성하기
routes/web.php에서 라우팅 설정하기
routes/web.php의 수정 전 코드
<?php
use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});
require __DIR__.'/auth.php';
routes/web.php의 수정 전 코드다.
여기에 아래의 코드들을 추가할 거다.
Route::resource('posts', PostController::class)
->only(['index', 'store'])
->middleware(['auth', 'verified']);
반드시 정해진 위치가 있는 건 아니지만, require __DIR__.'/auth.php'; 윗부분에 넣도록 하자.
Route::resource('posts', PostController::class): 원래 라라벨에서 리소스 라우트를 쓰면 CRUD에 필요한 7가지 주소를 자동으로 한 방에 다 만들어 준다.->only(['index', 'store']): 하지만 뒤에 이 코드를 붙여서 '지금은 7개 다 필요 없고, 글 목록 화면(index)과 글 저장하기 기능(store) 딱 2가지만 활성화하겠다'고 제한을 걸어둔 것이다.->middleware(['auth', 'verified']);: 보안 잠금장치다.auth는 반드시 로그인한 사용자만 이 주소에 접근할 수 있게 막는다. 그리고verified는 회원가입 후 이메일 인증까지 완벽하게 마친 사용자여야만 통과시켜 준다. 이 조건을 만족하지 못하면 로그인 페이지나 이메일 인증 안내 페이지로 자동 리다이렉트된다.
use App\Http\Controllers\PostController;
그리고 잊지 말고 이 코드도 반드시 추가해야 한다.
상단에 use로 시작하는 코드들이 모여있는 곳에 추가하도록 하자.
Route::resource('posts', PostController::class)라는 코드만 적어두면, php는 이 PostController가 내 컴퓨터 어디에 있는 파일인지 찾아내지 못하고 Class "PostController" not found 같은 에러를 발생시킨다.
하지만 상단에 이 한 줄의 코드를 적어줌으로써, 라라벨은 헷갈리지 않고 app/Http/Controllers/ 폴더로 들어가 해당 파일을 정확히 로드할 수 있게 된다.
이것을 흔히 "PostController를 임포트Import 한다"라고 말한다.
PHP Namespace Resolver라는 VSCode 익스텐션을 설치하자.
이걸 설치하면 앞으로는 임포트 시키는 코드를 직접 입력하지 않고, PostController라고 쓰여있는 곳에 마우스 오른쪽 클릭을 한 후 'Import Class'를 선택하면 자동으로 임포트 하는 코드가 생성된다.
PostController의 index 메서드
PostController.php
public function index()
{
return view('posts.index');
}
비어있던 index 메서드에 이렇게 코드를 추가한다.
사용자가 /posts 주소로 접근하면 라우터가 이 index 메서드를 호출한다.
현재 이 메서드는 다른 복잡한 로직 없이, resources/views/posts/index.blade.php 파일을 찾아서 브라우저에 화면을 반환(return view)하는 단순한 역할을 한다.
index.blade.php 파일 만들기
posts/index.blade.php
<x-app-layout>
<div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8">
<form method="POST" action="{{ route('posts.store') }}">
@csrf
<textarea
name="message"
placeholder="당신의 생각을 써보세요."
class="block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm"
></textarea>
<x-input-error :messages="$errors->get('message')" class="mt-2" />
<x-primary-button class="mt-4">
{{ __('Save') }}
</x-primary-button>
</form>
</div>
</x-app-layout>
resources/views 경로로 가서 수동으로 posts 폴더를 만들고, 그 안에 index.blade.php 파일을 만들자.
<x-app-layout>: 라라벨 블레이드 컴포넌트 문법이다. 로그인한 회원용 전체 레이아웃(layouts/app.blade.php) 뼈대를 그대로 가져와서 그 내부에 이 내용을 집어넣겠다는 뜻이다. 이렇게 하면 상단 메뉴바나 배경 등이 자동으로 유지되니 효율적이다.action="{{ route('posts.store') }}">: 이 폼에 글을 쓰고 버튼을 누르면, 라라벨이 자동으로 지정해 준 글 저장 주소(아까 web.php에서 허용해 준 store 라우트)로 데이터를 쏘아 보낸다.@csrf: 크로스 사이트 요청 위조(CSRF) 공격을 방어하는 라라벨의 핵심 보안 토큰이다. 이 한 줄을 적으면 라라벨이 브라우저에 임시 암호표를 숨겨둔다. 폼 전송을 할 때 이 암호표가 같이 넘어가지 않으면 라라벨 서버는 "해커의 불법 요청"으로 간주하고 419 Page Expired 에러를 내뿜으며 차단한다. 폼 태그 바로 아래에는 무조건 적어야 하는 약속과 같은 코드다. (Breeze를 Blade로 설치했을 경우에만)<x-input-error :messages="$errors->get('message')" class="mt-2" />: 글을 쓸 때 아무것도 안 적고 전송했거나, 곧 공부할 '유효성 검사'를 통과하지 못했을 때 라라벨 백엔드가 뱉어내는 에러 메시지($errors)를 화면에 빨간 글씨로 표시해 주는 컴포넌트다.
layouts/navigation.blade.php에서 메뉴에 링크 달기
layouts/navigation.blade.php의 수정 전 코드
<!-- Navigation Links -->
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
<x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
{{ __('Dashboard') }}
</x-nav-link>
</div>
{{-- 생략 --}}
<div class="pt-2 pb-3 space-y-1">
<x-responsive-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
{{ __('Dashboard') }}
</x-responsive-nav-link>
</div>
layouts/navigation.blade.php에서 이 부분을 찾아서 아래처럼 코드를 추가하자.
layouts/navigation.blade.php의 수정 후 코드
<!-- Navigation Links -->
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
<x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
{{ __('Dashboard') }}
</x-nav-link>
<x-nav-link :href="route('posts.index')" :active="request()->routeIs('posts.index')">
{{ __('Posts') }}
</x-nav-link>
</div>
{{-- 생략 --}}
<div class="pt-2 pb-3 space-y-1">
<x-responsive-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
{{ __('Dashboard') }}
</x-responsive-nav-link>
<x-responsive-nav-link :href="route('posts.index')" :active="request()->routeIs('posts.index')">
{{ __('Posts') }}
</x-responsive-nav-link>
</div>
각각 PC와 모바일 화면용 내비게이션 메뉴에 Posts로 이동하는 링크를 추가한 것이다.
:href="route('posts.index')": 메뉴를 누르면/posts주소로 이동시킨다.:active="request()->routeIs('posts.index')": 사용자가 현재 이 메뉴 페이지에 들어와 있는지 실시간으로 확인하는 코드다. 현재 내 주소가 posts.index가 맞다면 메뉴 글씨를 강조(Active)해 주는 시각적 효과를 켠다.
이 모든 코드들의 변화로 인해 이렇게 내비게이션 메뉴에 Posts가 추가되었고, 클릭하면 Posts 페이지로 이동하게 되었다.
드디어 단순한 웰컴 페이지를 넘어, 로그인한 회원들이 접근할 수 있는 'Posts' 메뉴와 깔끔한 글 작성 폼(Form)이 완성되었다.
라라벨 브리즈(Breeze)가 제공하는 기본 레이아웃 컴포넌트 덕분에 몇 줄의 코드만으로도 내비게이션 바까지 완벽하게 작동하는 것을 확인할 수 있다.
이제 사용자가 텍스트 영역에 글을 적고 Post 버튼을 누르면 데이터가 서버로 전송되어야 한다.
다음 포스트에서는 PostController의 store 메서드를 구현하여, 들어온 데이터의 무결성을 검사하는 '유효성 검사(Validation)'와 실제 DB에 안전하게 글을 저장하는 벡엔드 로직을 완성해 보겠다.
0 Comments
댓글 쓰기
🔸 댓글은 블로그 운영자의 승인 후에 블로그에 표시됩니다.
🔸 비로그인 방문자 분께서는 '익명'보다 이름/URL로 댓글을 남겨주시면 감사하겠습니다. (URL은 생략 가능합니다.)
🔸 구글 로그인 방문자는 '알림 사용'에 체크를 하시면, 남겨주신 댓글에 대한 답글 알림을 메일로 받아볼 수 있습니다. 📩