![Building Ecommerce Website With PHP Lumen Laravel And Nuxtjs](https://webmobtuts.com/wp-content/uploads/2020/12/Building-Ecommerce-Website-With-PHP-Lumen-Laravel-And-Nuxtjs-2-800x400.jpg)
In this article we will start implementing the most finest part of this series which is the shopping cart functionality, in this part we will begin adding the backend apis.
Before we start building shopping cart functionality, there are some concepts we have to care about to have a consistent e-commerce application:
- Store the cart data into session or database (in our case we will store it into database)
- The cart data must be stored for a limited time (in other means if the user didn’t take a decision after some time the system automatically destroy the cart)
- When adding a product into the cart deduct from the product inventory.
- Some platforms didn’t deduct from the inventory unless the user already make a successful purchase. In our case we will deduct from product inventory but if the user didn’t take a decision within 1 hour the system will destroy the cart and restore the cart amount into the product inventory.
- Use a cron job to track the user carts if it passed 1 hour and didn’t make a purchase then destroy the cart data.
Now with these concepts in mind let’s add the cart Apis into the Lumen project.
Backend Apis
On the lumen project update the ShoppingCart model, open app/Models/ShoppingCart.php and update as shown below:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class ShoppingCart extends Model { protected $hidden = ["created_at", "updated_at"]; protected $appends = ["total_price_formatted", "total_price_numeric", "amount_temp"]; protected $table = "shopping_cart"; public function user() { return $this->belongsTo(User::class, 'user_id'); } public function product() { return $this->belongsTo(Product::class, 'product_id')->with("gallery"); } public function getTotalPriceFormattedAttribute() { return number_format($this->amount * $this->product->price_after_discount_numeric, 1); } public function getTotalPriceNumericAttribute() { return $this->amount * $this->product->price_after_discount_numeric; } public function getAmountTempAttribute() { return $this->amount; } }
As shown i updated the product() relationship to include the gallery as well with the product using the with() method. Also i added methods these methods getTotalPriceFormattedAttribute(), getTotalPriceNumericAttribute(), getAmountTempAttribute() to return the formatted price, numeric price and amount temp(we will use this when updating cart amount), then adding these methods names into the $appends property to include them along with shopping cart response.Â
Shopping Cart Controller
Create a new restful controller inside app/Http/Controllers named ShoppingCartController.php
app/Http/Controllers/ShoppingCartController.php
<?php namespace App\Http\Controllers; use App\Models\Product; use App\Models\ShoppingCart; use Illuminate\Support\Facades\Auth; use Illuminate\Http\Request; use Illuminate\Support\Facades\Validator; class ShoppingCartController extends Controller { public function __construct() { } public function index() { } public function store(Request $request) { } public function update(Request $request) { } public function show($id) { } public function destroy($id) { } public function clearAll() { } }
Let’s start with by implementing the index() which display all cart items for specific user
Display All Cart Items
Update the index() method as follows:
public function index() { $user = Auth::user(); $cart = ShoppingCart::with('product')->where('user_id', $user->id)->get(); return response()->json(['cart' => $cart], 200); }
Here i retrieve the current authenticated user, then retrieve all cart items by this user and return the results.
Adding Products Into The Cart
To add products into the cart we need to update the store() method like this:
public function store(Request $request) { $validator = Validator::make($request->only('product_id', 'amount'), [ 'product_id' => "required", 'amount' => "required|numeric|min:1" ]); if($validator->fails()) { return response()->json(['success' => 0, 'message' => 'Required or incorrect fields', 'errors' => $validator->errors()], 500); } $product = Product::find($request->input('product_id')); if(!$product) { return response()->json(['success' => 0, 'message' => 'Product not found'], 404); } if($product->amount == 0) { return response()->json(['success' => 0, 'message' => 'Product has no more available items'], 500); } if($product->amount < $request->input('amount')) { return response()->json(['success' => 0, 'message' => 'There are only ' . $product->amount . ' available items of this product'], 500); } $user = Auth::user(); $cartItem = new ShoppingCart(); $cartItem->user_id = $user->id; $cartItem->product_id = $request->input('product_id'); $cartItem->amount = $request->input('amount'); $cartItem->save(); // update product amount $product->decrement('amount', $request->input('amount')); $cartItem = ShoppingCart::with('product')->where('user_id', $user->id)->where('product_id', $request->input('product_id'))->first(); return response()->json(['success' => 1, 'message' => 'Item added successfully to the cart', 'item' => $cartItem], 200); }
The store() method validates if there is a product_id and an amount, the next step we do some checks like checking for the product and the product amount != 0 and product amount not lower than the incoming amount. After that we begin store cart data into db and decrement the product amount and finally return a success response.
Updating Products Amount In the Cart
The place to update the products amount in the update() method so let’s update it with this code:
public function update(Request $request) { $validator = Validator::make($request->only('product_id', 'amount'), [ 'product_id' => "required", 'amount' => "required|numeric|min:1" ]); if($validator->fails()) { return response()->json(['success' => 0, 'message' => 'Required or incorrect fields', 'errors' => $validator->errors()], 500); } $product = Product::find($request->input('product_id')); if(!$product) { return response()->json(['success' => 0, 'message' => 'Product not found'], 404); } $user = Auth::user(); $cartItem = ShoppingCart::where('user_id', $user->id)->where('product_id', $request->input('product_id'))->first(); $oldAmount = $cartItem->amount; if($product->amount + $oldAmount < $request->input('amount')) { return response()->json(['success' => 0, 'message' => 'There are only ' . (($product->amount + $oldAmount) - $oldAmount) . ' available items of this product'], 500); } $cartItem->amount = $request->input('amount'); $cartItem->save(); // update product amount $product->amount = (($product->amount + $oldAmount) - $request->input('amount')); $product->save(); $cartItem = ShoppingCart::with('product')->where('user_id', $user->id)->where('product_id', $request->input('product_id'))->first(); return response()->json(['success' => 1, 'message' => 'Cart item updated successfully', 'item' => $cartItem], 200); }
The update() method is much like the store() method as we validate the user input first then we do the same checks, then i update the cart amount and update the product inventory.
Displaying Specific Cart Item
Update the show() method with this code:
$cartItem = ShoppingCart::with('product')->find($id); if(!$cartItem) { return response()->json(['success' => 0, 'message' => 'Cart item not found'], 404); } $user = Auth::user(); if($user->id != $cartItem->user_id) { return response()->json(['success' => 0, 'message' => 'This cart item does not belong to you!'], 500); } return response()->json(['item' => $cartItem], 200);
In the show() method we ensure that the cart is exist and belong to the current logged in user, if this the case we display an error message, otherwise we return the cart item.
Removing Specific Cart Item
The destroy() method responsible for removing specific cart item by id so let’s update it with this code:
public function destroy($id) { $cartItem = ShoppingCart::with('product')->find($id); if(!$cartItem) { return response()->json(['success' => 0, 'message' => 'Cart item not found'], 404); } $user = Auth::user(); if($user->id != $cartItem->user_id) { return response()->json(['success' => 0, 'message' => 'This cart item does not belong to you!'], 500); } $cartItemAmount = $cartItem->amount; $cartItem->delete(); // reset the product amount $product = Product::find($cartItem->product_id); $product->increment('amount', $cartItemAmount); return response()->json(['success' => 1, 'message' => 'Item removed successfully from cart'], 200); }
Once again in the destroy() method ensures that the cart item exist and belong to the current logged user. Most importantly before deleting the cart item save the item amount into a variable as in $cartItemAmount, this amount will be restored into the product inventory as shown above $product->increment(‘amount’, $cartItemAmount).
Clearing All Cart Items
The process of clearing all cart items in the clearAll() method let’s update this method:
public function clearAll() { $user = Auth::user(); $cart = ShoppingCart::where('user_id', $user->id)->get(); if (!$cart) { return response()->json(['success' => 0, 'message' => 'Your cart has no items to remove'], 500); } foreach ($cart as $item) { $cartItemAmount = $item->amount; $product = Product::find($item->product_id); if ($product) { $product->increment('amount', $cartItemAmount); } $item->delete(); } return response()->json(['success' => 1, 'message' => 'Cart cleared successfully'], 200); }
The clearAll() method is the same as the destroy() method but instead of working on single cart item the clearAll() works on all the cart items of the current user by iterating over the cart items and making the same process as in destroy().
Updating The Routes
Update routes/web.php to include the cart Apis so under this block:
$router->group(['prefix' => 'user'], function () use ($router) { $router->post('/', 'UsersController@store'); $router->put('/{id}', 'UsersController@update'); $router->delete('/{id}', 'UsersController@destroy'); });
Add this route group:
$router->group(['prefix' => 'cart'], function () use ($router) { $router->get('/', 'ShoppingCartController@index'); $router->post('/', 'ShoppingCartController@store'); $router->put('/', 'ShoppingCartController@update'); $router->get('/{id}', 'ShoppingCartController@show'); $router->delete('/clearAll', 'ShoppingCartController@clearAll'); $router->delete('/{id}', 'ShoppingCartController@destroy'); });
Continue to Part17: Shopping Cart Display
Hi!
What about the unregistered guest user, who didn’t logged in?
Can only the logged-in user add the product to the cart?
Yes that’s right because we store the cart in the DB not the session