Blade로 Chirper 구축 - Chirps 생성

1 개요

03. Creating Chirps
03. Chirps 생성

https://bootcamp.laravel.com/blade/creating-chirps

이제 새로운 애플리케이션을 만들 준비가 되었습니다! 사용자들이 Chirps라는 짧은 메시지를 게시할 수 있도록 해봅시다.

2 모델, 마이그레이션, 컨트롤러

사용자들이 Chirp를 게시할 수 있도록 하려면 모델, 마이그레이션, 컨트롤러를 만들어야 합니다. 각 개념을 좀 더 깊이 살펴보겠습니다:

  • 모델은 데이터베이스의 테이블과 상호작용할 수 있는 강력하고 즐거운 인터페이스를 제공합니다.
  • 마이그레이션은 데이터베이스의 테이블을 쉽게 생성하고 수정할 수 있게 해줍니다. 이를 통해 애플리케이션이 실행되는 모든 곳에서 동일한 데이터베이스 구조가 유지되도록 보장합니다.
  • 컨트롤러는 애플리케이션에 대한 요청을 처리하고 응답을 반환하는 역할을 합니다.

거의 모든 기능은 이 세 가지 요소가 조화롭게 작동하는 것을 포함하며, artisan make:model 명령어를 사용하면 이 모든 것을 한 번에 생성할 수 있습니다.

Chirp를 위한 모델, 마이그레이션, 리소스 컨트롤러를 생성하려면 다음 명령어를 사용하세요:

php artisan make:model -mrc Chirp

Note

php artisan make:model --help 명령어를 실행하여 사용가능한 모든 옵션을 볼 수 있습니다.

이 명령어는 다음 세 가지 파일을 생성합니다:

  • app/Models/Chirp.php: Eloquent 모델.
  • database/migrations/<timestamp>_create_chirps_table.php: 데이터베이스 테이블을 생성할 데이터베이스 마이그레이션.
  • app/Http/Controllers/ChirpController.php: 들어오는 요청을 처리하고 응답을 반환할 HTTP 컨트롤러.

3 라우팅

컨트롤러를 위해 URL을 생성해야 합니다. 이는 프로젝트의 routes 디렉토리에서 관리할 수 있습니다. 리소스 컨트롤러를 사용하기 때문에 단일 Route::resource() 문으로 모든 라우트를 정의하여 기존 URL 구조를 따를 수 있습니다.

우선, 두 개의 라우트를 활성화할 것입니다:

  • index 라우트는 폼과 Chirps 목록을 표시합니다.
  • store 라우트는 새로운 Chirps를 저장하는 데 사용됩니다.

이 라우트들을 두 개의 미들웨어 뒤에 배치할 것입니다:

  • auth 미들웨어는 로그인한 사용자만 라우트에 접근할 수 있도록 합니다.
  • verified 미들웨어는 이메일 인증을 활성화할 경우 사용됩니다.
routes/web.php
<?php
 
use App\Http\Controllers\ChirpController;
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');
});
 
Route::resource('chirps', ChirpController::class)
    ->only(['index', 'store'])
    ->middleware(['auth', 'verified']);
 
require __DIR__.'/auth.php';

이 코드는 다음과 같은 라우트를 생성합니다:

Verb URI Action Route Name
GET /chirps index chirps.index
POST /chirps store chirps.store

Note

모든 라우트를 보려면 php artisan route:list 명령어를 실행하면 됩니다.

ChirpController 클래스의 index 메소드에서 테스트 메시지를 반환하여 라우트와 컨트롤러를 테스트해봅시다:

app/Http/Controllers/ChirpController.php
<?php
...
use Illuminate\Http\Response; 
 
class ChirpController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(): Response 
    {
        return response('Hello, World!');
    }
    ...
}

이전에 로그인된 상태라면 http://localhost:8000/chirps , 또는 Sail을 사용 중이라면 http://localhost/chirps 로 이동하여 메시지를 확인할 수 있습니다.

4 Blade

