CRUD adalah singkatan dari Create, Read, Update, Delete: empat operasi dasar pada data. Hampir setiap aplikasi web berisi CRUD, baik untuk produk, artikel, maupun pengguna. Pada tutorial ini kita membuat CRUD Artikel di Laravel dari awal sampai bisa dipakai.
Prasyarat: Laravel sudah terpasang dan terhubung ke database (aturDB_*di file.env).
Langkah 1: Membuat model, migration, dan controller
php artisan make:model Post -mc --resource
Perintah ini membuat app/Models/Post.php, file migration, dan PostController berisi method resource (index, create, store, show, edit, update, destroy).
Langkah 2: Mendefinisikan tabel
Buka file migration di database/migrations/ lalu isi method up():
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('body');
$table->timestamps();
});
Jalankan:
php artisan migrate
Langkah 3: Mengatur model
Agar kolom boleh diisi secara massal (create dan update), daftarkan di $fillable:
class Post extends Model
{
protected $fillable = ['title', 'body'];
}
Ini adalah perlindungan mass assignment: hanya kolom yang kamu daftarkan yang boleh diisi dari input pengguna.
Langkah 4: Mendaftarkan route
Di routes/web.php, satu baris cukup untuk membuat ketujuh route CRUD:
use App\Http\Controllers\PostController;
Route::resource('posts', PostController::class);
Lihat daftarnya dengan php artisan route:list.
Langkah 5: Menulis controller
class PostController extends Controller
{
public function index()
{
$posts = Post::latest()->paginate(10);
return view('posts.index', compact('posts'));
}
public function create()
{
return view('posts.create');
}
public function store(Request $request)
{
$data = $request->validate([
'title' => 'required|max:150',
'body' => 'required',
]);
Post::create($data);
return redirect()->route('posts.index')
->with('success', 'Artikel berhasil dibuat.');
}
public function edit(Post $post)
{
return view('posts.edit', compact('post'));
}
public function update(Request $request, Post $post)
{
$data = $request->validate([
'title' => 'required|max:150',
'body' => 'required',
]);
$post->update($data);
return redirect()->route('posts.index')
->with('success', 'Artikel berhasil diperbarui.');
}
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('posts.index')
->with('success', 'Artikel dihapus.');
}
}
Beberapa hal penting:
Post $postpada parameter memakai route model binding: Laravel otomatis mengambil data berdasarkan ID di URL dan menampilkan 404 jika tidak ada.validate()menghentikan proses dan mengembalikan pengguna ke form beserta pesan error jika data tidak valid.paginate(10)membagi hasil menjadi halaman berisi 10 data.
Langkah 6: Membuat view
Buat resources/views/posts/index.blade.php:
@if (session('success'))
<p>{{ session('success') }}</p>
@endif
<a href="{{ route('posts.create') }}">Tambah artikel</a>
<table>
@foreach ($posts as $post)
<tr>
<td>{{ $post->title }}</td>
<td>
<a href="{{ route('posts.edit', $post) }}">Ubah</a>
<form method="POST" action="{{ route('posts.destroy', $post) }}"
>
@csrf
@method('DELETE')
<button>Hapus</button>
</form>
</td>
</tr>
@endforeach
</table>
{{ $posts->links() }}
Dan form di posts/create.blade.php:
<form method="POST" action="{{ route('posts.store') }}">
@csrf
<input name="title" value="{{ old('title') }}">
@error('title') <small>{{ $message }}</small> @enderror
<textarea name="body">{{ old('body') }}</textarea>
@error('body') <small>{{ $message }}</small> @enderror
<button>Simpan</button>
</form>
Catatan wajib:
@csrfmelindungi form dari serangan CSRF. Tanpa itu Laravel menolak permintaan (error 419).- HTML hanya mengenal GET dan POST, sehingga
@method('DELETE')dan@method('PUT')dipakai untuk "meminjam" method lain. {{ }}otomatis meng-escape HTML sehingga aman dari XSS.old('title')mempertahankan isian saat validasi gagal.
Kesalahan yang paling sering terjadi
| Gejala | Penyebab umum |
|---|---|
419 Page Expired | Lupa @csrf di form |
MassAssignmentException | Kolom belum masuk $fillable |
405 Method Not Allowed | Lupa @method('PUT'/'DELETE') |
Column not found | Migration belum dijalankan atau nama kolom salah |
| Data tidak berubah | Kolom tidak ada di input atau $fillable |
Pengembangan lanjutan
- Pindahkan aturan validasi ke Form Request (
php artisan make:request StorePostRequest). - Tambahkan pencarian dan filter dengan
when()pada query. - Tambahkan upload gambar dengan
$request->file('image')->store('posts', 'public'). - Batasi akses dengan middleware
authdan policy. - Gunakan soft delete agar data yang dihapus bisa dipulihkan.
Mengatur layout agar tidak menyalin HTML
Alih-alih mengulang <html>, <head>, dan navigasi di setiap view, buat satu layout:
{{-- resources/views/layouts/app.blade.php --}}
<!doctype html>
<html>
<head><title>@yield('title')</title></head>
<body>
<nav>...</nav>
@yield('content')
</body>
</html>
{{-- resources/views/posts/index.blade.php --}}
@extends('layouts.app')
@section('title', 'Daftar Artikel')
@section('content')
...isi halaman...
@endsection
Menambahkan pencarian
public function index(Request $request)
{
$posts = Post::query()
->when($request->q, fn ($query, $q) => $query->where('title', 'like', "%{$q}%"))
->latest()
->paginate(10)
->withQueryString(); // pencarian tetap ada saat pindah halaman
return view('posts.index', compact('posts'));
}
when() hanya menambah kondisi bila q terisi, sehingga kode tidak berantakan oleh if.
Upload gambar pada CRUD
Tambahkan kolom image (nullable) di migration, ubah form menjadi enctype="multipart/form-data", lalu:
$data = $request->validate([
'title' => 'required|max:150',
'body' => 'required',
'image' => 'nullable|image|max:2048',
]);
if ($request->hasFile('image')) {
$data['image'] = $request->file('image')->store('posts', 'public');
}
Jangan lupa php artisan storage:link, dan hapus berkas lama saat gambar diganti atau data dihapus.
Merapikan dengan Form Request
php artisan make:request PostRequest
class PostRequest extends FormRequest
{
public function authorize(): bool { return true; }
public function rules(): array
{
return [
'title' => ['required', 'max:150'],
'body' => ['required'],
];
}
public function messages(): array
{
return ['title.required' => 'Judul wajib diisi.'];
}
}
Lalu controller cukup menulis store(PostRequest $request) dan memakai $request->validated(). Aturan yang sama dipakai untuk store dan update.
Latihan untuk menguatkan pemahaman
- Tambahkan kolom
slugdan tampilkan artikel lewat URL/posts/judul-artikel. - Tambahkan fitur filter berdasarkan kategori (butuh relasi, lihat Mengenal Eloquent Relationship).
- Batasi agar hanya pengguna yang login yang boleh membuat dan menghapus (Membuat Authentication Laravel).
- Ubah penghapusan menjadi soft delete dan buat halaman "sampah" untuk memulihkan data.
- Buat versi API-nya dengan
Route::apiResource(Membuat REST API dengan Laravel).
Kesimpulan
Alur CRUD Laravel selalu sama: migration → model → route → controller → view. Setelah memahaminya sekali, kamu bisa membuat modul apa pun dengan pola yang identik.
Komentar (0)
Masuk / Daftar