File: D:/HostingSpaces/SBogers95/rentman.io/app/Komma/Shop/Cart/ShoppingCartService.php
<?php
namespace App\Komma\Shop\Cart;
use App\Komma\Shop\Discounts\Actions\ModifyPriceAction;
use App\Komma\Shop\Discounts\Discount;
use App\Komma\Shop\Discounts\DiscountableInterface;
use App\Komma\Shop\Discounts\DiscountServiceInterface;
use App\Komma\Shop\Products\Product\Product;
use App\Komma\Shop\Products\ProductableInterface;
/**
* Represents a shopping cart
*
* Class ShoppingCartService
*/
class ShoppingCartService implements ShoppingCartServiceInterface, HasCouponCodesInterface
{
use HasCouponCodesTrait;
/**
* @var string the session root variable where to store shopping cart related data
*/
public static $sessionVariable = 'ShoppingCartService';
/**
* Indicates whether or not if the ShoppingCartService restores all items in the shopping cart by looking at the session variable
*
* @var bool
*/
public static $restoreFromSession = true;
/**
* @var ShoppingCartItemInterface[]
*/
private $items;
/**
* @var Discount[]
*/
private $discounts;
/**
* @var DiscountServiceInterface
*/
private $discountService;
public function __construct()
{
$this->items = [];
$this->discounts = [];
$this->discountService = \App::make(DiscountServiceInterface::class);
$this->restoreFromSession();
}
/**
* Add a productable in the cart
*
* @param ProductableInterface $productable
* @param int $amount
* @return ShoppingCartItem
*/
public function addProductable(ProductableInterface $productable, int $amount = 1) : ?ShoppingCartItemInterface
{
/** @var Product $product */
if (! $productable) {
return null;
}
/** @var ShoppingCartItemInterface $shoppingCartItem */
$item = $this->getShoppingCartItemByProductableIdAndType($productable);
if ($item) {
$item->setAmount($item->getAmount() + $amount);
} else {
$item = (\App::make(ShoppingCartItemInterface::class))->setProductable($productable)->setAmount($amount);
$this->items[] = $item;
}
$this->updateDiscounts();
session()->put(self::$sessionVariable, $this->items);
return $item;
}
/**
* Returns an existing shoppingCartItem by checking if it has a productable with a
* certain id or false if there was no shoppingcart item with a
* productable with the specified productable id
* @param $productable
* @return ShoppingCartItemInterface|false
*/
private function getShoppingCartItemByProductableIdAndType(ProductableInterface $productable)
{
foreach ($this->items as $item) {
$itemProductable = $item->getProductable();
/** @var ShoppingCartItemInterface $item */
if ($itemProductable->id == $productable->id && get_class($productable) === get_class($itemProductable)) {
return $item;
}
}
return false;
}
/**
* Set the amount of items for a product
*
* @param int $itemId
* @param int $amount
* @return $this
*/
public function setItemAmount(int $itemId, int $amount = 1): ShoppingCartServiceInterface
{
$item = $this->getItemById($itemId);
if (! $item) {
return $this;
}
$item->setAmount($amount);
$this->updateDiscounts();
session()->put(self::$sessionVariable, $this->items);
return $this;
}
/**
* Deletes the ShoppingCartItem that has a product with the specified id
*
* @param ProductableInterface $productable
* @return ShoppingCartServiceInterface
*/
public function deleteItem(ProductableInterface $productable) : ShoppingCartServiceInterface
{
foreach ($this->items as $index => $item) {
if ($item->getProductable()->id == $productable->id) {
array_splice($this->items, $index, 1);
break;
}
}
$this->updateDiscounts();
session()->put(self::$sessionVariable, $this->items);
return $this;
}
/**
* Clears the shopping cart of all items
*
* @return ShoppingCartServiceInterface
*/
public function clear(): ShoppingCartServiceInterface
{
$this->items = [];
$this->updateDiscounts();
session()->put(self::$sessionVariable, $this->items);
return $this;
}
/**
* Returns the sum of all base prices of products.
* If you specify the boolean argument as true it takes the CartDiscounts into account
* Remember the base price is in cents.
*
* @param bool $includeDiscounts
* @return float
*/
public function getTotal(bool $includeDiscounts = true): float
{
$price = 0;
if (count($this->items) > 0) {
foreach ($this->items as $index => $item) {
$price += $item->getTotal($includeDiscounts);
}
}
if ($includeDiscounts) {
foreach ($this->discounts as $discount) {
$action = $discount->getDiscountAction();
switch (get_class($action)) {
case ModifyPriceAction::class:
$price = $action->do($price);
}
}
}
// dd($this); //debugging helper
return $price;
}
/**
* Returns the amount of items in the cart.
* If you specify the $unique argument as true it returns the number of ShoppingCartItems.
* If it is false it will return the sum of all products in all Shopping cart items
* If you specify the $includeCartDiscounts argument as true it takes the Discount into account
* @param bool $unique
* @param bool $includeDiscounts
* @return int
*/
public function getItemsCount(bool $unique = false, bool $includeDiscounts = false): int
{
if ($includeDiscounts === false) {
$itemCount = 0;
if ($unique == true) {
$products = [];
foreach ($this->items as $shoppingCartItem) {
/** @var $shoppingCartItem ShoppingCartItem */
$productClass = get_class($shoppingCartItem->getProductable());
if (! in_array($productClass, $products)) {
$itemCount++;
$products[] = $productClass;
}
}
} else {
foreach ($this->items as $item) {
$itemCount = $itemCount + $item->getAmount();
}
}
return $itemCount;
} else {
//TODO Implement me
return 0;
}
}
/**
* Get all shopping cart items
*
* @return array
*/
public function getItems(): array
{
return ! empty($this->items) ? $this->items : [];
}
/**
* Applies the discount to itself
*
* @param Discount $discount
* @return DiscountableInterface
*/
public function applyDiscount(Discount $discount): DiscountableInterface
{
$this->discounts[] = $discount;
session()->put(self::$sessionVariable, $this->items);
return $this;
}
/**
* Returns all discounts applied
*
* @return Discount[]
*/
public function getDiscounts(): array
{
return $this->discounts;
}
/**
* Restores the shopping cart using the session
*
* @return void
*/
private function restoreFromSession(): void
{
if (session()->has(self::$sessionVariable)) {
$this->items = session()->get(self::$sessionVariable);
} else {
session()->put(self::$sessionVariable, []);
}
}
/**
* Get a shoppingCartItem by ID
*
* @param $itemId int
* @return ShoppingCartItemInterface
*/
private function getItemById(int $itemId): ?ShoppingCartItemInterface
{
$returnItem = null;
foreach ($this->items as $index => $item) {
if ($item->getId() == $itemId) {
$returnItem = $item;
}
}
return $returnItem;
}
/**
* Adds a coupon code. Notice that this does not mean that it is valid.
* Validation is done via the DiscountServiceInterface
*
* @param string $code
* @return mixed
*/
public function addCouponCode(string $code): bool
{
if (! in_array($code, $this->couponCodes)) {
$this->couponCodes[] = $code;
$this->updateDiscounts();
return true;
}
return false;
}
/**
* Removes all discounts
*/
public function clearDiscounts(): void
{
$this->discounts = [];
foreach ($this->items as $shoppingCartItem) {
$shoppingCartItem->clearDiscounts();
}
}
/**
* Updates the discounts on the shopping cart and all shoppingCartItems after removing all discounts from them.
*/
public function updateDiscounts(): void
{
$this->clearDiscounts();
$this->discountService->updateDiscounts($this);
foreach ($this->items as $shoppingCartItem) {
$this->discountService->updateDiscounts($shoppingCartItem);
}
}
}