I have the following problem with shopping cart. I don’t know where to place the calculation, so it can update total price dynamically (Such when the cart item is removed, or the quantity updated). Because I need to call updateTotalPrice() method almost everywhere, but I don’t want to repeat the code that many times
CartService
class CartService extends AbstractController
{
private CartRepository $cartRepository;
private ManagerRegistry $managerRegistry;
private CartItemRepository $cartItemRepository;
public function __construct(CartItemRepository $cartItemRepository, CartRepository $cartRepository, ManagerRegistry $managerRegistry)
{
$this->cartItemRepository = $cartItemRepository;
$this->cartRepository = $cartRepository;
$this->managerRegistry = $managerRegistry;
}
/**
* Get Cart by ID
*
* @return Cart|null
*/
public function getCartByUserId(): ?Cart
{
/**
* @var User $user
*/
$user = $this->getUser();
return $this->cartRepository->findOneBy(['customer' => $user->getId()]);
}
/**
* Create Cart for Customer
*
* @return Cart|null
*/
public function createNewCart(): ?Cart
{
$entityManager = $this->managerRegistry->getManager();
$cart = new Cart();
/**
* @var User $user
*/
$cart->setCustomer($this->getUser());
$entityManager->persist($cart);
$entityManager->flush();
return $cart;
}
/**
* @param Cart $cart
* @param Product $product
* @return CartItem|null
*/
public function isProductInCart(Cart $cart, Product $product): ?CartItem
{
return $this->cartItemRepository->findOneBy(['product' => $product->getId(), 'cart' => $cart->getId()]);
}
/**
* Add new product to cart
*
* @param Cart $cart
* @param Product $product
* @param int $quantity
* @return void
*/
public function insertProduct(Cart $cart, Product $product, int $quantity): void
{
$entityManager = $this->managerRegistry->getManager();
$insertProduct = new CartItem();
$insertProduct->setCart($cart)
->setCart($cart)
->setQuantity($quantity)
->setProduct($product);
$cart->addCartItem($insertProduct);
$cart->setTotalprice($cart->getTotalprice() + $insertProduct->getQuantity() * $insertProduct->getProduct()->getPrice());
$entityManager->persist($insertProduct);
$entityManager->flush();
}
/**
* Update item's quantity
*
* @param CartItem $cartItem
* @param int $quantity
* @return void
*/
public function updateCartItemQuantity(CartItem $cartItem, int $quantity): void
{
$entityManager = $this->managerRegistry->getManager();
$cartItem->setQuantity($quantity);
$entityManager->persist($cartItem);
$entityManager->flush();
}
/**
* Remove specific product from cart
*
* @param int $id
* @return void
*/
public function removeProductFromCart(int $id): void
{
$product = $this->cartItemRepository->findOneBy(['product' => $id]);
$entityManager = $this->managerRegistry->getManager();
$entityManager->remove($product);
$entityManager->flush();
}
/**
* Set or update total price
*
* @param Cart $cart
* @param float $totalprice
* @return void
*/
public function updateTotalPrice(Cart $cart, float $totalprice): void
{
$entityManager = $this->managerRegistry->getManager();
$cart->setTotalprice($cart->getTotalprice() + $totalprice);
$entityManager->persist($cart);
$entityManager->flush($cart);
}
/**
* Add Product to Cart
*
* @param Product $product
* @param $cartItem
* @return void
*/
public function addOrUpdateProduct(Product $product, $cartItem): void
{
$cart = $this->getCartByUserId();
if (!$cart instanceof Cart) {
$cart = $this->createNewCart();
}
$isProductInCart = $this->isProductInCart($cart, $product);
//If product doens't exist, insert it inside cart. If exist, update quantity and add message
if (!$isProductInCart) {
$this->insertProduct($cart, $product, $cartItem->getQuantity());
$this->addFlash('productAdded', 'Product added to Cart');
} else {
$this->updateCartItemQuantity($isProductInCart, $cartItem->getQuantity() + $isProductInCart->getQuantity());
$this->updateTotalPrice($cart, $cartItem->getQuantity() * $cartItem->getProduct()->getPrice());
$this->addFlash('productAdded', 'Product already in cart. Quantity Updated');
}
}
OrderController (That’s the cart)
<?php
namespace AppController;
/**
* @IsGranted("IS_AUTHENTICATED_FULLY")
*/
#[Route('/cart', name: 'cart.')]
class OrderController extends AbstractController
{
/**
* Show current Cart
*
* @param CartService $cartService
* @return Response
*/
#[Route('/', name: 'show_cart')]
public function showCart(CartService $cartService): Response
{
$cart = $cartService->getCartByUserId();
return $this->render('cart/index.html.twig', [
'cart' => $cart,
]);
}
/**
* Update existing cart item quantity
*
* @param CartItem $cartItem
* @param int $quantity
* @param CartService $cartService
* @return Response
*/
#[Route('/updatecartquantity/{id}/{quantity}', name: 'updatequantity')]
public function updateCartQuantity(CartItem $cartItem, int $quantity, CartService $cartService): Response
{
$cartService->updateCartItemQuantity($cartItem, $quantity);
return $this->redirect($this->generateUrl('cart.show_cart'));
}
/**
* Remove product from cart
*
* @param CartService $cartService
* @param int $id
* @return Response
*/
#[Route('/removeitem/{id}', name: 'removefromcart')]
public function removeFromCart(CartService $cartService, int $id): Response
{
$cartService->removeProductFromCart($id);
return $this->redirect($this->generateUrl('cart.show_cart'));
}
}
Product Controller (Shows the product -> After choosing quantity can be inserted inside cart
#[Route('/product', name: 'product.')]
class ProductController extends AbstractController
{
/**
* Show Product, and add to cart
*
* @param Product $product
* @param CartService $cartService
* @param Request $request
* @return Response
*/
#[Route('/showproduct/{id}', name: 'showproduct')]
public function showProduct(Product $product, CartService $cartService, Request $request): Response
{
$form = $this->createForm(CartItemType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$item = $form->getData();
$item->setProduct($product);
$cartService->addOrUpdateProduct($product, $item);
}
return $this->render('product/showproduct.html.twig', [
'product' => $product,
'form' => $form->createView()
]);
}
}
