Relasi category() dan posts() sudah kita definisikan sejak episode 8, tapi sejauh ini cuma dipakai untuk menampilkan nama kategori di satu post. Episode ini kita buktikan sisi sebaliknya: dari satu kategori, tampilkan semua post di dalamnya — inilah makna sesungguhnya dari relasi "one to many".
Halaman filter kategori menampilkan semua post dalam satu kategori.
Membuat CategoryController
php artisan make:controller CategoryController
Controller ini cuma butuh satu method:
class CategoryController extends Controller
{
public function show(Category $category)
{
$posts = $category->posts()->latest()->get();
return view('categories.show', compact('category', 'posts'));
}
}
Perhatikan $category->posts() — ini memanggil method relasi hasMany yang sudah kita definisikan di model Category sejak episode 8. Karena dipanggil dengan (), ini mengembalikan query builder (bukan collection langsung), sehingga kita masih bisa chain ->latest() sebelum ->get().
Route
Route::get('/categories/{category}', [CategoryController::class, 'show'])->name('categories.show');
Sama seperti Post $post di PostController, Category $category di sini juga pakai route model binding — Laravel otomatis resolve dari {category} di URL.
View categories/show.blade.php
@extends('layouts.app')
@section('content')
<h1>Category: {{ $category->name }}</h1>
@forelse ($posts as $post)
<div class="border-bottom py-3">
<h2 class="h5 mb-1">
<a href="{{ route('posts.show', $post) }}">{{ $post->title }}</a>
</h2>
</div>
@empty
<x-alert type="info">No posts in this category yet.</x-alert>
@endforelse
@endsection
Menghubungkan dari halaman post
Supaya fitur ini bisa ditemukan user, kita jadikan nama kategori di halaman list dan detail post sebagai link:
@if ($post->category)
<a href="{{ route('categories.show', $post->category) }}">{{ $post->category->name }}</a>
@else
Uncategorized
@endif
Kenapa ini penting dipahami
Ini contoh nyata kenapa Eloquent relationship powerful: kita tidak menulis SQL JOIN sama sekali untuk fitur ini. Method posts() di model Category yang sudah kita tulis di episode 8 langsung bisa dipakai ulang di konteks yang berbeda — sekali definisikan relasi, pakai di mana saja.
Testing
php artisan tinker --execute="
\$cat = App\Models\Category::first();
echo \$cat->posts()->count();
"
Lalu buka http://laravel13-blog-dasar.test/categories/1 di browser — harus muncul semua post yang punya category_id = 1.
Selanjutnya
Dengan 15 post di database, scroll panjang tanpa henti mulai terasa tidak praktis. Episode berikutnya kita tambahkan search dan pagination.