Aplikasi E-Commerce Laravel 6 #8: Manage Carts

Aplikasi E-Commerce Laravel 6 #8: Manage Carts

Pendahuluan

Transaksi menjadi bagian yang penting dalam aplikasi berbasis penjualan dan mengelola data keranjang menjadi salah satu bagian yang akan melengkapi proses pendataan transaksi yang dilakukan oleh pelanggan. Maka pada serial ini kita akan belajar bagaimana membuat keranjang belanja menggunakan Laravel pada aplikasi E-commerce yang sedang kita kerjakan.

Memandang CRUD dengan sudut pandang yang berbeda, dimana biasanya kita berinteraksi dengan database untuk proses pengolahan data, maka kali ini kita akan menggunakan Cookie untuk memanipulasi data keranjang yang dimiliki.

Baca Juga: Aplikasi E-commerce Laravel 6 #7: Filter Product Detail

Add to Cart With Cookie

Mengelola keranjang belanja atau cart dapat dilakukan dengan dua cara, yakni menyimpannya secara langsung ke database atau di-browser melalui Cookie. Pada seri kali ini kita akan menggunakan cara kedua, karena cara pertama kurang lebih cara kerjanya hanya menggunakan metode CRUD.

Schema yang diinginkan adalah ketika pengguna menekan tombol Add to Cart, maka data tersebut akan teruskan ke-backend gunakan melakukan pengecekan. Jika data-nya berdasarkan product_id sudah ada didalam cookie, maka quantity-nya akan dijumlahkan. Selain itu, jika datanya belum tersedia, maka data tersebut akan disimpan kedalam cookie.

Bagian pertama yang akan dikerjakan adalah memberikan aksi ketika tombol Add to Cart ditekan, buka file show.blade.php dan modifikasi bagian code berikut

<!-- CODE SEBELUMNYA -->

<p></p>

<!-- TAMBAHKAN FORM ACTION -->
<form action="{{ route('front.cart') }}" method="POST">
  @csrf
  <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">
    
    <!-- BUAT INPUTAN HIDDEN YANG BERISI ID PRODUK -->
    <input type="hidden" name="product_id" value="{{ $product->id }}" class="form-control">
    
    <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">
    
    <!-- UBAH JADI BUTTON -->
    <button class="main_btn">Add to Cart</button>
    <!-- UBAH JADI BUTTON -->
    
  </div>
</form>

<!-- CODE SETELAHNYA -->

Kemudian buat controller baru dengan command

php artisan make:controller Ecommerce/CartController

Buka controller CartController.php dan tambahkan method berikut

public function addToCart(Request $request)
{
    //VALIDASI DATA YANG DIKIRIM
    $this->validate($request, [
        'product_id' => 'required|exists:products,id', //PASTIKAN PRODUCT_IDNYA ADA DI DB
        'qty' => 'required|integer' //PASTIKAN QTY YANG DIKIRIM INTEGER
    ]);

    //AMBIL DATA CART DARI COOKIE, KARENA BENTUKNYA JSON MAKA KITA GUNAKAN JSON_DECODE UNTUK MENGUBAHNYA MENJADI ARRAY
    $carts = json_decode($request->cookie('dw-carts'), true); 
  
    //CEK JIKA CARTS TIDAK NULL DAN PRODUCT_ID ADA DIDALAM ARRAY CARTS
    if ($carts && array_key_exists($request->product_id, $carts)) {
        //MAKA UPDATE QTY-NYA BERDASARKAN PRODUCT_ID YANG DIJADIKAN KEY ARRAY
        $carts[$request->product_id]['qty'] += $request->qty;
    } else {
        //SELAIN ITU, BUAT QUERY UNTUK MENGAMBIL PRODUK BERDASARKAN PRODUCT_ID
        $product = Product::find($request->product_id);
        //TAMBAHKAN DATA BARU DENGAN MENJADIKAN PRODUCT_ID SEBAGAI KEY DARI ARRAY CARTS
        $carts[$request->product_id] = [
            'qty' => $request->qty,
            'product_id' => $product->id,
            'product_name' => $product->name,
            'product_price' => $product->price,
            'product_image' => $product->image
        ];
    }

    //BUAT COOKIE-NYA DENGAN NAME DW-CARTS
    //JANGAN LUPA UNTUK DI-ENCODE KEMBALI, DAN LIMITNYA 2800 MENIT ATAU 48 JAM
    $cookie = cookie('dw-carts', json_encode($carts), 2880);
    //STORE KE BROWSER UNTUK DISIMPAN
    return redirect()->back()->cookie($cookie);
}

Jangan lupa untuk menambahkan use statement.

use App\Product;

Tugas selanjutnya adalah mendefinisikan routing dari method diatas, buka file routes/web.php dan tambahkan route berikut

Route::post('cart', 'Ecommerce\CartController@addToCart')->name('front.cart');

