Belajar Laravel paling cepat bukan dengan menghafal dokumentasi, melainkan dengan membangun sesuatu yang nyata. Dan proyek paling klasik untuk pemula adalah CRUD, singkatan dari Create, Read, Update, Delete, empat operasi dasar dalam mengelola data.
Dalam tutorial Laravel 12 ini, kamu akan membangun aplikasi pendataan produk sederhana dari nol: tambah data, tampilkan daftar, ubah data, dan hapus data. Semua langkah dijelaskan berurutan lengkap dengan contoh kode yang bisa langsung kamu praktikkan. Di akhir tutorial, kamu akan memahami alur kerja utama Laravel yaitu route, controller, model, migration, dan Blade. Kalau kamu benar-benar baru di dunia Laravel, baca juga panduan membuat project sederhana menggunakan Laravel untuk pengenalan awal yang lebih santai.
Apa Itu CRUD dan Kenapa Laravel Cocok untuk Mempelajarinya?
CRUD adalah fondasi hampir semua aplikasi web. Aplikasi kasir, sistem akademik, toko online, semuanya dibangun di atas empat operasi ini. Laravel sangat cocok untuk belajar CRUD karena menyediakan semua peralatannya secara bawaan: Eloquent ORM untuk database, Blade untuk tampilan, dan resource controller yang memetakan operasi CRUD ke method secara rapi.
Yang akan kita bangun adalah aplikasi Data Produk sederhana dengan field nama, deskripsi, harga, dan stok.

