Membuat Fitur Search + Pagination

Di tulisan sebelumnya, saya pernah membahas pagination dengan lengkap. Tulisan lain yang serupa juga bisa ditemukan pada pos berikut.

Di tulisan ini, fitur search + pagination akan ditulis ulang dalam contoh kasus lebih sederhana. Bonusnya, pada contoh aplikasi, juga disediakan fitur tambahan untuk menampilkan jumlah data yang bisa ditentukan sendiri oleh pengguna aplikasi.

Tulisan ini merupakan bagian ke 4 dari total 4 dalam seri Membuat Pagination di Laravel.

Sebelum beranjak jauh, pastikan kalian sudah memahami tulisan dasar pembuatan pagination di Laravel. Untuk fitur pencarian akan dijelaskan secara singkat pada tulisan ini.

Dalam contoh kasus, kita akan menggunakan contoh data user yang model dan migration-nya sudah tersedia di paket aplikasi. Yang perlu kalian lakukan adalah menghubungkan Laravel dengan pangkalan data (database), menjalankan migration untuk membuat tabel users, kemudian menambahkan contoh data (paling tidak 100 baris) agar fitur pagination dapat berfungsi.

Fitur Search

Di SQL, kita bisa menggunakan katakunci LIKE untuk mencari data yang mengandung kata tertentu. Di Laravel, Eloquent lebih tepatnya, kalian dapat menggunakan method where() untuk menggunakan fitur LIKE di SQL. Sebagai contoh, bisa dilihat skrip di bawah untuk mencari user dengan email dan/ataunamemengandung kata “@gmail.com” yang diambil dari request GET.

public function paginate(\Illuminate\Http\Request $request)
{
    $users = User::when($request->keyword, function ($query) use ($request) {
        $query->where('email', 'like', "%{$request->keyword}%")
            ->orWhere('name', 'like', "%{$request->keyword}%");
    })->get();

    return view('users.paginate', compact('users'));
}

Method when($value, $callback, $default = null) berfungsi untuk mengevaluasi query string keyword memiliki nilai. Jika nilainya tidak ada (kosong), maka langkah untuk melakukan pencarian menggunakan fitur where($column, $operator, $value, $boolean = 'and') dalam closure akan diabaikan.

Sebagai contoh, URL yang terbentuk untuk menjalankan skrip di atas adalah sebagai berikut:

domain.com/users?keyword=anne
domain.com/users?keyword=@gmail

.. dst

Untuk meng-generate URL menjadi bentuk di atas, kalian bisa membuat sebuah form pada halaman yang sama. Form tersebut menggunakan method GET dengan action halaman yang sama pula. Sebagai contoh, di bawah potongan form pencarian.

<form action="{{ url()->current() }}">
    <div class="col-md-11">
        <input type="text" name="keyword" class="form-control" placeholder="Search users...">
    </div>
    <div class="col-md-1">
        <button type="submit" class="btn btn-primary">
            Search
        </button>
    </div>
</form>

Fitur Pagination

Sampai di sini, pencarian sudah berhasil dibuat. Langkah selanjutnya adalah membagi data tersebut ke dalam beberapa halaman dengan fitur pagination apabila hasil pencarian menghasilkan jumlah data yang cukup banyak.

Dari skrip yang sudah dibuat di atas, tak perlu melakukan banyak perubahan. Yang perlu dilakukan hanyalah mengganti method  get() dengan method paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null).

/**
 * @param Request $request
 */
public function paginate(Request $request)
{
    $users = User::when($request->keyword, function ($query) use ($request) {
        $query->where('email', 'like', "%{$request->keyword}%")
            ->orWhere('name', 'like', "%{$request->keyword}%");
    })->paginate();

    return view('users.paginate', compact('users'));
}

Method paginate() menerima argumen pertama dengan tipe data integer. Argumen tersebut berfungsi untuk menentukan jumlah data per halaman, nilai bawaannya adalah 15. Jika kalian ingin menampilkan jumlah data yang berbeda, kalian dapat memodifikasinya menjadi seperti berikut.

->paginate(20);

Jangan lupa menambahkan skrip di bawah untuk menampilkan link pagination di view.

{{ $users->links() }}

Fitur Search + Pagination

