Cara Membuat Fitur Filter Data di Laravel

Fitur filter dan pencarian data adalah kebutuhan yang sangat umum dalam aplikasi web — dari filter produk di e-commerce hingga pencarian laporan di sistem manajemen. Di Laravel, ad...

Cara Membuat Fitur Filter Data di Laravel

Fitur filter dan pencarian data adalah kebutuhan yang sangat umum dalam aplikasi web — dari filter produk di e-commerce hingga pencarian laporan di sistem manajemen. Di Laravel, ada beberapa cara untuk mengimplementasikannya, mulai dari yang paling sederhana hingga yang paling terstruktur. Artikel ini akan mengajarkan kamu pola filter data yang bersih, mudah diperluas, dan tidak mengotori controller.

Pendekatan Sederhana: Filter Langsung di Controller

Cara paling dasar adalah menggunakan kondisional di query builder. Cocok untuk filter yang tidak terlalu banyak:

<?php

namespace App\Http\Controllers;

use App\Models\Product;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    public function index(Request $request)
    {
        $query = Product::query();

        // Filter berdasarkan nama (pencarian)
        if ($request->filled('search')) {
            $query->where('name', 'like', '%' . $request->search . '%');
        }

        // Filter berdasarkan kategori
        if ($request->filled('category_id')) {
            $query->where('category_id', $request->category_id);
        }

        // Filter range harga
        if ($request->filled('min_price')) {
            $query->where('price', '>=', $request->min_price);
        }
        if ($request->filled('max_price')) {
            $query->where('price', '<=', $request->max_price);
        }

        // Sorting
        $sortBy  = $request->get('sort_by', 'created_at');
        $sortDir = $request->get('sort_dir', 'desc');
        $allowedSorts = ['name', 'price', 'created_at'];

        if (in_array($sortBy, $allowedSorts)) {
            $query->orderBy($sortBy, $sortDir === 'asc' ? 'asc' : 'desc');
        }

        $products = $query->paginate(15)->withQueryString();

        return view('products.index', compact('products'));
    }
}

Membuat Form Filter di Blade

<form method="GET" action="{{ route('products.index') }}">
    <input type="text" name="search" value="{{ request('search') }}" placeholder="Cari produk...">

    <select name="category_id">
        <option value="">Semua Kategori</option>
        @foreach($categories as $cat)
            <option value="{{ $cat->id }}" {{ request('category_id') == $cat->id ? 'selected' : '' }}>
                {{ $cat->name }}
            </option>
        @endforeach
    </select>

    <input type="number" name="min_price" value="{{ request('min_price') }}" placeholder="Harga min">
    <input type="number" name="max_price" value="{{ request('max_price') }}" placeholder="Harga maks">

    <button type="submit">Filter</button>
    <a href="{{ route('products.index') }}">Reset</a>
</form>

Gunakan withQueryString() pada paginator agar parameter filter tetap ada saat berpindah halaman.

Pendekatan Lebih Bersih: Local Scope di Model

Untuk filter yang reusable, gunakan Eloquent local scope:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    public function scopeSearch(Builder $query, ?string $search): Builder
    {
        return $query->when($search, function ($q) use ($search) {
            $q->where('name', 'like', "%{$search}%")
              ->orWhere('description', 'like', "%{$search}%");
        });
    }

    public function scopeCategory(Builder $query, ?int $categoryId): Builder
    {
        return $query->when($categoryId, fn($q) => $q->where('category_id', $categoryId));
    }

    public function scopePriceRange(Builder $query, ?float $min, ?float $max): Builder
    {
        return $query
            ->when($min, fn($q) => $q->where('price', '>=', $min))
            ->when($max, fn($q) => $q->where('price', '<=', $max));
    }
}

Penggunaan di controller menjadi sangat bersih:

$products = Product::query()
    ->search($request->search)
    ->category($request->category_id)
    ->priceRange($request->min_price, $request->max_price)
    ->latest()
    ->paginate(15)
    ->withQueryString();

Pendekatan Profesional: Filter Class Terpisah

Untuk aplikasi berskala besar dengan banyak filter, buat kelas filter tersendiri agar controller tetap tipis:

<?php
// app/Filters/ProductFilter.php

namespace App\Filters;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;

class ProductFilter
{
    public function __construct(protected Request $request) {}

    public function apply(Builder $query): Builder
    {
        if ($this->request->filled('search')) {
            $search = $this->request->search;
            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                  ->orWhere('sku', $search);
            });
        }

        if ($this->request->filled('category_id')) {
            $query->where('category_id', $this->request->category_id);
        }

        if ($this->request->filled('min_price')) {
            $query->where('price', '>=', $this->request->min_price);
        }

        if ($this->request->filled('max_price')) {
            $query->where('price', '<=', $this->request->max_price);
        }

        if ($this->request->filled('in_stock')) {
            $query->where('stock', '>', 0);
        }

        return $query;
    }
}

Gunakan di controller dengan inject:

use App\Filters\ProductFilter;

public function index(Request $request, ProductFilter $filter)
{
    $products = $filter->apply(Product::query())
        ->latest()
        ->paginate(15)
        ->withQueryString();

    return view('products.index', compact('products'));
}

Menjaga State Filter di View

Pastikan nilai filter tetap terisi setelah form disubmit dengan menggunakan helper request():

<input type="text"
       name="search"
       value="{{ request('search') }}"
       placeholder="Cari nama atau SKU...">

Kesimpulan

Pilih pendekatan yang sesuai dengan kompleksitas proyekmu. Untuk filter sederhana, langsung di controller sudah cukup. Untuk yang lebih kompleks dan reusable, gunakan local scope di model. Jika filter sudah sangat banyak dan perlu digunakan di banyak tempat, pisahkan ke kelas Filter tersendiri. Dengan pola yang tepat, fitur filter kamu akan mudah diperluas dan dipelihara tanpa mengotori kode di mana-mana.

filter data laravel laravel query filter eloquent scope laravel laravel search filter filter tabel laravel query builder laravel
Rekomendasi

Hosting Cepat untuk Website & Laravel

Butuh hosting yang ngebut dan stabil untuk deploy website atau aplikasi Laravel-mu? Ini rekomendasi yang saya pakai.

Lihat Rekomendasi Hosting
Yudhi
Ditulis oleh

Yudhi

Web Developer

Web developer yang sehari-hari berkutat dengan PHP, Laravel, JavaScript, dan MySQL. Terbiasa membangun aplikasi web dari nol — merancang database, menulis fitur, memburu bug, hingga deploy ke server — lalu menuangkan solusi dan tutorialnya di DhieCoderWeb agar lebih mudah diikuti developer lain.

Bagikan artikel
Kembali

Komentar (0)

Punya pertanyaan atau tambahan? Tulis di bawah — tak perlu login.

Membalas komentar… batal

Belum ada komentar. Jadilah yang pertama!

🚀 Partner Recommendation

Butuh Source Code & Aplikasi Premium?

Download aplikasi Laravel, POS, Sekolah, Klinik, ERP, dan source code siap pakai di GudangCode.

GudangCode
  • ✔ Source Code Premium
  • ✔ Sistem Siap Pakai
  • ✔ Lifetime Update
  • ✔ Membership Lifetime
  • ✔ Update Aplikasi Harian
Daftar Membership →