Laravel 을 배우기 위해서 진행하는 간단한 프로젝트이다.
db table 생성, 모델, 컨트롤을 자동 생성하고, 글쓰기 권한 설정하기와 알림 메일을 보내는 방법을 익힐 수 있다.
https://bootcamp.laravel.com/introduction
Laravel Bootcamp - Learn the PHP Framework for Web Artisans
Together let's walk through building and deploying a modern Laravel application from scratch.
bootcamp.laravel.com
1. 모델, DB, 컨트롤 만들기
# 가장 많이 사용하는 명령어
php artisan make:model -mrc Chirp
3개의 파일이 생성된다.
app/Models/Chirp.php
database/migrations/<timestamp>_create_chirps_table.php
app/Http/Controller/ChirpController.php
(1) app/Models/Chirp.php
class Chirp extends Model
{
use HasFactory;
protected $fillable = [
'message',
];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
(2) database/migrations/<timestamp>_create_chirps_table.php
db 의 테이블명은 chirps 가 된다.
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
(3) app/Http/Controller/ChirpController.php
index, store, edit, update, destroy (저장, 수정, 삭제)
class ChirpController extends Controller
{
public function index(): View
{
return view('chirps.index', [
'chirps' => Chirp::with('user')->latest()->get(),
]);
}
public function create()
{
//
}
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'message' => 'required|string|max:255',
]);
$request->user()->chirps()->create($validated);
return redirect(route('chirps.index'));
}
public function show(Chirp $chirp)
{
}
public function edit(Chirp $chirp): View
{
$this->authorize('update', $chirp);
return view('chirps.edit', [
'chirp' => $chirp,
]);
}
public function update(Request $request, Chirp $chirp): RedirectResponse
{
$this->authorize('update', $chirp);
$validated = $request->validate([
'message' => 'required|string|max:255',
]);
$chirp->update($validated);
return redirect(route('chirps.index'));
}
public function destroy(Chirp $chirp): RedirectResponse
{
$this->authorize('delete', $chirp);
$chirp->delete();
return redirect(route('chirps.index'));
}
}
2. 라우팅 설정하기
routes/web.php (컨트롤을 이용한 가장 간단한 세팅)
Route::resource('chirps', ChirpController::class)
->only(['index', 'store', 'edit', 'update', 'destroy'])
->middleware(['auth', 'verified']);
3. View 파일 만들기 (2개)
(1) 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 class="mt-6 bg-white shadow-sm rounded-lg divide-y">
@foreach ($chirps as $chirp)
<div class="p-6 flex space-x-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-gray-600 -scale-x-100" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
</svg>
<div class="flex-1">
<div class="flex justify-between items-center">
<div>
<span class="text-gray-800">{{ $chirp->user->name }}</span>
<small class="ml-2 text-sm text-gray-600">{{ $chirp->created_at->format('j M Y, g:i a') }}</small>
@unless ($chirp->created_at->eq($chirp->updated_at))
<small class="text-sm text-gray-600"> · {{ __('edited') }}</small>
@endunless
</div>
@if ($chirp->user->is(auth()->user()))
<x-dropdown>
<x-slot name="trigger">
<button>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
<path d="M6 10a2 2 0 11-4 0 2 2 0 014 0zM12 10a2 2 0 11-4 0 2 2 0 014 0zM16 12a2 2 0 100-4 2 2 0 000 4z" />
</svg>
</button>
</x-slot>
<x-slot name="content">
<x-dropdown-link :href="route('chirps.edit', $chirp)">
{{ __('Edit') }}
</x-dropdown-link>
<form method="POST" action="{{ route('chirps.destroy', $chirp) }}">
@csrf
@method('delete')
<x-dropdown-link :href="route('chirps.destroy', $chirp)" onclick="event.preventDefault(); this.closest('form').submit();">
{{ __('Delete') }}
</x-dropdown-link>
</form>
</x-slot>
</x-dropdown>
@endif
</div>
<p class="mt-4 text-lg text-gray-900">{{ $chirp->message }}</p>
</div>
</div>
@endforeach
</div>
</div>
</x-app-layout>
(2) resources/views/chirps/edit.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.update', $chirp) }}">
@csrf
@method('patch')
<textarea
name="message"
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', $chirp->message) }}</textarea>
<x-input-error :messages="$errors->get('message')" class="mt-2" />
<div class="mt-4 space-x-2">
<x-primary-button>{{ __('Save') }}</x-primary-button>
<a href="{{ route('chirps.index') }}">{{ __('Cancel') }}</a>
</div>
</form>
</div>
</x-app-layout>
4. 권한 설정하기
php artisan make:policy ChirpPolicy --model=Chirp
app/Policies/ChirpPolicy.php
class ChirpPolicy
{
public function viewAny(User $user): bool
{
//
}
public function view(User $user, Chirp $chirp): bool
{
//
}
public function create(User $user): bool
{
//
}
public function update(User $user, Chirp $chirp): bool
{
return $chirp->user()->is($user);
}
public function delete(User $user, Chirp $chirp): bool
{
return $this->update($user, $chirp);
}
public function restore(User $user, Chirp $chirp): bool
{
//
}
public function forceDelete(User $user, Chirp $chirp): bool
{
//
}
}
5. 추가설정 (알림메일 보내기)
1. 메일 폼 만들기
php artisan make:notification NewChirp
app/Notifications/NewChirp.php
class NewChirp extends Notification
{
use Queueable;
public function __construct(public Chirp $chirp)
{
//
}
public function via(object $notifiable): array
{
return ['mail'];
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject("New Chirp from {$this->chirp->user->name}")
->greeting("New Chirp from {$this->chirp->user->name}")
->line(Str::limit($this->chirp->message, 50))
->action('Go to Chirper', url('/'))
->line('Thank you for using our application!');
}
public function toArray(object $notifiable): array
{
return [
//
];
}
}
2. 이벤트 전달자 생성하기 (model <-> ChirpCreated <-> 이벤트서비스 <-> 이벤트구독리스트)
php artisan make:event ChirpCreated
app/Events/ChirpCreated.php
class ChirpCreated
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(public Chirp $chirp)
{
//
}
public function broadcastOn(): array
{
return [
new PrivateChannel('channel-name'),
];
}
}
3. 모델에 이벤트 패치하기
app/Models/Chirp.php
class Chirp extends Model
{
# 추가할 내용
protected $dispatchesEvents = [
'created' => ChirpCreated::class,
];
}
4. 이벤트 구독 리스트 만들기
php artisan make:listener SendChirpCreatedNotifications --event=ChirpCreated
app/Listeners/SendChirpCreatedNotifications.php
class SendChirpCreatedNotifications implements ShouldQueue
{
public function __construct()
{
//
}
public function handle(ChirpCreated $event): void
{
foreach (User::whereNot('id', $event->chirp->user_id)->cursor() as $user) {
$user->notify(new NewChirp($event->chirp));
}
}
}
5. 이벤트 서비스에 등록하기
App\Providers\EventServiceProvider.php
protected $listen = [
ChirpCreated::class => [
SendChirpCreatedNotifications::class,
],
];
6. 알림메일 테스트 방법
로컬에서 테스트
.env 환경파일에서 log 기록으로 확인
MAIL_MAILER=log
storage/logs/laravel.log 에 기록됨.
.env 환경파일에서 메일서버 계정연결
MAIL_MAILER=smtp
MAIL_HOST=mail.domain.com
MAIL_PORT=25
MAIL_USERNAME=id
MAIL_PASSWORD=pw
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="id@domain.com"
MAIL_FROM_NAME="${APP_NAME}"
또 하나의 관리자 계정을 추가해야 메일이 발송됨. 관리자가 2명 이상 있어야함.
6. 에러 발생
Jetstream 을 이미 설치한 경우 다음과 같은 에러가 발생할 수 있다.
Undefined variable $messages
Undefined variable $for
resources/views/components/input-error.blade.php
아래와 같이 수정한다.
@props(['messages'=>'','for'=>''])
@if ($messages)
<ul {{ $attributes->merge(['class' => 'text-sm text-red-600 space-y-1']) }}>
@foreach ((array) $messages as $message)
<li>{{ $message }}</li>
@endforeach
</ul>
@endif
@error($for)
<p {{ $attributes->merge(['class' => 'text-sm text-red-600']) }}>{{ $message }}</p>
@enderror
'Laravel' 카테고리의 다른 글
Laravel - Splade (Single Page Application) (0) | 2023.10.21 |
---|---|
Laravel - 라우트(Route) 핵심정리 (0) | 2023.10.21 |
Laravel - 프로젝트 시작하기 (0) | 2023.10.19 |
Laravel - .env 환경설정 알아보기 (0) | 2023.10.19 |
Laravel - Artisan 명령어 알아보기 (0) | 2023.10.19 |
Laravel 을 배우기 위해서 진행하는 간단한 프로젝트이다.
db table 생성, 모델, 컨트롤을 자동 생성하고, 글쓰기 권한 설정하기와 알림 메일을 보내는 방법을 익힐 수 있다.
https://bootcamp.laravel.com/introduction
Laravel Bootcamp - Learn the PHP Framework for Web Artisans
Together let's walk through building and deploying a modern Laravel application from scratch.
bootcamp.laravel.com
1. 모델, DB, 컨트롤 만들기
# 가장 많이 사용하는 명령어
php artisan make:model -mrc Chirp
3개의 파일이 생성된다.
app/Models/Chirp.php
database/migrations/<timestamp>_create_chirps_table.php
app/Http/Controller/ChirpController.php
(1) app/Models/Chirp.php
class Chirp extends Model
{
use HasFactory;
protected $fillable = [
'message',
];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
(2) database/migrations/<timestamp>_create_chirps_table.php
db 의 테이블명은 chirps 가 된다.
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
(3) app/Http/Controller/ChirpController.php
index, store, edit, update, destroy (저장, 수정, 삭제)
class ChirpController extends Controller
{
public function index(): View
{
return view('chirps.index', [
'chirps' => Chirp::with('user')->latest()->get(),
]);
}
public function create()
{
//
}
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'message' => 'required|string|max:255',
]);
$request->user()->chirps()->create($validated);
return redirect(route('chirps.index'));
}
public function show(Chirp $chirp)
{
}
public function edit(Chirp $chirp): View
{
$this->authorize('update', $chirp);
return view('chirps.edit', [
'chirp' => $chirp,
]);
}
public function update(Request $request, Chirp $chirp): RedirectResponse
{
$this->authorize('update', $chirp);
$validated = $request->validate([
'message' => 'required|string|max:255',
]);
$chirp->update($validated);
return redirect(route('chirps.index'));
}
public function destroy(Chirp $chirp): RedirectResponse
{
$this->authorize('delete', $chirp);
$chirp->delete();
return redirect(route('chirps.index'));
}
}
2. 라우팅 설정하기
routes/web.php (컨트롤을 이용한 가장 간단한 세팅)
Route::resource('chirps', ChirpController::class)
->only(['index', 'store', 'edit', 'update', 'destroy'])
->middleware(['auth', 'verified']);
3. View 파일 만들기 (2개)
(1) 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 class="mt-6 bg-white shadow-sm rounded-lg divide-y">
@foreach ($chirps as $chirp)
<div class="p-6 flex space-x-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-gray-600 -scale-x-100" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
</svg>
<div class="flex-1">
<div class="flex justify-between items-center">
<div>
<span class="text-gray-800">{{ $chirp->user->name }}</span>
<small class="ml-2 text-sm text-gray-600">{{ $chirp->created_at->format('j M Y, g:i a') }}</small>
@unless ($chirp->created_at->eq($chirp->updated_at))
<small class="text-sm text-gray-600"> · {{ __('edited') }}</small>
@endunless
</div>
@if ($chirp->user->is(auth()->user()))
<x-dropdown>
<x-slot name="trigger">
<button>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
<path d="M6 10a2 2 0 11-4 0 2 2 0 014 0zM12 10a2 2 0 11-4 0 2 2 0 014 0zM16 12a2 2 0 100-4 2 2 0 000 4z" />
</svg>
</button>
</x-slot>
<x-slot name="content">
<x-dropdown-link :href="route('chirps.edit', $chirp)">
{{ __('Edit') }}
</x-dropdown-link>
<form method="POST" action="{{ route('chirps.destroy', $chirp) }}">
@csrf
@method('delete')
<x-dropdown-link :href="route('chirps.destroy', $chirp)" onclick="event.preventDefault(); this.closest('form').submit();">
{{ __('Delete') }}
</x-dropdown-link>
</form>
</x-slot>
</x-dropdown>
@endif
</div>
<p class="mt-4 text-lg text-gray-900">{{ $chirp->message }}</p>
</div>
</div>
@endforeach
</div>
</div>
</x-app-layout>
(2) resources/views/chirps/edit.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.update', $chirp) }}">
@csrf
@method('patch')
<textarea
name="message"
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', $chirp->message) }}</textarea>
<x-input-error :messages="$errors->get('message')" class="mt-2" />
<div class="mt-4 space-x-2">
<x-primary-button>{{ __('Save') }}</x-primary-button>
<a href="{{ route('chirps.index') }}">{{ __('Cancel') }}</a>
</div>
</form>
</div>
</x-app-layout>
4. 권한 설정하기
php artisan make:policy ChirpPolicy --model=Chirp
app/Policies/ChirpPolicy.php
class ChirpPolicy
{
public function viewAny(User $user): bool
{
//
}
public function view(User $user, Chirp $chirp): bool
{
//
}
public function create(User $user): bool
{
//
}
public function update(User $user, Chirp $chirp): bool
{
return $chirp->user()->is($user);
}
public function delete(User $user, Chirp $chirp): bool
{
return $this->update($user, $chirp);
}
public function restore(User $user, Chirp $chirp): bool
{
//
}
public function forceDelete(User $user, Chirp $chirp): bool
{
//
}
}
5. 추가설정 (알림메일 보내기)
1. 메일 폼 만들기
php artisan make:notification NewChirp
app/Notifications/NewChirp.php
class NewChirp extends Notification
{
use Queueable;
public function __construct(public Chirp $chirp)
{
//
}
public function via(object $notifiable): array
{
return ['mail'];
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject("New Chirp from {$this->chirp->user->name}")
->greeting("New Chirp from {$this->chirp->user->name}")
->line(Str::limit($this->chirp->message, 50))
->action('Go to Chirper', url('/'))
->line('Thank you for using our application!');
}
public function toArray(object $notifiable): array
{
return [
//
];
}
}
2. 이벤트 전달자 생성하기 (model <-> ChirpCreated <-> 이벤트서비스 <-> 이벤트구독리스트)
php artisan make:event ChirpCreated
app/Events/ChirpCreated.php
class ChirpCreated
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(public Chirp $chirp)
{
//
}
public function broadcastOn(): array
{
return [
new PrivateChannel('channel-name'),
];
}
}
3. 모델에 이벤트 패치하기
app/Models/Chirp.php
class Chirp extends Model
{
# 추가할 내용
protected $dispatchesEvents = [
'created' => ChirpCreated::class,
];
}
4. 이벤트 구독 리스트 만들기
php artisan make:listener SendChirpCreatedNotifications --event=ChirpCreated
app/Listeners/SendChirpCreatedNotifications.php
class SendChirpCreatedNotifications implements ShouldQueue
{
public function __construct()
{
//
}
public function handle(ChirpCreated $event): void
{
foreach (User::whereNot('id', $event->chirp->user_id)->cursor() as $user) {
$user->notify(new NewChirp($event->chirp));
}
}
}
5. 이벤트 서비스에 등록하기
App\Providers\EventServiceProvider.php
protected $listen = [
ChirpCreated::class => [
SendChirpCreatedNotifications::class,
],
];
6. 알림메일 테스트 방법
로컬에서 테스트
.env 환경파일에서 log 기록으로 확인
MAIL_MAILER=log
storage/logs/laravel.log 에 기록됨.
.env 환경파일에서 메일서버 계정연결
MAIL_MAILER=smtp
MAIL_HOST=mail.domain.com
MAIL_PORT=25
MAIL_USERNAME=id
MAIL_PASSWORD=pw
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="id@domain.com"
MAIL_FROM_NAME="${APP_NAME}"
또 하나의 관리자 계정을 추가해야 메일이 발송됨. 관리자가 2명 이상 있어야함.
6. 에러 발생
Jetstream 을 이미 설치한 경우 다음과 같은 에러가 발생할 수 있다.
Undefined variable $messages
Undefined variable $for
resources/views/components/input-error.blade.php
아래와 같이 수정한다.
@props(['messages'=>'','for'=>''])
@if ($messages)
<ul {{ $attributes->merge(['class' => 'text-sm text-red-600 space-y-1']) }}>
@foreach ((array) $messages as $message)
<li>{{ $message }}</li>
@endforeach
</ul>
@endif
@error($for)
<p {{ $attributes->merge(['class' => 'text-sm text-red-600']) }}>{{ $message }}</p>
@enderror
'Laravel' 카테고리의 다른 글
Laravel - Splade (Single Page Application) (0) | 2023.10.21 |
---|---|
Laravel - 라우트(Route) 핵심정리 (0) | 2023.10.21 |
Laravel - 프로젝트 시작하기 (0) | 2023.10.19 |
Laravel - .env 환경설정 알아보기 (0) | 2023.10.19 |
Laravel - Artisan 명령어 알아보기 (0) | 2023.10.19 |