Skip to content

Commit

Permalink
Improving the cart clone/switch handler (#7)
Browse files Browse the repository at this point in the history
* Cloning the cart instead of the old method

* Add Exception clas for Cart, modification method getTotal in CartManager, we can now optionaly pass the cart id (#8)
  • Loading branch information
benjamin-hubert authored Nov 30, 2016
1 parent d21fb4f commit 1cc6e41
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 62 deletions.
4 changes: 4 additions & 0 deletions AlpixelShopEvents.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ class AlpixelShopEvents
const CART_PRE_VALIDATION = 'alpixel_shop.cart.event.pre_cart_validation';
const CART_PROCESS = 'alpixel_shop.cart.event.process_for_order';

const CART_PRE_MEMORIZE = 'alpixel_shop.cart.event.pre.cart_memorize';
const CART_POST_MEMORIZE = 'alpixel_shop.cart.event.post.cart_memorize';

const CART_CREATED = 'alpixel_shop.cart.event.cart_created';
const CART_UPDATED = 'alpixel_shop.cart.event.cart_updated';

const CART_PRE_EMPTY = 'alpixel_shop.cart.event.pre.cart_empty';
const CART_POST_EMPTY = 'alpixel_shop.cart.event.post.cart_empty';

Expand Down
29 changes: 28 additions & 1 deletion Entity/Cart.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
namespace Alpixel\Bundle\ShopBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Types\ArrayType;
use Doctrine\ORM\Mapping as ORM;

/**
* Cart.
*
* @ORM\Table(name="alpixel_shop_cart")
* @ORM\Entity(repositoryClass="Alpixel\Bundle\ShopBundle\Repository\CartRepository")
* @ORM\HasLifecycleCallbacks()
*/
class Cart
{
Expand Down Expand Up @@ -54,7 +56,32 @@ class Cart
public function __construct()
{
$this->cartProducts = new ArrayCollection();
$this->name = date('Y-m-d H:i:s');
}

public function __clone()
{
$newProductCollection = new ArrayCollection();
foreach ($this->cartProducts as $cartProduct) {
$newCartProduct = clone $cartProduct;
$newCartProduct->setCart($this);
$newProductCollection->add($newCartProduct);
}

$this->createdAt = new \DateTime();
$this->updatedAt = new \DateTime();
$this->cartProducts = $newProductCollection;
$this->order = null;
$this->name = null;
}

/**
* @ORM\PrePersist()
*/
public function generateName()
{
if (empty($this->name)) {
$this->name = date('d/m/Y H\Hi');
}
}

/**
Expand Down
7 changes: 7 additions & 0 deletions Entity/CartProduct.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ public function __toString()
return self::class.' #'.$this->id;
}

public function __clone()
{
$this->cart = null;
$this->createdAt = new \DateTime();
$this->updatedAt = new \DateTime();
}

/**
* Get id.
*
Expand Down
27 changes: 27 additions & 0 deletions Entity/Customer.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ class Customer extends BaseUser
*/
protected $currency;

/**
* @ORM\ManyToOne(targetEntity="\Alpixel\Bundle\ShopBundle\Entity\Cart")
* @ORM\JoinColumn(name="cart_id", referencedColumnName="id", onDelete="SET NULL")
*/
protected $currentCart;

public function __toString()
{
return $this->firstname.' '.strtoupper($this->lastname);
Expand Down Expand Up @@ -120,4 +126,25 @@ public function setFirstname($firstname)

return $this;
}

/**
* @return Cart
*/
public function getCurrentCart()
{
return $this->currentCart;
}

/**
* @param Cart $currentCart
* @return Customer
*/
public function setCurrentCart($currentCart)
{
$this->currentCart = $currentCart;

return $this;
}


}
19 changes: 19 additions & 0 deletions Exception/CartAccessDeniedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Alpixel\Bundle\ShopBundle\Exception;


/**
* @author Alexis BUSSIERES <[email protected]>
*/
class CartAccessDeniedException extends \Exception
{
public function __construct($message = "", $code = 0, \Exception $previous = null)
{
if ($message === "") {
$message = 'Access cart denied.';
}

parent::__construct($message, $code, $previous);
}
}
19 changes: 19 additions & 0 deletions Exception/CartNotFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Alpixel\Bundle\ShopBundle\Exception;


/**
* @author Alexis BUSSIERES <[email protected]>
*/
class CartNotFoundException extends \Exception
{
public function __construct($message = "", $code = 0, \Exception $previous = null)
{
if ($message === "") {
$message = 'Cart not found.';
}

parent::__construct($message, $code, $previous);
}
}
144 changes: 102 additions & 42 deletions Helper/Cart/CartManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
use Alpixel\Bundle\ShopBundle\Event\CartEvent;
use Alpixel\Bundle\ShopBundle\Event\CartProcessEvent;
use Alpixel\Bundle\ShopBundle\Event\CartProductEvent;
use Alpixel\Bundle\ShopBundle\Exception\CartAccessDeniedException;
use Alpixel\Bundle\ShopBundle\Exception\CartNotFoundException;
use Alpixel\Bundle\ShopBundle\Exception\NoProductException;
use Alpixel\Bundle\ShopBundle\Exception\OutOfStockException;
use Doctrine\ORM\EntityManager;
Expand Down Expand Up @@ -101,19 +103,26 @@ protected function createCart()
}

/**
* @param \Alpixel\Bundle\ShopBundle\Entity\Customer $customer
* @return \Alpixel\Bundle\ShopBundle\Entity\Cart|mixed|null|object
*/
public function getCurrentCart()
public function getCurrentCart(Customer $customer = null)
{
$cart = $this->sessionCart->getCurrent();
if ($cart !== null) {
return $this->entityManager->getRepository('AlpixelShopBundle:Cart')
->find($cart);
if ($customer === null) {
$cart = $this->sessionCart->getCurrent();
if ($cart !== null) {
return $this->entityManager
->getRepository('AlpixelShopBundle:Cart')
->find($cart);
}
}

if ($this->customer !== null) {
$cart = $this->entityManager->getRepository('AlpixelShopBundle:Cart')
->findOneCurrentCartByCustomer($this->customer);
if ($customer === null) {
$customer = $this->customer;
}

if ($customer !== null) {
$cart = $customer->getCurrentCart();
if ($cart !== null) {
$this->sessionCart->setCurrent($cart);
}
Expand All @@ -125,12 +134,28 @@ public function getCurrentCart()
/**
* @param bool $withProductDiscount
* @param bool $withCartDiscount
* @param null $cartId
* @return float|int
* @throws CartAccessDeniedException
* @throws CartNotFoundException
*/
public function getTotal($withProductDiscount = true, $withCartDiscount = true)
public function getTotal($withProductDiscount = true, $withCartDiscount = true, $cartId = null)
{
$total = 0;
$cart = $this->getCurrentCart();

if ($cartId === null) {
$cart = $this->getCurrentCart();
} else {
$cart = $this->entityManager->getRepository('AlpixelShopBundle:Cart')->find($cartId);

if ($cart === null) {
throw new CartNotFoundException(sprintf('Unable to find a cart with id "%s"', $cartId));
}

if (!$this->cartBelongsToCustomer($cart)) {
throw new CartAccessDeniedException();
}
}

foreach ($cart->getCartProducts() as $cartProduct) {
$total += $this->priceHelper->getProductPrice(
Expand Down Expand Up @@ -160,25 +185,26 @@ public function getCartDiscount()
}

/**
* @param \Alpixel\Bundle\ShopBundle\Entity\Customer $customer
* @return \Alpixel\Bundle\ShopBundle\Entity\Cart
*/
private function newCart()
private function newCart(Customer $customer = null)
{
$cart = new Cart();
$cart->setCustomer($this->customer);
$this->saveCart($cart);
if ($customer === null) {
$customer = $this->customer;
}

return $cart;
}
$cart = new Cart();
$cart->setCustomer($customer);
$customer->setCurrentCart($cart);

/**
* @param \Alpixel\Bundle\ShopBundle\Entity\Cart $cart
*/
protected function saveCart(Cart $cart)
{
$this->entityManager->persist($cart);
$this->entityManager->persist($cart->getCustomer());
$this->entityManager->flush();

$this->sessionCart->setCurrent($cart);

return $cart;
}

/**
Expand All @@ -200,7 +226,6 @@ public function cancelCurrentCart()
$this->dispatcher->dispatch(AlpixelShopEvents::CART_POST_EMPTY, new CartEvent($cart));

$cart = $this->newCart();
$this->saveCart($cart);
$this->dispatcher->dispatch(AlpixelShopEvents::CART_CREATED, new CartEvent($cart));
} else {
$this->dispatcher->dispatch(AlpixelShopEvents::CART_POST_EMPTY, new CartEvent($cart));
Expand Down Expand Up @@ -234,7 +259,8 @@ public function addToCart(Product $product, $quantity = 0)
$cart = $this->getCurrentCart();
$this->dispatcher->dispatch(AlpixelShopEvents::CART_PRODUCT_PRE_ADD, new CartProductEvent($cartProduct));
$cart->addCartProduct($cartProduct);
$this->saveCart($cart);
$this->entityManager->persist($cart);
$this->entityManager->flush();
}

$this->dispatcher->dispatch(AlpixelShopEvents::CART_PRODUCT_POST_ADD, new CartProductEvent($cartProduct));
Expand Down Expand Up @@ -323,7 +349,7 @@ public function removeQuantityFromCartProduct(CartProduct $cartProduct, $quantit

$this->entityManager->flush();

if(count($cart->getCartProducts()) === 0) {
if (count($cart->getCartProducts()) === 0) {
$this->cancelCurrentCart();
}

Expand Down Expand Up @@ -384,39 +410,73 @@ public function getCustomer()
}

/**
* @return Cart|null
* @param \Alpixel\Bundle\ShopBundle\Entity\Cart $cart
* @param String $newName
* @param Boolean $deleteAfterMemorize
* @return \Alpixel\Bundle\ShopBundle\Entity\Cart|null
*/
public function saveKeepCart($name = null)
public function memorize(Cart $cart, $newName = null, $deleteAfterMemorize = true)
{
$cart = $this->getCurrentCart();
if ($cart->getCartProducts()->count() === 0) {
throw new \InvalidArgumentException("A cart must have items to be cloned");
}

if ($cart !== null && $cart->getCartProducts()->count() > 0 && $this->getCustomer() !== null) {
if (is_string($name) && !empty($name)) {
$cart->setName($name);
$this->entityManager->persist($cart);
$this->entityManager->flush();
}
$this->dispatcher->dispatch(AlpixelShopEvents::CART_PRE_MEMORIZE, new CartEvent($cart));
if ($deleteAfterMemorize === false) {
$newCart = clone $cart;
$newCart->setName($newName);

$this->entityManager->persist($newCart);
$this->entityManager->flush();

$this->dispatcher->dispatch(AlpixelShopEvents::CART_POST_MEMORIZE, new CartEvent($newCart));

return $this->newCart();
return $newCart;
} else {
$cart->setName($newName);

$newCart = $this->newCart();
$this->dispatcher->dispatch(AlpixelShopEvents::CART_CREATED, new CartEvent($newCart));
$this->dispatcher->dispatch(AlpixelShopEvents::CART_POST_MEMORIZE, new CartEvent($cart));

return $cart;
}

return null;
}

/**
* @param Cart $cart
* @param Customer|null $customer
* @return bool
* @param bool $keepSavedCart
* @return Cart
*/
public function switchCurrentCart(Cart $cart, Customer $customer = null)
public function switchCart(Cart $cart, Customer $customer = null, $keepSavedCart = true)
{
$isSwitched = false;
if ($cart->getOrder() === null && $this->cartBelongsToCustomer($cart, $customer)) {
$this->sessionCart->setCurrent($cart);
$isSwitched = true;
if($customer === null) {
$customer = $this->customer;
}

return $isSwitched;
if ($this->cartBelongsToCustomer($cart, $customer)) {

$oldCart = $this->getCurrentCart();

if ($keepSavedCart === false) {
$newCart = $cart;
} else {
$newCart = clone $cart;
}

$customer->setCurrentCart($newCart);
$this->sessionCart->setCurrent($newCart);
$this->entityManager->persist($customer);
$this->entityManager->remove($oldCart);
$this->entityManager->flush();

return $newCart;

} else {
throw new \InvalidArgumentException('This cart does not belong to this customer');
}
}

/**
Expand Down
Loading

0 comments on commit 1cc6e41

Please sign in to comment.