#13: Mengenal Relasi – Menghubungkan Tabel Berita dengan Kategori
Halo, Detektif Relasi!
Di tutorial sebelumnya, kita sudah membuat tabel news yang memiliki kolom category_id. Tapi apa gunanya kolom itu? Kolom inilah yang menjadi jembatan penghubung antara berita dan kategori. Di Laravel, kita bisa membuat relasi agar kita bisa dengan mudah mengambil nama kategori dari sebuah berita, atau mengambil semua berita dalam satu kategori. Mari kita pahami dengan cara yang menyenangkan!
- Memahami konsep relasi database (one-to-many) antara kategori dan berita.
- Menggunakan relasi yang sudah kita buat di model
NewsdanCategory. - Belajar Eager Loading agar pengambilan data lebih efisien.
- Menampilkan nama kategori di halaman daftar berita.
Analogi Relasi: Seperti Anak dan Ibunya
Bayangkan Kategori adalah seorang Ibu, dan Berita adalah anak-anaknya.
- Satu Ibu (kategori) bisa memiliki banyak anak (berita). Contoh: Kategori "Olahraga" bisa memiliki berita "Piala Dunia", "Olimpiade", dll.
- Setiap anak (berita) hanya memiliki satu Ibu (kategori). Contoh: Berita "Piala Dunia" pasti masuk ke kategori "Olahraga", bukan ke kategori lain.
Ini yang disebut one-to-many (satu ke banyak). Di Laravel, kita menggunakan hasMany di model Ibu, dan belongsTo di model Anak.
Langkah 1: Melihat Relasi yang Sudah Kita Buat
Kita sudah menyiapkan relasi di tutorial #12. Mari kita lihat kembali:
public function category()
{
return $this->belongsTo(Category::class);
}
Artinya: Sebuah berita "termasuk ke" (belongs to) satu kategori.
public function news()
{
return $this->hasMany(News::class);
}
Artinya: Sebuah kategori "memiliki banyak" (has many) berita.
🔧 Langkah 2: Menggunakan Relasi di Controller
Kita akan buat controller untuk berita. Tapi sebelum itu, mari kita coba relasi di tinker (terminal interaktif Laravel) agar lebih paham.
Buka terminal, pastikan di folder proyek, lalu jalankan:
php artisan tinker
Kemudian coba kode berikut:
// Ambil berita dengan ID 1 (pastikan ada)
$news = App\Models\News::find(1);
// Tampilkan judul berita
$news->title;
// Tampilkan nama kategori dari berita ini (menggunakan relasi)
$news->category->name;
// Ambil kategori dengan ID 1
$category = App\Models\Category::find(1);
// Tampilkan semua berita dalam kategori ini
$category->news;
Jika berhasil, kamu akan melihat nama kategori muncul. Keluar dari tinker dengan exit.
Langkah 3: Membuat Controller Berita Sederhana (Index)
Kita akan buat NewsController dengan method index() untuk menampilkan daftar berita beserta nama kategorinya.
Jalankan perintah:
php artisan make:controller NewsController
Buka app/Http/Controllers/NewsController.php dan isi:
<?php
namespace App\Http\Controllers;
use App\Models\News;
use Illuminate\Http\Request;
class NewsController extends Controller
{
public function index()
{
// Ambil semua berita, termasuk relasi kategori (Eager Loading)
$news = News::with('category')->latest()->paginate(10);
return view('news-index', compact('news'));
}
}
Penjelasan:
with('category')→ Eager Loading. Ini akan mengambil data kategori sekaligus saat mengambil berita, sehingga tidak perlu query terpisah untuk setiap berita. Lebih cepat dan efisien.latest()→ mengurutkan dari yang terbaru (berdasarkan created_at).paginate(10)→ menampilkan 10 berita per halaman.
Langkah 4: Membuat View untuk Daftar Berita
Isi dengan kode berikut:
<!DOCTYPE html>
<html>
<head>
<title>Daftar Berita</title>
<style>
body { font-family: 'Segoe UI', Arial; margin: 20px; background: #f0f2f5; }
.container { max-width: 1000px; margin: auto; background: white; padding: 20px; border-radius: 12px; }
h1 { color: #e67e22; }
table { width: 100%; border-collapse: collapse; }
th, td { border: 1px solid #ddd; padding: 10px; text-align: left; }
th { background: #e67e22; color: white; }
.btn { background: #007bff; color: white; padding: 8px 16px; text-decoration: none; border-radius: 5px; display: inline-block; margin-bottom: 15px; }
.badge { background: #28a745; color: white; padding: 2px 8px; border-radius: 20px; font-size: 0.8rem; }
</style>
</head>
<body>
<div class="container">
<h1>Daftar Berita</h1>
<a href="#" class="btn">+ Tambah Berita (nanti)</a>
@if ($news->count() > 0)
<table>
<thead>
<th>ID</th>
<th>Judul</th>
<th>Kategori</th>
<th>Slug</th>
<th>Dibuat</th>
</thead>
<tbody>
@foreach ($news as $item)
{{ $item->id }}
{{ $item->title }}
<span class="badge">{{ $item->category->name ?? 'Tanpa Kategori' }}</span>
{{ $item->slug }}
{{ $item->created_at->diffForHumans() }}
@endforeach
</tbody>
</table>
<div style="margin-top: 20px;">
{{ $news->links() }}
</div>
@else
<p>Belum ada berita. Yuk tambah berita pertama!</p>
@endif
</div>
</body>
</html>
Perhatikan baris {{ $item->category->name ?? 'Tanpa Kategori' }}. Ini adalah keajaiban relasi! Kita bisa mengakses nama kategori hanya dengan $item->category->name. Operator ?? adalah default jika kategori tidak ada (null).
Langkah 5: Menambahkan Rute untuk Daftar Berita
use App\Http\Controllers\NewsController;
Route::get('/berita', [NewsController::class, 'index'])->name('news.index');
Sekarang buka browser: http://localhost:8000/berita. Kamu akan melihat daftar berita yang sudah ada (jika ada) dengan nama kategori yang muncul. Hebat!
Memahami Eager Loading vs Lazy Loading
- Lazy Loading (tanpa
with): Jika kita hanya menulisNews::all(), lalu di view memanggil$news->category->name, Laravel akan menjalankan query tambahan untuk setiap berita (N+1 problem). Ini lambat jika banyak data. - Eager Loading (pakai
with('category')): Laravel hanya menjalankan 2 query: satu untuk berita, satu untuk semua kategori yang dibutuhkan. Jauh lebih cepat!
with() saat mengambil data yang memiliki relasi, terutama di halaman daftar.Relasi Sebaliknya: Menampilkan Berita dalam Halaman Kategori
Kita juga bisa membuat halaman khusus untuk melihat berita-berita dalam satu kategori. Contoh: /kategori/olahraga. Ini memanfaatkan relasi dari sisi kategori.
Di routes/web.php:
Route::get('/kategori/{slug}', [CategoryController::class, 'show'])->name('kategori.show');
Di CategoryController tambahkan method:
public function show($slug)
{
$category = Category::where('slug', $slug)->firstOrFail();
$news = $category->news()->latest()->paginate(10);
return view('kategori-show', compact('category', 'news'));
}
Di view, kamu bisa menampilkan $category->name dan daftar $news. Ini akan kita buat lengkap nanti di tutorial frontend.
Ringkasan Hari Ini
- ✅ Relasi one-to-many menghubungkan kategori (induk) dengan berita (anak).
- ✅ Di model, kita menggunakan
hasManydanbelongsTo. - ✅ Eager loading (
with()) membuat pengambilan data lebih efisien. - ✅ Kita bisa mengakses nama kategori dari berita dengan
$news->category->name. - ✅ Kita sudah membuat halaman daftar berita yang menampilkan nama kategori.
Apa Selanjutnya?
Sekarang kita sudah paham relasi. Selanjutnya kita akan membuat CRUD lengkap untuk berita: form tambah berita dengan pilihan kategori (dropdown), upload gambar, edit, dan hapus. Setelah itu, kita akan membangun halaman depan website yang bisa dibaca oleh pengunjung (frontend). Terus semangat!
Seri Tutorial Laravel 13 Pemula – Proyek Web Berita
✨ Selanjutnya: #14: Membuat Upload Gambar – Menyimpan File Gambar Berita dengan Storage Laravel