Seri Belajar Laravel: ← Part 4 — Eloquent ORM  |  Part 5 — Form & CRUD  |  Part 6 — Layout Blade →

Aplikasi catatan kita sudah bisa menampilkan data. Sekarang saatnya membuat user bisa menambah, mengedit, dan menghapus catatan melalui form. Inilah CRUD lengkap: Create, Read, Update, Delete.

📋 Progress Belajarmu

Setup Route Lengkap

Pertama, daftarkan semua route CRUD di routes/web.php:

use App\Http\Controllers\CatatanController;

Route::get('/catatan',              [CatatanController::class, 'index']);   // Daftar
Route::get('/catatan/create',       [CatatanController::class, 'create']);  // Form tambah
Route::post('/catatan',             [CatatanController::class, 'store']);   // Simpan baru
Route::get('/catatan/{id}',         [CatatanController::class, 'show']);    // Detail
Route::get('/catatan/{id}/edit',    [CatatanController::class, 'edit']);    // Form edit
Route::put('/catatan/{id}',         [CatatanController::class, 'update']); // Simpan edit
Route::delete('/catatan/{id}',      [CatatanController::class, 'destroy']);// Hapus

① Form Tambah Catatan (Create)

Tambahkan method create di CatatanController:

public function create()
{
    return view('catatan.create');
}

Buat file resources/views/catatan/create.blade.php:

<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <title>Tambah Catatan</title>
    <style>
        body  { font-family: sans-serif; max-width: 600px; margin: 40px auto; padding: 0 20px; }
        label { display: block; margin: 16px 0 6px; font-weight: 600; color: #374151; }
        input, textarea {
            width: 100%; padding: 10px; border: 1px solid #d1d5db;
            border-radius: 6px; font-size: 1rem; box-sizing: border-box;
        }
        .error { color: #dc2626; font-size: 0.875rem; margin-top: 4px; }
        button { margin-top: 20px; background: #0f766e; color: white; border: none;
                 padding: 10px 24px; border-radius: 6px; cursor: pointer; font-size: 1rem; }
    </style>
</head>
<body>
    <h1>Tambah Catatan</h1>
    <a href="/catatan">← Kembali</a>

    <form action="/catatan" method="POST">
        @csrf  {{-- WAJIB ada! Melindungi dari serangan CSRF --}}

        <label>Judul</label>
        <input type="text" name="judul" value="{{ old('judul') }}">
        @error('judul')
            <div class="error">{{ $message }}</div>
        @enderror

        <label>Isi Catatan</label>
        <textarea name="isi" rows="5">{{ old('isi') }}</textarea>
        @error('isi')
            <div class="error">{{ $message }}</div>
        @enderror

        <label style="display:flex;align-items:center;gap:8px;font-weight:normal;">
            <input type="checkbox" name="penting" value="1" style="width:auto;"
                {{ old('penting') ? 'checked' : '' }}>
            Tandai sebagai penting
        </label>

        <button type="submit">Simpan Catatan</button>
    </form>
</body>
</html>
@csrf adalah directive Blade yang menyisipkan token keamanan tersembunyi ke form. Tanpanya, Laravel akan menolak semua POST request dengan error "419 Page Expired". Selalu tambahkan @csrf di setiap form POST.

old('judul') mengisi ulang field dengan nilai yang sudah diketik sebelumnya — sangat berguna ketika validasi gagal agar user tidak perlu ketik ulang semuanya.

② Validasi dan Simpan (Store)

public function store(Request $request)
{
    // Validasi input
    $validated = $request->validate([
        'judul' => 'required|min:3|max:255',
        'isi'   => 'required|min:10',
    ]);

    // Simpan ke database
    Catatan::create([
        'judul'   => $validated['judul'],
        'isi'     => $validated['isi'],
        'penting' => $request->has('penting'),
    ]);

    // Redirect ke daftar dengan pesan sukses
    return redirect('/catatan')->with('sukses', 'Catatan berhasil ditambahkan!');
}

Tampilkan flash message di catatan/index.blade.php:

@if(session('sukses'))
    <div style="background:#dcfce7;border:1px solid #16a34a;padding:12px 16px;border-radius:6px;margin-bottom:16px;color:#15803d;">
        ✓ {{ session('sukses') }}
    </div>
@endif

③ Form Edit & Update

public function edit($id)
{
    $catatan = Catatan::findOrFail($id);
    return view('catatan.edit', compact('catatan'));
}

public function update(Request $request, $id)
{
    $catatan = Catatan::findOrFail($id);

    $validated = $request->validate([
        'judul' => 'required|min:3|max:255',
        'isi'   => 'required|min:10',
    ]);

    $catatan->update([
        'judul'   => $validated['judul'],
        'isi'     => $validated['isi'],
        'penting' => $request->has('penting'),
    ]);

    return redirect('/catatan')->with('sukses', 'Catatan berhasil diperbarui!');
}

Buat resources/views/catatan/edit.blade.php. Form edit hampir sama dengan create, bedanya menggunakan method spoofing:

<form action="/catatan/{{ $catatan->id }}" method="POST">
    @csrf
    @method('PUT')  {{-- Laravel perlu ini karena HTML form hanya support GET & POST --}}

    <input type="text" name="judul" value="{{ old('judul', $catatan->judul) }}">
    <textarea name="isi">{{ old('isi', $catatan->isi) }}</textarea>
    <input type="checkbox" name="penting" value="1" {{ $catatan->penting ? 'checked' : '' }}>

    <button type="submit">Perbarui</button>
</form>

④ Hapus Data (Delete)

public function destroy($id)
{
    $catatan = Catatan::findOrFail($id);
    $catatan->delete();

    return redirect('/catatan')->with('sukses', 'Catatan berhasil dihapus.');
}

Tambahkan tombol hapus di daftar atau halaman detail. Karena DELETE tidak bisa dari link biasa, gunakan form mini:

<form action="/catatan/{{ $item->id }}" method="POST" style="display:inline;"
      onsubmit="return confirm('Yakin hapus catatan ini?')">
    @csrf
    @method('DELETE')
    <button type="submit" style="background:#dc2626;color:white;border:none;padding:6px 12px;border-radius:4px;cursor:pointer;">
        Hapus
    </button>
</form>

Referensi Aturan Validasi Tersering

RuleArti
requiredWajib diisi
min:3Minimal 3 karakter
max:255Maksimal 255 karakter
emailHarus format email
unique:users,emailHarus unik di tabel users kolom email
numericHarus angka
nullableBoleh kosong/null
confirmedHarus ada field _confirmation yang sama (untuk password)

Langkah Selanjutnya

Aplikasi catatan kamu sekarang sudah fungsional penuh! Tapi tampilannya masih setiap halaman memiliki HTML sendiri-sendiri yang duplikat. Di Part 6 — Layout Blade, kita akan membuat template layout yang digunakan bersama oleh semua halaman, dan menambahkan styling yang profesional.