Aplikasi E-Commerce Laravel 6 #7: Filter & Product Detail

Aplikasi E-Commerce Laravel 6 #7: Filter & Product Detail

Pendahuluan

Hal sederhana tapi kerap kali mengundang tanya, bagaimana sih cara filter data berdasarkan parameter tertentu? Maka pada seri artikel ini kita akan belajar bagaimana cara menampilkan data produk berdasarkan kategori yang dipilih. Selain itu kita juga akan belajar bagaimana mengelompokkan query menggunakan View Composer di Laravel.

Perlahan namun pasti, langkah kita dalam menyusun potongan fitur dengan case Aplikasi E-Commerce menggunakan Laravel 6 telah memperlihatkan hasil. Harapannya materi-materi sederhana ini bisa membantu kamu dan saya khususnya dalam menambah pengalaman serta wawasan tentang Laravel. Jadi, selamat menikmati.

Baca Juga: Aplikasi E-Commerce Laravel 6 #6: Templating & Display Products

View Composers

Sebelum melanjutkan langkah kita untuk melengkapi fitur lainnya, maka terlebih dahulu kita akan membuat sebuah fungsi untuk mengelompokkan query agar lebih mudah digunakan secara berulang kali. Jika kita buat file FrontController, tepatnya berada pada method product(), maka kita akan menemukan query yang kurang lebih seperti ini

$categories = Category::with(['child'])->withCount(['child'])->getParent()->orderBy('name', 'ASC')->get();

Query diatas digunakan untuk mengambil semua data kategori beserta turunannya untuk ditampilkan pada sidebar di halaman product. Query yang sama akan digunakan pada method selanjutnya, sehingga perlu kita kelompokkan agar tidak dituliskan secara berulang kali. Berhubung hasil dari query tersebut hanya akan digunakan pada view, maka pengelompokannya menggunakan View Composers.

View Composer memungkinkan kita membuat sebuah fungsi yang dapat di-passing ke semua view yang diinginkan, sehingga view tersebut dapat menggunakan data yang diberikan oleh View Composer.

Pertama, buat folder View didalam folder app/Http dan didalamnya kita buat lagi sebuah file bernama CategoryComposer.php, kemudian masukkan code berikut

<?php

namespace App\Http\View;

use Illuminate\View\View;
use App\Category;

class CategoryComposer
{
    public function compose(View $view)
    {
        //JADI QUERY TADI KITA PINDAHKAN KESINI
        $categories = Category::with(['child'])->withCount(['child'])->getParent()->orderBy('name', 'ASC')->get();
      	//KEMUDIAN PASSING DATA TERSEBUT DENGAN NAMA VARIABLE CATEGORIES
        $view->with('categories', $categories);
    }
}

Agar View Composer diatas bisa digunakan, maka kita perlu untuk meneruskan data tersebut ke View dengan menggunakan bantuan Providers. Buka file AppServiceProvider.php dan masukkan code berikut didalam method boot()

View::composer('ecommerce.*', 'App\Http\View\CategoryComposer');

Penjeleasan: Parameter pertama berisi tujuan dimana data dari View Composer akan di-passing, kita masukkan ecommerce.* yang berarti semua file yang berada didalam folder resources/views/ecommerce. Parameter kedua adalah sumber datanya, maka dalam hal ini adalah CategoryComposer.

Dengan file yang sama, tambahkan use statement

use Illuminate\Support\Facades\View;

Karena query-nya sudah dikelompokkan, maka kita perlu memodifikasi method product() karena ada sebuah query yang tidak lagi diperlukan. Buka file FrontController.php dan modifikasi method product() menjadi:

public function product()
{
    $products = Product::orderBy('created_at', 'DESC')->paginate(12);
    return view('ecommerce.product', compact('products'));
}

Filter Product By Category

Mengikuti jejak yang telah kita tinggalkan pada serial sebelumnya dimana ketika kategori yang berada pada sidebar diklik maka akan menuju ke halaman kategori dengan menampilkan produk yang berada pada kategori terakait.