Dari modifkasi beberapa baris skrip di atas, seharusnya kita sudah bisa menggunakan fitur search beserta fitur pagination-nya. Namun, hal ini masih menyisakan masalah. Ketika kalian mengklik halaman selanjutnya, maka pencarian sebelumnya tidak dieksekusi. Untuk lebih jelasnya, kalian bisa melihat kasus apda gambar bergerak di bawah.

Search + Pagination

Fitur search tidak berfungsi di halaman selanjutnya

Permasalahan yang terjadi adalah, query string keyword tidak terbawa ketika berpindah ke halaman berikutnya. Sehingga fitur pencarian tidak dieksekusi seperti yang dijelaskan di awal.

Agar fitur pencarian berfungsi di halaman selanjutnya, seharusnya URL yang terbentuk adalah sebagai berikut:

domain.com/users?keyword=anne&page=2
domain.com/users?keyword=.com&page=3

... dst

Untuk menangani kasus di atas, kita dapat menggunakan method appends($key, $value = null) dari class LengthAwarePaginator.

/**
* @param Request $request
*/
public function paginate(Request $request)
{
    $users = User::when($request->keyword, function ($query) use ($request) {
        $query->where('email', 'like', "%{$request->keyword}%")
            ->orWhere('name', 'like', "%{$request->keyword}%");
    })->paginate();

    $users->appends($request->only('keyword'));

    return view('users.paginate', compact('users'));
}

Method appends() berfungsi untuk menambahkan query string custom pada pagination. Tipe data yang diterima pada method tersebut adalah array. Penggunaan method only pada object $request berfungsi untuk memastikan bahwa query string yang boleh ditambahkan adalah keyword. Method only($keys) mengembalikan nilai array berpasangan.

Fitur Bonus, Limitasi

Fitur ini memberikan kebebasan bagi pengguna untuk menentukan jumlah data yang akan ditampilkan per halaman. Adapaun query string yang akan digunakan untuk membatasi adalah limit. Query string limit ini harus berupa integer. Oleh karenanya, kita butuh validasi untuk memastikan bahwa data limit harus berupa integer.

/**
 * @param Request $request
 */
public function paginate(\Illuminate\Http\Request $request)
{
    $this->validate($request, [
        'limit' => 'integer',
    ]);

    $users = User::when($request->keyword, function ($query) use ($request) {
        $query->where('email', 'like', "%{$request->keyword}%")
            ->orWhere('name', 'like', "%{$request->keyword}%");
    })->paginate($request->limit ? $request->limit : 20);

    $users->appends($request->only('keyword', 'limit'));

    return view('users.paginate', compact('users'));
}

Pada skrip, saya menambahkan validasi menggunakan controller helper untuk memastikan tipe data yang akan diproses sudah valid.

Query string limit digunakan pada argumen pertama method paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null). Apabila query string limit tidak didefinisikan, maka akan menggunakan nilai bawaan 20.

Sebagai alternatif, di PHP 7, kalian bisa menggunakan null coalescing operator.

->paginate($request->limit ?? 20);

Langkah terakhir, agar query string limit juga diikutsertakan di URL ketika berpindah halaman, jangan lupa untuk mengizinkan query string limit untuk ditambahkan pada pagination. Lihat baris ke 15 pada contoh skrip di atas.

***

Untuk melihat skrip lengkap tutorial kali ini, bisa kalian klik pada tautan menuju Github berikut. Untuk demo aplikasi, langsung klik tautan berikut.

Contoh aplikasi

Contoh lengkap demo aplikasi

Jika ada hal yang belum bisa dipahami atau terdapat bug pada aplikasi maupun kesalahan tulisan, jangan sungkan untuk meninggalkan komentar di bawah.

2 comments

  1. Salam kenal.
    Trima kasih atas tulisannya.

    Saya mau bertanya, saya ingin membuat sitem informasi jumlah karywan dalam sebuah prusahan karna mereka masi medata dengan buku sedangkan setiap tahuna ada penambahan anggota.

    Apa ada tutorial yg membahas mengenai sitem informasi pendataan ini?

    Trima kasih.

    • Tutorial di blog ini dibentuk berdasar potongan-potongan yang umum ditemui dalam sebuah aplikasi.
      Silakan digabungkan untuk mendapatkan sebuah aplikasi sesuai dengan kebutuhan.

Tinggalkan Balasan