Sampai episode ini, kamu sudah tahu cara membuat route, controller, dan model dengan Eloquent. Sekarang saatnya menggabungkan semuanya dalam satu fitur CRUD yang lengkap dan proper — bukan asal jalan, tapi punya validasi yang ketat dan feedback user yang jelas.
Kita akan membangun fitur "Posts" (blog post) dari awal: dari form create di Blade, submit ke controller, validasi server-side, simpan ke database, tampilkan list, edit, dan delete. Semua tanpa perlu install library eksternal — kekuatan Laravel sudah cukup.
Menyiapkan Resource Route dan Controller
Langkah pertama adalah setup route. Di Laravel, ada cara smart untuk membuat CRUD route sekaligus: Resource Route. Buka file routes/web.php dan tambahkan baris ini:
Route::resource('posts', PostController::class);Satu baris itu akan generate 7 route otomatis:
GET /posts→ index (tampilkan list)GET /posts/create→ create (form buat post baru)POST /posts→ store (terima form, simpan ke DB)GET /posts/{id}→ show (detail satu post)GET /posts/{id}/edit→ edit (form edit)PUT /posts/{id}→ update (terima form edit, update DB)DELETE /posts/{id}→ destroy (hapus post)
Sekarang buat controller dengan artisan command:
php artisan make:controller PostController --resourceFlag --resource akan generate template controller dengan semua method CRUD yang diperlukan. Cek di app/Http/Controllers/PostController.php — sudah ada skeleton method index(), create(), store(), update(), destroy(), dan teman-temannya.
Membuat Model dan Migration
Sebelum bikin form, kita perlu table di database. Buat model Post dengan migration sekaligus:
php artisan make:model Post --migrationBuka migration file (di database/migrations/, cari file terbaru untuk Posts), lalu edit method up():
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->string('slug')->unique();
$table->timestamps();
});Kolom title untuk judul, content untuk isi, slug untuk URL-friendly identifier. Sekarang jalankan migration:
php artisan migrateTabel posts sudah siap di database kamu.
Form Create Post dengan CSRF Protection
Buat file view untuk form create di resources/views/posts/create.blade.php. Struktur folder harus posts/ di dalam views:
<form action="{{ route('posts.store') }}" method="POST">
@csrf
<div>
<label for="title">Judul Post</label>
<input type="text" id="title" name="title" value="{{ old('title') }}">
@error('title')
<span style="color: red;">{{ $message }}</span>
@enderror
</div>
<div>
<label for="content">Isi</label>
<textarea id="content" name="content">{{ old('content') }}</textarea>
@error('content')
<span style="color: red;">{{ $message }}</span>
@enderror
</div>
<button type="submit">Buat Post</button>
</form>Perhatian penting: @csrf adalah Blade directive yang generate CSRF token. Ini adalah langkah keamanan wajib — Laravel akan reject POST request yang tidak punya token ini. Lihat dokumentasi CSRF Laravel untuk penjelasan detail.
Directive @error adalah Blade control structure untuk menampilkan pesan error validasi kalau ada. Kita bahas di section berikutnya.
Validasi Input dengan Rules Laravel
Di controller PostController.php, isi method store():
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string|min:10',
]);
// Generate slug dari title
$validated['slug'] = Str::slug($validated['title']);
Post::create($validated);
return redirect()->route('posts.index')->with('success', 'Post berhasil dibuat!');
}Method validate() adalah fitur powerful bawaan Laravel. Setiap key di array adalah nama input, nilainya adalah "rules" — kondisi yang harus dipenuhi:
required→ field wajib diisistring→ harus teks, bukan angka atau filemax:255→ maksimal 255 karaktermin:10→ minimal 10 karakter (untuk content, agar tidak post kosong)
Kalau validasi gagal, Laravel otomatis redirect balik ke form dan share error message yang bisa diakses di Blade via @error. Kalau lolos, data disimpan ke database.
Jangan lupa import class Str di bagian atas controller:
use Illuminate\Support\Str;Untuk referensi lengkap semua rules validasi, baca dokumentasi validation Laravel.
Menampilkan List Posts (Index)
Di method index():
public function index()
{
$posts = Post::all();
return view('posts.index', ['posts' => $posts]);
}Buat view resources/views/posts/index.blade.php:
<h1>Daftar Posts</h1>
<a href="{{ route('posts.create') }}">Buat Post Baru</a>
@if ($posts->isEmpty())
<p>Belum ada post.</p>
@else
<ul>
@foreach ($posts as $post)
<li>
<h3>{{ $post->title }}</h3>
<p>{{ Str::limit($post->content, 100) }}</p>
<a href="{{ route('posts.show', $post->id) }}">Lihat Detail</a>
<a href="{{ route('posts.edit', $post->id) }}">Edit</a>
<form action="{{ route('posts.destroy', $post->id) }}" method="POST" style="display:inline;">
@csrf
@method('DELETE')
<button type="submit" onclick="return confirm('Yakin?')">Hapus</button>
</form>
</li>
@endforeach
</ul>
@endifPerhatian: untuk DELETE request, kita pakai @method('DELETE') karena HTML form hanya support GET dan POST. Blade directive ini men-spoof HTTP method.
Update dan Delete Data
Method edit() menampilkan form edit (form yang pre-filled dengan data lama):
public function edit(Post $post)
{
return view('posts.edit', ['post' => $post]);
}View posts/edit.blade.php hampir mirip dengan create, tapi action-nya ke route posts.update dan method PUT:
<form action="{{ route('posts.update', $post->id) }}" method="POST">
@csrf
@method('PUT')
<input type="text" name="title" value="{{ old('title', $post->title) }}">
<textarea name="content">{{ old('content', $post->content) }}</textarea>
<button type="submit">Simpan Perubahan</button>
</form>Method update():
public function update(Request $request, Post $post)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string|min:10',
]);
$validated['slug'] = Str::slug($validated['title']);
$post->update($validated);
return redirect()->route('posts.show', $post->id)->with('success', 'Post updated!');
}Method destroy() untuk delete:
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('posts.index')->with('success', 'Post deleted!');
}Menampilkan Error Validasi di Blade
Sudah disinggung di form, tapi mari perjelas: kalau validasi gagal, Laravel share variable $errors (instance MessageBag) ke view. Di Blade, kita akses via:
@error('title')
<span>{{ $message }}</span>
@enderrorAtau kalau mau menampilkan semua error sekaligus:
@if ($errors->any())
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
@endifDirective old() di input juga penting — kalau form gagal validasi, value yang user ketik akan tetap muncul di form, sehingga user tidak perlu mengetik ulang dari awal.
Hasil Akhir: Mini Blog Sederhana Kamu
Selamat! Sekarang kamu punya aplikasi CRUD lengkap yang bisa:
- Menampilkan daftar semua post
- Membuat post baru dengan form yang aman (CSRF protection)
- Validasi input di server-side — judul wajib, isi minimal 10 karakter
- Edit post yang sudah ada
- Hapus post dengan konfirmasi
- Tampilkan pesan sukses setelah aksi (dengan
with('success', '...'))
Ini adalah "Hello World" yang proper di Laravel. Kamu sudah menggabungkan resource route, controller, model Eloquent (dari episode #6 tentang Eloquent ORM Laravel 13), form dengan Blade templating, dan validasi. Dari sini, kamu bisa extend ke fitur lebih kompleks: authorization (siapa yang boleh edit post?), soft delete, search, pagination, dan sebagainya.
Jangan skip validasi atau anggap opsional — di production, input user adalah musuh terbesar kamu. Selalu validasi di server-side. Di depan (JavaScript) bisa tambahan untuk UX, tapi server-side adalah garis pertahanan pertama.
Kesimpulan
CRUD di Laravel 13 terlihat banyak step, tapi sebenarnya flow-nya sangat terstruktur: route → controller → validation → database → view. Framework ini sudah provide semua tools yang kamu butuh tanpa perlu library tambahan. Dengan resource route, Eloquent model, dan built-in validation, kamu bisa bangun fitur data management dengan cepat dan aman.
Di episode berikutnya, kita akan tambah fitur seperti authentication (login/register), authorization (siapa yang boleh edit post sendiri), dan deployment. Sebelum itu, coba extend mini blog ini: tambah kategori post, user author, comment, atau search. Practice is the best teacher. Happy coding!