Buka file FrontController.php dan tambahkan sebuah method baru berikut ini

 public function categoryProduct($slug)
{
   //JADI QUERYNYA ADALAH KITA CARI DULU KATEGORI BERDASARKAN SLUG, SETELAH DATANYA DITEMUKAN
   //MAKA SLUG AKAN MENGAMBIL DATA PRODUCT YANG BERELASI MENGGUNAKAN METHOD PRODUCT() YANG TELAH DIDEFINISIKAN PADA FILE CATEGORY.PHP SERTA DIURUTKAN BERDASARKAN CREATED_AT DAN DI-LOAD 12 DATA PER SEKALI LOAD
    $products = Category::where('slug', $slug)->first()->product()->orderBy('created_at', 'DESC')->paginate(12);
    //LOAD VIEW YANG SAMA YAKNI PRODUCT.BLADE.PHP KARENA TAMPILANNYA AKAN KITA BUAT SAMA JUGA
    return view('ecommerce.product', compact('products'));
}

Sedikit modifikasi akan dilakukan pada file product.blade.php karena terdapat sedikit kesalahan, dimana parent category harusnya bisa diklik juga karena bisa berisi produk. Buka file tersebut kemudian modifikasi bagian sidebar-nya atau bagian code berikut

<!-- CODE SEBELUMNYA -->

<div class="col-lg-3">
    <div class="left_sidebar_area">
        <aside class="left_widgets cat_widgets">
            <div class="l_w_title">
                <h3>Kategori Produk</h3>
            </div>
            <div class="widgets_inner">
                <ul class="list" >
                    @foreach ($categories as $category)
                    <li>
                      
                      	<!-- MODIFIKASI BAGIAN INI -->
                        <strong><a href="{{ url('/category/' . $category->slug) }}">{{ $category->name }}</a></strong>
                      <!-- MODIFIKASI BAGIAN INI -->

                        @foreach ($category->child as $child)
                      
                      	<!-- MODIFIKASI BAGIAN INI -->
                        <ul class="list" style="display: block">
                        <!-- MODIFIKASI BAGIAN INI -->
                          
                            <li>
                                <a href="{{ url('/category/' . $child->slug) }}">{{ $child->name }}</a>
                            </li>
                        </ul>
                        @endforeach
                    </li>
                    @endforeach
                </ul>
            </div>
        </aside>
    </div>
</div>

<!-- CODE SETELAHNYA -->

Masih dengan file yang sama, diantara code @empty dan @endforelse dimana code ini adalah looping data produk. Letakkan HTML code dibawah ini diantara kedua code tersebut

<!-- CODE SEBELUMNYA -->

@empty
<div class="col-md-12">
    <h3 class="text-center">Tidak ada produk</h3>
</div>
@endforelse

<!-- CODE SETELAHNYA -->

Bagian terakhir adalah mendefinisikan routing-nya. Buka file routes/web.php dan tambahkan route berikut

Route::get('/category/{slug}', 'Ecommerce\FrontController@categoryProduct')->name('front.category');

Show Product Detail

Ketika produk diklik maka calon pelanggan akan diarahkan pada sebuah halaman yang akan menampilkan detail informasi produk. Halaman ini berisi semua informasi produk yang dibutuhkan oleh calon pelanggan dalam mencari tahu tentang produk yang akan dibelinya.

Buka file FrontController.php dan tambahkan method berikut

public function show($slug)
{
    //QUERY UNTUK MENGAMBIL SINGLE DATA BERDASARKAN SLUG-NYA
    $product = Product::with(['category'])->where('slug', $slug)->first();
    //LOAD VIEW SHOW.BLADE.PHP DAN PASSING DATA PRODUCT
    return view('ecommerce.show', compact('product'));
}

Kemudian buat file show.blade.php dan letakkan didalam folder resources/views/ecommerce/, kemudian tambahkan potongan code berikut

@extends('layouts.ecommerce')

@section('title')
    <title>Jual {{ $product->name }}</title>
@endsection