Prasyarat: Yang Perlu Disiapkan
Sebelum mulai, pastikan komputermu sudah memiliki:
- PHP 8.2 atau lebih baru (Laravel 12 membutuhkan minimal PHP 8.2). Cek dengan perintah
php -v. - Composer, package manager PHP. Cek dengan
composer --version. - MySQL atau MariaDB yang sudah berjalan. Kamu juga bisa memakai SQLite untuk latihan cepat.
- Teks editor seperti VS Code.
Jika semua sudah siap, mari mulai langkah pertama.
Langkah 1: Instalasi Laravel 12
Buka terminal, lalu jalankan perintah berikut untuk membuat proyek baru bernama toko-sederhana:
composer create-project laravel/laravel:^12.0 toko-sederhana
cd toko-sederhana
Tunggu proses instalasi selesai. Setelah itu, jalankan server development bawaan Laravel:
php artisan serve
Buka browser dan akses http://127.0.0.1:8000. Jika halaman selamat datang Laravel muncul, instalasi berhasil.
Langkah 2: Konfigurasi Database
Buka file .env di folder proyek, lalu sesuaikan pengaturan database dengan milikmu:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=toko_sederhana
DB_USERNAME=root
DB_PASSWORD=
Buat database kosong bernama toko_sederhana di MySQL terlebih dahulu, misalnya lewat phpMyAdmin atau perintah SQL CREATE DATABASE toko_sederhana;.
Langkah 3: Membuat Model, Migration, dan Controller Sekaligus
Salah satu keunggulan Laravel adalah perintah artisan yang bisa menghasilkan beberapa file sekaligus. Untuk fitur produk, kita butuh model Product, file migration untuk tabelnya, dan controller. Cukup satu perintah:
php artisan make:model Product -mcr
Arti flag-nya: -m membuat migration, -c membuat controller, -r membuat controller bertipe resource (sudah berisi method CRUD standar). Perintah ini menghasilkan tiga file:
app/Models/Product.phpdatabase/migrations/xxxx_xx_xx_xxxxxx_create_products_table.phpapp/Http/Controllers/ProductController.php
Langkah 4: Menulis Migration untuk Tabel Products
Buka file migration yang baru dibuat, lalu definisikan struktur tabel di dalam method up:
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description')->nullable();
$table->decimal('price', 12, 2);
$table->integer('stock')->default(0);
$table->timestamps();
});
}
Setelah itu jalankan migration untuk membuat tabelnya di database:
php artisan migrate
Jika berhasil, tabel products beserta kolomnya sudah tersedia.
Langkah 5: Mengatur Model Product
Buka app/Models/Product.php dan tambahkan properti $fillable. Properti ini menentukan kolom mana saja yang boleh diisi secara massal, sekaligus melindungi dari celah mass assignment:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $fillable = ['name', 'description', 'price', 'stock'];
}
Langkah 6: Menulis Logika CRUD di Controller
Inilah bagian inti tutorial. Buka app/Http/Controllers/ProductController.php dan isi ketujuh method resource sebagai berikut:
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
// READ: tampilkan semua produk
public function index()
{
$products = Product::latest()->paginate(10);
return view('products.index', compact('products'));
}
// CREATE: tampilkan form tambah
public function create()
{
return view('products.create');
}
// CREATE: simpan data baru
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'description' => 'nullable|string',
'price' => 'required|numeric|min:0',
'stock' => 'required|integer|min:0',
]);
Product::create($validated);
return redirect()->route('products.index')
->with('success', 'Produk berhasil ditambahkan.');
}
// READ: tampilkan satu produk
public function show(Product $product)
{
return view('products.show', compact('product'));
}
// UPDATE: tampilkan form edit
public function edit(Product $product)
{
return view('products.edit', compact('product'));
}
// UPDATE: simpan perubahan
public function update(Request $request, Product $product)
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'description' => 'nullable|string',
'price' => 'required|numeric|min:0',
'stock' => 'required|integer|min:0',
]);
$product->update($validated);
return redirect()->route('products.index')
->with('success', 'Produk berhasil diperbarui.');
}
// DELETE: hapus produk
public function destroy(Product $product)
{
$product->delete();
return redirect()->route('products.index')
->with('success', 'Produk berhasil dihapus.');
}
}
Perhatikan dua hal penting di kode ini. Pertama, $request->validate() memastikan data yang masuk sudah benar sebelum disimpan. Kedua, Laravel otomatis mengubah parameter Product $product menjadi data produk yang sesuai berdasarkan ID di URL. Fitur ini namanya route model binding.
Langkah 7: Mendaftarkan Route
Buka routes/web.php dan daftarkan satu baris route resource. Satu baris ini otomatis membuat semua URL dan nama route untuk ketujuh method di atas:
use App\Http\Controllers\ProductController;
Route::resource('products', ProductController::class);
Dengan ini kamu mendapatkan URL seperti /products (daftar), /products/create (form tambah), /products/{id}/edit (form ubah), dan seterusnya.
Langkah 8: Membuat Tampilan dengan Blade
Buat folder resources/views/products, lalu buat file-file berikut.
Layout dasar (resources/views/layouts/app.blade.php):
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Data Produk</title>
<style>
body { font-family: sans-serif; max-width: 900px; margin: 2rem auto; padding: 0 1rem; }
table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background: #f4f4f4; }
.alert { background: #d4edda; padding: 10px; border-radius: 4px; margin-bottom: 1rem; }
.btn { display: inline-block; padding: 6px 12px; border-radius: 4px; text-decoration: none; }
.btn-primary { background: #0d6efd; color: #fff; }
.btn-warning { background: #ffc107; color: #000; }
.btn-danger { background: #dc3545; color: #fff; border: none; cursor: pointer; }
form div { margin-bottom: 12px; }
label { display: block; margin-bottom: 4px; font-weight: bold; }
input, textarea { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; }
.error { color: #dc3545; font-size: 0.9em; }
</style>
</head>
<body>
<h1>Aplikasi Data Produk</h1>
@if (session('success'))
<div class="alert">{{ session('success') }}</div>
@endif
@yield('content')
</body>
</html>
Daftar produk (resources/views/products/index.blade.php):
@extends('layouts.app')
@section('content')
<a href="{{ route('products.create') }}" class="btn btn-primary">Tambah Produk</a>
<table>
<thead>
<tr>
<th>Nama</th>
<th>Harga</th>
<th>Stok</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
@forelse ($products as $product)
<tr>
<td>{{ $product->name }}</td>
<td>Rp {{ number_format($product->price, 0, ',', '.') }}</td>
<td>{{ $product->stock }}</td>
<td>
<a href="{{ route('products.edit', $product) }}" class="btn btn-warning">Ubah</a>
<form action="{{ route('products.destroy', $product) }}" method="POST" style="display:inline">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger"
onclick="return confirm('Hapus produk ini?')">Hapus</button>
</form>
</td>
</tr>
@empty
<tr><td colspan="4">Belum ada data produk.</td></tr>
@endforelse
</tbody>
</table>
{{ $products->links() }}
@endsection
Form tambah (resources/views/products/create.blade.php):
@extends('layouts.app')
@section('content')
<h2>Tambah Produk Baru</h2>
<form action="{{ route('products.store') }}" method="POST">
@csrf
<div>
<label>Nama Produk</label>
<input type="text" name="name" value="{{ old('name') }}">
@error('name') <div class="error">{{ $message }}</div> @enderror
</div>
<div>
<label>Deskripsi</label>
<textarea name="description">{{ old('description') }}</textarea>
</div>
<div>
<label>Harga</label>
<input type="number" name="price" value="{{ old('price') }}">
@error('price') <div class="error">{{ $message }}</div> @enderror
</div>
<div>
<label>Stok</label>
<input type="number" name="stock" value="{{ old('stock', 0) }}">
@error('stock') <div class="error">{{ $message }}</div> @enderror
</div>
<button type="submit" class="btn btn-primary">Simpan</button>
</form>
@endsection
Form ubah (resources/views/products/edit.blade.php): salin file create.blade.php, lalu ubah dua hal: action form menjadi route('products.update', $product) dan tambahkan @method('PUT') tepat di bawah @csrf. Isi value setiap input dengan data lama, contohnya value="{{ old('name', $product->name) }}".
Tiga hal penting pada form Blade: @csrf wajib ada untuk keamanan, @method('PUT') dan @method('DELETE') diperlukan karena browser hanya mendukung GET dan POST, dan @error menampilkan pesan validasi dari controller.
Langkah 9: Uji Aplikasi
Pastikan server masih berjalan (php artisan serve), lalu buka http://127.0.0.1:8000/products. Coba alurnya satu per satu: tambah produk baru, lihat daftarnya, ubah datanya, lalu hapus. Jika pesan sukses muncul dan data berubah sesuai harapan, selamat, CRUD Laravel 12 pertamamu sudah jadi.
Memahami Alur Kerja: Dari URL Sampai ke Browser
Agar tidak sekadar menyalin kode, pahami alur yang terjadi setiap kali kamu membuka halaman. Misalnya saat mengakses /products:
- Route menerima permintaan dan meneruskannya ke method
indexdiProductController. - Controller meminta data ke model
Product, yang mengambilnya dari tabelproductslewat Eloquent. - Controller mengirim data tersebut ke view
products.index. - Blade menggabungkan view dengan layout, lalu hasilnya dikirim kembali ke browser sebagai HTML.
Alur yang sama berlaku untuk semua operasi. Form tambah mengirim POST ke method store, form ubah mengirim PUT ke method update, dan tombol hapus mengirim DELETE ke method destroy. Kalau kamu hafal alur empat tahap ini, debugging aplikasi Laravel akan jauh lebih mudah karena kamu selalu tahu di lapisan mana masalah terjadi.
Kesalahan Umum Pemula dan Cara Mengatasinya
SQLSTATE Access denied. Periksa kembali DB_USERNAME, DB_PASSWORD, dan nama database di file .env. Setelah mengubah .env, tidak perlu restart apapun kecuali config di-cache.
MassAssignmentException. Kamu lupa menambahkan kolom ke $fillable di model. Tambahkan nama kolom yang error ke array tersebut.
Halaman 404 saat buka /products. Pastikan route resource sudah didaftarkan di routes/web.php dan tidak ada typo pada nama controller.
Perubahan tidak tersimpan. Cek validasi di controller. Jika validasi gagal, Laravel mengembalikan ke form sebelumnya beserta pesan error, jadi perhatikan bagian @error di Blade.
FAQ: Pertanyaan Seputar CRUD Laravel
Apa itu CRUD dalam Laravel?
CRUD adalah empat operasi dasar pengelolaan data yaitu Create (membuat), Read (membaca), Update (mengubah), dan Delete (menghapus). Di Laravel, keempatnya dipetakan rapi ke dalam resource controller dengan tujuh method standar.
Apakah tutorial ini bisa dipakai untuk Laravel 11?
Bisa, dengan sedikit penyesuaian. Struktur dasar resource controller, migration, dan Blade hampir sama. Namun beberapa detail seperti persyaratan versi PHP bisa berbeda, jadi sesuaikan dengan dokumentasi versi yang kamu pakai.
Apakah harus bisa PHP dulu sebelum belajar Laravel?
Sangat disarankan memahami dasar PHP seperti variabel, fungsi, array, dan konsep OOP (class dan object). Tanpa dasar itu, kode Laravel akan terasa seperti sulap.
Bagaimana cara menampilkan pesan error validasi?
Gunakan directive @error('nama_field') di file Blade tepat di bawah input yang bersangkutan. Laravel otomatis mengirim pesan error kembali ke form jika validasi di controller gagal.
Apa langkah selanjutnya setelah menguasai CRUD?
Pelajari autentikasi (login dan register), relasi antar tabel di Eloquent, upload file, dan pembuatan REST API. REST API adalah kelanjutan alami karena pola controller-nya mirip dengan yang baru saja kamu pelajari.
Penutup
Kamu baru saja membangun aplikasi CRUD lengkap di Laravel 12: instalasi, migration, model, resource controller, route, dan tampilan Blade. Pola ini akan terus kamu temui di hampir semua proyek Laravel, jadi pastikan kamu benar-benar memahaminya sebelum lanjut.
Langkah alami berikutnya adalah mengubah CRUD ini menjadi REST API, karena pola controller-nya sangat mirip. Baca juga panduan kami tentang cara membuat REST API dengan Laravel untuk melanjutkan perjalanan belajarmu.