아직까 별 게 없죠? ChirpController 클래스의 index 메소드를 업데이트하여 Blade 뷰를 렌더링하도록 합시다:

app/Http/Controllers/ChirpController.php
<?php
...
use Illuminate\View\View;
 
class ChirpController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(): View
    {
        return view('chirps.index');
    }
    ...
}

그런 다음 새 Chirps를 생성하기 위한 폼이 포함된 Blade 뷰 템플릿을 생성할 수 있습니다:

resources/views/chirps/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('chirps.store') }}">
            @csrf
            <textarea
                name="message"
                placeholder="{{ __('What\'s on your mind?') }}"
                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"
            >{{ old('message') }}</textarea>
            <x-input-error :messages="$errors->get('message')" class="mt-2" />
            <x-primary-button class="mt-4">{{ __('Chirp') }}</x-primary-button>
        </form>
    </div>
</x-app-layout>

이제 브라우저에서 페이지를 새로고침 하면 Breeze에서 제공하는 기본 레이아웃에 새 폼이 렌더링되는 것을 볼 수 있습니다!

Chirp-form.png

위의 스크린샷과 조금 다르게 보일 경우, Tailwind가 우리가 방금 생성한 새 파일의 CSS 클래스를 감지하도록 Vite 개발 서버를 중지하고 다시 시작해야 할 수 있습니다.

이 시점부터 Vite 개발 서버가 npm run dev로 실행 중인 경우, Blade 템플릿에 대한 모든 변경사항이 브라우저에서 자동으로 새로고침됩니다.

5 내비게이션 메뉴

Breeze에서 제공하는 내비게이션 메뉴에 링크를 추가해봅시다.

데스크톱 화면에 대한 메뉴 항목을 추가하려면 Breeze에서 제공하는 navigation.blade.php 컴포넌트를 업데이트하세요:

resources/views/layouts/navigation.blade.php
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
    <x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
        {{ __('Dashboard') }}
    </x-nav-link>
    <x-nav-link :href="route('chirps.index')" :active="request()->routeIs('chirps.index')">
        {{ __('Chirps') }}
    </x-nav-link>
</div>

모바일 화면에도 추가하려면:

resources/views/layouts/navigation.blade.php
<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('chirps.index')" :active="request()->routeIs('chirps.index')">
        {{ __('Chirps') }}
    </x-responsive-nav-link>
</div>

6 Chrip 저장

폼이 이전에 생성한 chirps.store 라우트로 메시지를 포스트하도록 설정되었습니다. 이제 ChirpController 클래스의 store 메소드를 업데이트하여 데이터를 유효성 검증하고 새로운 Chirp를 생성하겠습니다.

app/Http/Controllers/ChirpController.php
<?php
...
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;

class ChirpController extends Controller
{
    ...
    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'message' => 'required|string|max:255',
        ]);

        $request->user()->chirps()->create($validated);

        return redirect(route('chirps.index'));
    }
    ...
}

Laravel의 강력한 유효성 검증 기능을 사용하여 사용자가 메시지를 제공하고, 그 메시지가 이후 생성할 데이터베이스 컬럼의 255자 제한을 초과하지 않도록 합니다.

그런 다음, chirps 관계를 활용하여 로그인한 사용자에게 속하는 레코드를 생성합니다. 이 관계는 곧 정의할 것입니다.

마지막으로, 사용자들을 chirps.index 라우트로 다시 보내기 위해 리다이렉트 응답을 반환할 수 있습니다.

7 관계 생성

이전 단계에서 $request->user() 객체에 chirps 메소드를 호출한 것을 눈치챘을 것입니다. 이 메소드를 User 모델에 생성하여 "다대일(has many)" 관계를 정의해야 합니다:

app/Models/User.php
<?php
...
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
 
class User extends Authenticatable
{
    ...
    public function chirps(): HasMany
    {
        return $this->hasMany(Chirp::class);
    }
}

Note

