Langsung ke konten

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:

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'])
+ ->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:

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>
+ </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:

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>

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:

app/Http/Controllers/ChirpController.php
<?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)
{
//
}
 
}

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:

app/Policies/ChirpPolicy.php
<?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.

Chirp yang telah diedit

Lanjutkan untuk mengizinkan penghapusan Chirp...