"Blade로 Chirper 구축 - Chirps 삭제"의 두 판 사이의 차이

 
(같은 사용자의 중간 판 3개는 보이지 않습니다)
10번째 줄: 10번째 줄:


==라우팅==
==라우팅==
<code>chirps.destroy</code> 라우트를 활성화하기 위해 다시 라우트를 업데이트합니다:
{{소스헤더|routes/web.php}}
<syntaxhighlight lang='php' highlight='4'>
<?php
...
Route::resource('chirps', ChirpController::class)
    ->only(['index', 'store', 'edit', 'update', 'destroy'])
    ->middleware(['auth', 'verified']);
...
</syntaxhighlight>
이제 이 컨트롤러의 라우트 테이블은 다음과 같습니다:
{| class='wikitable'
|-
! Verb !! URI !! Action !! Route Name
|-
| GET || <code>/chirps</code> || index || chirps.index
|-
| POST || <code>/chirps</code> || store || chirps.store
|-
| GET || <code>/chirps/{chirp}/edit</code> || edit || chirps.edit
|-
| PUT/PATCH || <code>/chirps/{chirp}</code> || update || chirps.update
|-
| DELETE || <code>/chirps/{chirp}<code> || destroy || chirps.destroy
|}
==컨트롤러 업데이트하기==
==컨트롤러 업데이트하기==
이제 <code>ChirpController</code> 클래스의 <code>destroy</code> 메소드를 업데이트하여 삭제 작업을 수행하고 Chirp 인덱스로 돌아가게 할 수 있습니다:
{{소스헤더|app/Http/Controllers/ChirpController.php}}
<syntaxhighlight lang='php' highlight='9-16'>
<?php
...
class ChirpController extends Controller
{
    ...
    /**
    * Remove the specified resource from storage.
    */
    public function destroy(Chirp $chirp): RedirectResponse
    {
        Gate::authorize('delete', $chirp);
        $chirp->delete();
        return redirect(route('chirps.index'));
    }
}
</syntaxhighlight>
==인가==
==인가==
편집과 마찬가지로 Chirp 작성자만 자신의 Chirp를 삭제할 수 있도록 삭제 메서드를 ChirpPolicy 클래스에서 업데이트해보겠습니다:
{{소스헤더|app/Policies/ChirpPolicy.php}}
<syntaxhighlight lang='php' highlight='11'>
<?php
...
class ChirpPolicy
{
    ...
    /**
    * Determine whether the user can delete the model.
    */
    public function delete(User $user, Chirp $chirp): bool
    {
        return $this->update($user, $chirp);
    }
    ...
}
</syntaxhighlight>
<code>update</code> 메서드의 로직을 반복하지 않고, <code>destroy</code> 메소드에서 <code>update</code> 메소드를 호출하여 동일한 로직을 정의할 수 있습니다. 이제 Chirp를 업데이트할 권한이 있는 사람은 Chirp를 삭제할 권한도 가지게 됩니다.
==뷰 업데이트하기==
==뷰 업데이트하기==
마지막으로, 이전에 만든 <code>chirps.index</code> 뷰에 있는 드롭다운 메뉴에 삭제 버튼을 추가할 수 있습니다:
{{소스헤더|resources/views/chirps/index.blade.php}}
<syntaxhighlight lang='php' highlight='42-48'>
<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"> &middot; {{ __('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>
</syntaxhighlight>
==테스트하기==
==테스트하기==
만약 마음에 들지 않는 Chirp를 올렸다면, 삭제해보세요!
만약 마음에 들지 않는 Chirp를 올렸다면, 삭제해보세요!


[[파일:chirp-delete-blade.png|640px]]
[[파일:chirp-delete-blade.png|640px]]

2024년 6월 18일 (화) 22:14 기준 최신판

1 개요[ | ]

06. Deleting Chirps
06. Chirps 삭제

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

이번에는 사용자가 자신의 Chirp을 삭제할 수 있는 기능을 제공합시다.

이제 어떻게 하는지 감을 잡기 시작했을 거라고 생각합니다. 이 기능을 얼마나 빠르게 추가할 수 있는지에 대해 여러분이 감명받을 거라고 생각합니다.

2 라우팅[ | ]

chirps.destroy 라우트를 활성화하기 위해 다시 라우트를 업데이트합니다:

routes/web.php
<?php
...
Route::resource('chirps', ChirpController::class)
    ->only(['index', 'store', 'edit', 'update', 'destroy'])
    ->middleware(['auth', 'verified']);
...

이제 이 컨트롤러의 라우트 테이블은 다음과 같습니다:

Verb URI Action Route Name
GET /chirps index chirps.index
POST /chirps store chirps.store
GET /chirps/{chirp}/edit edit chirps.edit
PUT/PATCH /chirps/{chirp} update chirps.update
DELETE /chirps/{chirp} destroy chirps.destroy

3 컨트롤러 업데이트하기[ | ]

이제 ChirpController 클래스의 destroy 메소드를 업데이트하여 삭제 작업을 수행하고 Chirp 인덱스로 돌아가게 할 수 있습니다:

app/Http/Controllers/ChirpController.php
<?php
...
class ChirpController extends Controller
{
    ...
    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Chirp $chirp): RedirectResponse
    {
        Gate::authorize('delete', $chirp);
 
        $chirp->delete();
 
        return redirect(route('chirps.index'));
    }
}

4 인가[ | ]

편집과 마찬가지로 Chirp 작성자만 자신의 Chirp를 삭제할 수 있도록 삭제 메서드를 ChirpPolicy 클래스에서 업데이트해보겠습니다:

app/Policies/ChirpPolicy.php
<?php
...
class ChirpPolicy
{
    ...
    /**
     * Determine whether the user can delete the model.
     */
    public function delete(User $user, Chirp $chirp): bool
    {
        return $this->update($user, $chirp);
    }
    ...
}

update 메서드의 로직을 반복하지 않고, destroy 메소드에서 update 메소드를 호출하여 동일한 로직을 정의할 수 있습니다. 이제 Chirp를 업데이트할 권한이 있는 사람은 Chirp를 삭제할 권한도 가지게 됩니다.

5 뷰 업데이트하기[ | ]

마지막으로, 이전에 만든 chirps.index 뷰에 있는 드롭다운 메뉴에 삭제 버튼을 추가할 수 있습니다:

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"> &middot; {{ __('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>

6 테스트하기[ | ]

만약 마음에 들지 않는 Chirp를 올렸다면, 삭제해보세요!

Chirp-delete-blade.png

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