Laravel은 다양한 종류의 모델 관계를 제공하며, Eloquent 관계 문서에서 더 자세히 읽어볼 수 있습니다.

8 대량 할당 보호

요청의 모든 데이터를 모델에 전달하는 것은 위험할 수 있습니다. 사용자가 프로필을 편집할 수 있는 페이지를 생각해 보십시오. 요청 전체를 모델에 전달하면 사용자가 is_admin 컬럼과 같이 원하는 모든 컬럼을 수정할 수 있습니다. 이를 대량 할당 취약점이라고 합니다.

Laravel은 기본적으로 대량 할당을 차단하여 실수로 이러한 일이 발생하는 것을 방지합니다. 하지만 대량 할당은 매우 편리하여 각 속성을 일일이 할당할 필요가 없습니다. 안전한 속성에 대해 대량 할당을 활성화하려면 이를 "fillable"로 표시할 수 있습니다.

Chirp 모델에 $fillable 속성을 추가하여 message 속성에 대한 대량 할당을 활성화해 보겠습니다:

app/Models/Chirp.php
<?php
...
class Chirp extends Model
{
    ...
    protected $fillable = [
        'message',
    ];
}

Laravel의 대량 할당 보호에 대한 자세한 내용은 문서를 참조하세요.

9 마이그레이션 업데이트하기

애플리케이션을 생성하는 동안 Laravel은 이미 database/migrations 디렉토리에 포함된 기본 마이그레이션을 적용했습니다. 현재 데이터베이스 구조를 확인하려면 php artisan db:showphp artisan db:table 명령어를 사용할 수 있습니다:

php artisan db:show
php artisan db:table users

이제 남은 것은 ChirpUser 간의 관계와 메시지 자체를 저장하기 위한 추가 컬럼입니다. 이전에 생성한 데이터베이스 마이그레이션 파일을 열어서 부가 컬럼을 추가할 시간입니다:

database/migrations/<timestamp>_create_chirps_table.php
<?php
...
return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('chirps', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->string('message');
            $table->timestamps();
        });
    }
    ...
};

이 마이그레이션을 추가한 이후로 데이터베이스를 마이그레이션하지 않았으므로 지금 해보겠습니다:

php artisan migrate

Warning

각 데이터베이스 마이그레이션은 한 번만 실행됩니다. 테이블에 추가 변경을 하려면 또 다른 마이그레이션을 생성해야 합니다. 개발 중에는 php artisan migrate:fresh 명령어를 사용하여 배포되지 않은 마이그레이션을 업데이트하고 데이터베이스를 처음부터 다시 빌드할 수 있습니다.

10 테스트

생성한 폼을 사용하여 Chirp를 보낼 준비가 되었습니다! 아직 페이지에 기존 Chirp를 표시하지 않았기 때문에 결과를 볼 수는 없습니다.

Chirp-form-filled.png

메시지 필드를 비워두거나 255자 이상을 입력하면 유효성 검증이 작동하는 것을 볼 수 있습니다.

10.1 Artisan Tinker

지금이 Artisan Tinker에 대해 배울 좋은 시점입니다. Artisan Tinker는 Laravel 애플리케이션에서 임의의 PHP 코드를 실행할 수 있는 REPL(읽기-평가-출력 루프)입니다.

콘솔에서 새 tinker 세션을 시작합니다:

php artisan tinker

다음으로, 데이터베이스에 있는 Chirp를 표시하기 위해 다음 코드를 실행합니다:

App\Models\Chirp::all();
=> Illuminate\Database\Eloquent\Collection {#4512
     all: [
       App\Models\Chirp {#4514
         id: 1,
         user_id: 1,
         message: "I'm building Chirper with Laravel!",
         created_at: "2022-08-24 13:37:00",
         updated_at: "2022-08-24 13:37:00",
       },
     ],
   }

Tinker를 종료하려면 exit 명령어를 사용하거나 Ctrl + c를 누릅니다.

문서 댓글 ({{ doc_comments.length }})
{{ comment.name }} {{ comment.created | snstime }}