05. Mengedit Chirp
Mari kita tambahkan fitur yang tidak ada di platform mikroblog bertema burung populer lainnya — kemampuan untuk mengedit Chirp!
Routing
Pertama, kita akan memperbarui file rute kita untuk mengaktifkan rute chirps.edit dan chirps.update untuk controller resource kita. Rute chirps.edit akan menampilkan formulir untuk mengedit Chirp, sementara rute chirps.update akan menerima data dari formulir dan memperbarui model:
<?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'])+ ->only(['index', 'store', 'edit', 'update']) ->middleware(['auth', 'verified']);
require __DIR__.'/auth.php';
Tabel rute untuk controller ini sekarang terlihat seperti ini:
| 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 |
Menautkan ke halaman edit
Selanjutnya, mari tautkan rute chirps.edit baru kita. Kita akan menggunakan komponen x-dropdown bawaan Breeze, yang hanya akan kita tampilkan kepada penulis Chirp. Kita juga akan menampilkan indikasi jika Chirp telah diedit dengan membandingkan tanggal created_at milik Chirp dengan tanggal updated_at-nya:
<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>+ </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>
Membuat formulir edit
Mari kita buat view Blade baru dengan formulir untuk mengedit Chirp. Ini mirip dengan formulir untuk membuat Chirp, kecuali kita akan mengirimkan ke rute chirps.update dan menggunakan direktif @method untuk menentukan bahwa kita membuat request (berjenis) "PATCH". Kita juga akan mengisi kolom isian tersebut dengan pesan Chirp yang sudah ada:
<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>
Memperbarui controller
Mari perbarui metode edit pada ChirpController untuk menampilkan formulir kita. Laravel akan secara otomatis memuat model Chirp dari database menggunakan route model binding sehingga kita bisa meneruskannya langsung ke view.
Kita kemudian akan memperbarui metode update untuk memvalidasi request dan memperbarui database.
Meskipun kita hanya menampilkan tombol edit kepada penulis Chirp, kita tetap perlu memastikan pengguna yang mengakses rute ini memiliki otorisasi:
<?php
namespace App\Http\Controllers; use App\Models\Chirp; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Http\Response;+use Illuminate\Support\Facades\Gate; use Illuminate\View\View; class ChirpController extends Controller {
/** * Menampilkan daftar resource. */ public function index(): View { return view('chirps.index', [ 'chirps' => Chirp::with('user')->latest()->get(), ]); } /** * Menampilkan formulir untuk membuat resource baru. */ public function create() { // } /** * Menyimpan resource yang baru dibuat ke dalam penyimpanan. */ public function store(Request $request): RedirectResponse { $validated = $request->validate([ 'message' => 'required|string|max:255', ]); $request->user()->chirps()->create($validated); return redirect(route('chirps.index')); } /** * Menampilkan resource yang dipilih/spesifik. */ public function show(Chirp $chirp) { // } /** * Menampilkan formulir untuk mengedit resource yang dipilih/spesifik. */- public function edit(Chirp $chirp)+ public function edit(Chirp $chirp): View {- //+ Gate::authorize('update', $chirp);+ + return view('chirps.edit', [+ 'chirp' => $chirp,+ ]); } /** * Memperbarui resource yang dipilih/spesifik di dalam penyimpanan. */- public function update(Request $request, Chirp $chirp)+ public function update(Request $request, Chirp $chirp): RedirectResponse {- //+ Gate::authorize('update', $chirp);+ + $validated = $request->validate([+ 'message' => 'required|string|max:255',+ ]);+ + $chirp->update($validated);+ + return redirect(route('chirps.index')); }
/** * Menghapus resource yang dipilih/spesifik dari penyimpanan. */ public function destroy(Chirp $chirp) { // } }
Anda mungkin menyadari bahwa aturan validasi diduplikasi dengan metode store. Anda mungkin mempertimbangkan untuk mengekstraknya menggunakan Form Request Validation milik Laravel, yang memudahkan penggunaan kembali aturan validasi dan menjaga controller tetap ringan.
Otorisasi
Secara default, metode authorize akan mencegah siapa pun untuk dapat memperbarui Chirp. Kita dapat menentukan siapa yang diizinkan untuk memperbaruinya dengan membuat Model Policy menggunakan perintah berikut:
php artisan make:policy ChirpPolicy --model=Chirp
Ini akan membuat kelas policy di app/Policies/ChirpPolicy.php yang dapat kita perbarui untuk menentukan bahwa hanya penulis yang berwenang untuk memperbarui Chirp:
<?php
namespace App\Policies; use App\Models\Chirp; use App\Models\User; use Illuminate\Auth\Access\HandlesAuthorization; class ChirpPolicy {
use HandlesAuthorization; /** * Tentukan apakah pengguna dapat melihat model apa saja. */ public function viewAny(User $user): bool { // } /** * Tentukan apakah pengguna dapat melihat model yang ditentukan. */ public function view(User $user, Chirp $chirp): bool { // } /** * Tentukan apakah pengguna dapat membuat model. */ public function create(User $user): bool { // } /** * Menentukan apakah pengguna dapat memperbarui model. */ public function update(User $user, Chirp $chirp): bool {- //+ return $chirp->user()->is($user); }
/** * Menentukan apakah pengguna dapat menghapus model. */ public function delete(User $user, Chirp $chirp): bool { // } /** * Menentukan apakah pengguna dapat merestorasi model. */ public function restore(User $user, Chirp $chirp): bool { // } /** * Menentukan apakah pengguna dapat menghapus model secara permanen. */ public function forceDelete(User $user, Chirp $chirp): bool { // } }
Coba sekarang
Waktunya untuk mencobanya! Silakan edit beberapa Chirp menggunakan menu dropdown. Jika Anda mendaftarkan akun pengguna lain, Anda akan melihat bahwa hanya penulis Chirp yang dapat mengeditnya.