How to Build a Shopping Cart in Laravel 12 (Step-by-Step) Part 2
In the second part of this tutorial, we will add the controllers we need with the functions to get and display the products, add, update, and remove products from the cart, and finally proceed to payment and pay orders using Stripe.
Create the home controller
First, let's create the home controller. Inside, we have only one function to get the products.
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class HomeController extends Controller
{
public function index()
{
$products = Product::latest()->get();
return view('home',compact('products'));
}
}
Create the cart controller
Next, let's create the cart controller. Inside, we have the functions to add, update, and remove products from the cart.
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class CartController extends Controller
{
private array $cart;
public function __construct()
{
$this->cart = session()->get('cart', []);
}
/**
* Get the cart items from the session
*/
public function index()
{
$cart = $this->cart;
//get cart items from the session
return view('cart',compact('cart'));
}
/**
* Add items to the cart
*/
public function addToCart(Request $request)
{
//find and get the product by id
$product = Product::findOrFail($request->product_id);
//check if the product is already in the cart
if(isset($this->cart[$product->id])) {
return back()->with('info', 'Product already added to your cart');
}else {
$this->cart[$product->id] = [
'product_id' => $product->id,
'name' => $product->name,
'price' => $product->price,
'qty' => 1,
'image' => $product->image
];
session()->put('cart', $this->cart);
$this->calculateCartItemsTotal();
return back()->with('success', 'Product added to your cart');
}
}
/**
* Update item inside the cart
*/
public function updateCartItem(Request $request)
{
//find and get the product by id
$product = Product::findOrFail($request->product_id);
//get the new qty
$qty = $request->qty;
//check if the product is already in the cart
if(isset($this->cart[$product->id])) {
$this->cart[$product->id]['qty'] = $qty;
//set the new cart session
session()->put('cart', $this->cart);
$this->calculateCartItemsTotal();
}
return back()->with('success', 'Cart updated successfully');
}
/**
* Remove item from the cart
*/
public function removeCartItem(Request $request)
{
//find and get the product by id
$product = Product::findOrFail($request->product_id);
//check if the product is already in the cart
if(isset($this->cart[$product->id])) {
unset($this->cart[$product->id]);
//set the new cart session
session()->put('cart', $this->cart);
$this->calculateCartItemsTotal();
}
return back()->with('success', 'Product removed successfully');
}
/**
* Clear the cart
*/
public function clearCart()
{
//remove cart from the session
session()->forget('cart');
session()->forget('cartItemsTotal');
return back()->with('success', 'Cart cleared');
}
private function calculateCartItemsTotal()
{
$total = collect($this->cart)->sum(fn($item) => $item['price'] * $item['qty']);
session()->put('cartItemsTotal', $total);
}
}
Create the order controller
Next, let's create the order controller. Inside, we have the functions to pay orders using Stripe, so here you need your Stripe secret key. Grab it from your Stripe account and add it to the setApiKey method.
<?php
namespace App\Http\Controllers;
use Stripe\Stripe;
use ErrorException;
use Illuminate\Http\Request;
use Stripe\Checkout\Session;
use Illuminate\Support\Facades\Log;
use Stripe\Exception\InvalidRequestException;
class OrderController extends Controller
{
private array $cart;
public function __construct()
{
$this->cart = session()->get('cart', []);
//provide the stripe key
Stripe::setApiKey("YOUR STRIPE SECRET KEY HERE");
}
/**
* Pay order by stripe
*/
public function payOrderByStripe()
{
//proceed to payment
try {
$checkout_session = Session::create([
'line_items' => [[
'price_data' => [
'currency' => 'usd',
'product_data' => [
'name' => 'Laravel 12 Shopping Cart'
],
'unit_amount' => $this->calculateTotalToPay($this->cart),
],
'quantity' => 1
]],
'mode' => 'payment',
'success_url' => route('order.success').'?session_id={CHECKOUT_SESSION_ID}'
]);
return redirect($checkout_session->url);
} catch (ErrorException $e) {
Log::error('Stripe error: '.$e->getMessage());
return back()->with('error', 'Something went wrong with the payment. Please try again.');
}
}
/**
* Calculate the total to pay
*/
private function calculateTotalToPay(array $items) : float
{
$total = 0;
foreach($items as $item)
{
$total += $item['qty'] * $item['price'];
}
return $total * 100;
}
/**
* Redirect user to success page after payment
*/
public function successPaid(Request $request)
{
$sessionId = $request->get('session_id');
if($sessionId) {
try {
Session::retrieve($sessionId);
session()->forget('cart');
session()->forget('cartItemsTotal');
return view('success-paid');
} catch (InvalidRequestException $e) {
return to_route('home');
}
}else {
return to_route('home');
}
}
}
Adding routes
Next, inside the web.php file, let's add the routes we need.
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\CartController;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\OrderController;
Route::get('/', [HomeController::class,'index'])->name('home');
Route::get('cart', [CartController::class,'index'])->name('cart.index');
Route::post('add/cart', [CartController::class,'addToCart'])->name('cart.add');
Route::put('update/cart', [CartController::class,'updateCartItem'])->name('cart.update');
Route::delete('remove/cart', [CartController::class,'removeCartItem'])->name('cart.remove');
Route::delete('clear/cart', [CartController::class,'clearCart'])->name('cart.clear');
Route::get('order/pay', [OrderController::class,'payOrderByStripe'])->name('order.pay');
Route::get('success/pay', [OrderController::class,'successPaid'])->name('order.success');