@section('content')
    <!--================Home Banner Area =================-->
	<section class="banner_area">
		<div class="banner_inner d-flex align-items-center">
			<div class="container">
				<div class="banner_content text-center">
                    <h2>{{ $product->name }}</h2>
					<div class="page_link">
                        <a href="{{ url('/') }}">Home</a>
                        <a href="#">{{ $product->name }}</a>
					</div>
				</div>
			</div>
		</div>
	</section>
	<!--================End Home Banner Area =================-->

	<div class="product_image_area">
		<div class="container">
			<div class="row s_product_inner">
				<div class="col-lg-6">
					<div class="s_product_img">
						<div id="carouselExampleIndicators" class="carousel slide" data-ride="carousel">
							<div class="carousel-inner">
								<div class="carousel-item active">
									<img class="d-block w-100" src="{{ asset('storage/products/' . $product->image) }}" alt="{{ $product->name }}">
								</div>
							</div>
						</div>
					</div>
				</div>
				<div class="col-lg-5 offset-lg-1">
					<div class="s_product_text">
						<h3>{{ $product->name }}</h3>
                        <h2>Rp {{ number_format($product->price) }}</h2>
						<ul class="list">
							<li>
								<a class="active" href="#">
                                    <span>Kategori</span> : {{ $product->category->name }}</a>
							</li>
						</ul>
						<p></p>
						<div class="product_count">
							<label for="qty">Quantity:</label>
							<input type="text" name="qty" id="sst" maxlength="12" value="1" title="Quantity:" class="input-text qty">
							<button onclick="var result = document.getElementById('sst'); var sst = result.value; if( !isNaN( sst )) result.value++;return false;"
							 class="increase items-count" type="button">
								<i class="lnr lnr-chevron-up"></i>
							</button>
							<button onclick="var result = document.getElementById('sst'); var sst = result.value; if( !isNaN( sst ) &amp;&amp; sst > 0 ) result.value--;return false;"
							 class="reduced items-count" type="button">
								<i class="lnr lnr-chevron-down"></i>
							</button>
						</div>
						<div class="card_area">
							<a class="main_btn" href="#">Add to Cart</a>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>
	<!--================End Single Product Area =================-->

	<!--================Product Description Area =================-->
	<section class="product_description_area">
		<div class="container">
			<ul class="nav nav-tabs" id="myTab" role="tablist">
				<li class="nav-item">
					<a class="nav-link active show" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Description</a>
				</li>
				<li class="nav-item">
					<a class="nav-link" id="profile-tab" data-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Specification</a>
				</li>
			</ul>
			<div class="tab-content" id="myTabContent">
				<div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab" style="color: black">
					{!! $product->description !!}
				</div>
				<div class="tab-pane fade" id="profile" role="tabpanel" aria-labelledby="profile-tab">
					<div class="table-responsive">
						<table class="table">
							<tbody>
								<tr>
									<td>
										<h5>Berat</h5>
									</td>
									<td>
                                        <h5>{{ $product->weight }} gr</h5>
									</td>
								</tr>
								<tr>
									<td>
										<h5>Harga</h5>
									</td>
									<td>
										<h5>Rp {{ number_format($product->price) }}</h5>
									</td>
								</tr>
								<tr>
									<td>
										<h5>Kategori</h5>
									</td>
									<td>
										<h5>{{ $product->category->name }}</h5>
									</td>
								</tr>
							</tbody>
						</table>
					</div>
				</div>
			</div>
		</div>
	</section>
	<!--================End Product Description Area =================-->
@endsection

Note: Tidak ada yang spesial dari code diatas, hanya mencetak informasi produk seperti nama produk, harga, berat, menampilkan gambar dan lain lain.

Bagian terakhir adalah mendefinisikan routing-nya. Buka file routes/web.php dan tambahkan route berikut

Route::get('/product/{slug}', 'Ecommerce\FrontController@show')->name('front.show_product');

Baca Juga: Aplikasi E-Commerce Laravel 6 #5: Mass Upload Products

Kesimpulan

Dua fitur baru telah kita tambahkan kedalam aplikasi ecommerce menggunakan Laravel 6, dimana fitur tersebut adalah Filter produk berdasarkan kategori dan menampilkan detail produk. Dalam artikel ini kita belajar 1 hal baru, yakni cara menggunakan View Composer di Laravel. Selain itu, kita juga belajar mengambil data dari table yang berelasi.

Adapun dokumentasi code dari artikel ini bisa kamu lihat di Github.

Category:
Share:

Comments