Proses menambahkan data baru kedalam keranjang berakhir disini, akan tetapi kita tidak bisa melihat isi keranjang saat ini, maka hal yang harus dikerjakan selanjutnya adalah menampilkan data keranjang yang telah disimpan ke dalam Cookie.

Buka file CartController.php dan tambahkan method berikut

public function listCart()
{
    //MENGAMBIL DATA DARI COOKIE
    $carts = json_decode(request()->cookie('dw-carts'), true);
    //UBAH ARRAY MENJADI COLLECTION, KEMUDIAN GUNAKAN METHOD SUM UNTUK MENGHITUNG SUBTOTAL
    $subtotal = collect($carts)->sum(function($q) {
        return $q['qty'] * $q['product_price']; //SUBTOTAL TERDIRI DARI QTY * PRICE
    });
    //LOAD VIEW CART.BLADE.PHP DAN PASSING DATA CARTS DAN SUBTOTAL
    return view('ecommerce.cart', compact('carts', 'subtotal'));
}

Buka kembali file routes/web.php untuk menambahkan route berikut

Route::get('/cart', 'Ecommerce\CartController@listCart')->name('front.list_cart');

Kemudian buat file cart.blade.php di dalam folder resources/views/ecommerce dan tambahkan code dibawah ini.

@extends('layouts.ecommerce')

@section('title')
    <title>Keranjang Belanja - Dw Ecommerce</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>Keranjang Belanja</h2>
					<div class="page_link">
                        <a href="{{ url('/') }}">Home</a>
                        <a href="{{ route('front.list_cart') }}">Cart</a>
					</div>
				</div>
			</div>
		</div>
	</section>
	<!--================End Home Banner Area =================-->

	<!--================Cart Area =================-->
	<section class="cart_area">
		<div class="container">
			<div class="cart_inner">
        
        <!-- DISABLE BAGIAN INI JIKA INGIN MELIHAT HASILNYA TERLEBIH DAHULU -->
        <!-- KARENA MODULENYA AKAN DIKERJAKAN PADA SUB BAB SELANJUTNYA -->
        <!-- HANYA SAJA DEMI KEMUDAHAN PENULISAN MAKA SAYA MASUKKAN PADA BAGIAN INI -->
                <form action="{{ route('front.update_cart') }}" method="post">
                    @csrf
        <!-- DISABLE BAGIAN INI JIKA INGIN MELIHAT HASILNYA TERLEBIH DAHULU -->
                  
				<div class="table-responsive">
					<table class="table">
						<thead>
							<tr>
								<th scope="col">Product</th>
								<th scope="col">Price</th>
								<th scope="col">Quantity</th>
								<th scope="col">Total</th>
							</tr>
						</thead>
						<tbody>
              <!-- LOOPING DATA DARI VARIABLE CARTS -->
                            @forelse ($carts as $row)
							<tr>
								<td>
									<div class="media">
										<div class="d-flex">
                                            <img src="{{ asset('storage/products/' . $row['product_image']) }}" width="100px" height="100px" alt="{{ $row['product_name'] }}">
										</div>
										<div class="media-body">
                                            <p>{{ $row['product_name'] }}</p>
										</div>
									</div>
								</td>
								<td>
                                    <h5>Rp {{ number_format($row['product_price']) }}</h5>
								</td>
								<td>
									<div class="product_count">
                    
                    
                    <!-- PERHATIKAN BAGIAN INI, NAMENYA KITA GUNAKAN ARRAY AGAR BISA MENYIMPAN LEBIH DARI 1 DATA -->
                                        <input type="text" name="qty[]" id="sst{{ $row['product_id'] }}" maxlength="12" value="{{ $row['qty'] }}" title="Quantity:" class="input-text qty">
                                        <input type="hidden" name="product_id[]" value="{{ $row['product_id'] }}" class="form-control">
                    <!-- PERHATIKAN BAGIAN INI, NAMENYA KITA GUNAKAN ARRAY AGAR BISA MENYIMPAN LEBIH DARI 1 DATA -->
                    
                    
										<button onclick="var result = document.getElementById('sst{{ $row['product_id'] }}'); 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{{ $row['product_id'] }}'); 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>
								</td>
								<td>
                                    <h5>Rp {{ number_format($row['product_price'] * $row['qty']) }}</h5>
								</td>
                            </tr>
                            @empty
                            <tr>
                                <td colspan="4">Tidak ada belanjaan</td>
                            </tr>
                            @endforelse
							<tr class="bottom_button">
								<td>
									<button class="gray_btn">Update Cart</button>
								</td>
								<td></td>
								<td></td>
								<td></td>
                            </tr>
                            </form>
							<tr>
								<td>

								</td>
								<td>

								</td>
								<td>
									<h5>Subtotal</h5>
								</td>
								<td>
                                    <h5>Rp {{ number_format($subtotal) }}</h5>
								</td>
							</tr>
							{{-- <tr class="shipping_area">
								<td></td>
								<td></td>
								<td>
									<h5>Shipping</h5>
								</td>
								<td>
									<div class="shipping_box">
										<ul class="list">
											<li>
												<a href="#">Flat Rate: $5.00</a>
											</li>
											<li>
												<a href="#">Free Shipping</a>
											</li>
											<li>
												<a href="#">Flat Rate: $10.00</a>
											</li>
											<li class="active">
												<a href="#">Local Delivery: $2.00</a>
											</li>
										</ul>
										<h6>Calculate Shipping
											<i class="fa fa-caret-down" aria-hidden="true"></i>
										</h6>
										<select class="shipping_select">
											<option value="1">Bangladesh</option>
											<option value="2">India</option>
											<option value="4">Pakistan</option>
										</select>
										<select class="shipping_select">
											<option value="1">Select a State</option>
											<option value="2">Select a State</option>
											<option value="4">Select a State</option>
										</select>
										<input type="text" placeholder="Postcode/Zipcode">
										<a class="gray_btn" href="#">Update Details</a>
									</div>
								</td>
							</tr> --}}
							<tr class="out_button_area">
								<td></td>
								<td></td>
								<td></td>
								<td>
									<div class="checkout_btn_inner">
										<a class="gray_btn" href="#">Continue Shopping</a>
										<a class="main_btn" href="#">Proceed to checkout</a>
									</div>
								</td>
							</tr>
						</tbody>
					</table>
				</div>
			</div>
		</div>
	</section>
	<!--================End Cart Area =================-->
@endsection

Keranjang belanja sudah bisa diakses melalui url: http://localhost:8000/cart, akan tetapi agar lebih mudah diakses melalui menu navigasi, maka kita harus memodifikasi file ecommerce.blade.php yang terletak di dalam folder resources/views/layouts dan modifikasi line berikut menjadi

<li class="nav-item">
  <a href="{{ route('front.list_cart') }}" class="icons">
    <i class="lnr lnr lnr-cart"></i>
  </a>
</li>

Note: Jika kesulitan mencari code-nya, silahkan search dengan keyword lnr lnr lnr-cart.

Update Cart Item

Fitur lainnya yang harus disediakan adalah pelanggan bisa memodifikasi quantity belanjaannya pada halaman keranjang. Adapun rule yang akan kita berlakukan adalah ketika pelanggan menekan tombol update cart maka secara otomatis akan memperbaharui data keranjang, dimana ketentuannya adalah data yang memiliki quantity 0 akan dihapus, selain itu akan di-update.

Tugas kita menjadi lebih mudah karena view-nya sudah dikerjakan pada sub-bab sebelumnya, maka tugas kita hanya meng-handle data yang dikirimkan oleh pelanggan. Buka file CartController.php dan tambahkan method berikut

public function updateCart(Request $request)
{
    //AMBIL DATA DARI COOKIE
    $carts = json_decode(request()->cookie('dw-carts'), true);
    //KEMUDIAN LOOPING DATA PRODUCT_ID, KARENA NAMENYA ARRAY PADA VIEW SEBELUMNYA
    //MAKA DATA YANG DITERIMA ADALAH ARRAY SEHINGGA BISA DI-LOOPING
    foreach ($request->product_id as $key => $row) {
        //DI CHECK, JIKA QTY DENGAN KEY YANG SAMA DENGAN PRODUCT_ID = 0
        if ($request->qty[$key] == 0) {
            //MAKA DATA TERSEBUT DIHAPUS DARI ARRAY
            unset($carts[$row]);
        } else {
            //SELAIN ITU MAKA AKAN DIPERBAHARUI
            $carts[$row]['qty'] = $request->qty[$key];
        }
    }
    //SET KEMBALI COOKIE-NYA SEPERTI SEBELUMNYA
    $cookie = cookie('dw-carts', json_encode($carts), 2880);
    //DAN STORE KE BROWSER.
    return redirect()->back()->cookie($cookie);
}

Langkah terakhir adalah mendefinisikan routing-nya, buka file routes/web.php dan tambahkan code

Route::post('/cart/update', 'Ecommerce\CartController@updateCart')->name('front.update_cart');

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

Kesimpulan

Serial ini kita belajar hal baru yakni berinteraksi dengan cookie, sebab tidak hanya database tapi ada banyak cara dan method yang digunakan untuk menyimpan data berdasarkan kegunaannya. Keranjang belanja sifatnya sementara dan hanya dimiliki oleh user tertentu berdasarkan user yang sedang mengaksesnya. Maka cookie menjadi satu dari sekian solusi yang bisa digunakan.

Adapun dokumentasi code dari artikel ini bisa dilihat di Github.

Category:
Share:

Comments