HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/SBogers10/komma.pro/app/KommaApp/Shop/Cart/ShoppingCartService.php
<?php
namespace App\KommaApp\Shop\Cart;


use App\KommaApp\Shop\Discounts\Actions\ModifyPriceAction;
use App\KommaApp\Shop\Discounts\DiscountableInterface;
use App\KommaApp\Shop\Discounts\Discount;
use App\KommaApp\Shop\Discounts\DiscountServiceInterface;
use App\KommaApp\Shop\Products\Product\Product;
use App\KommaApp\Shop\Products\ProductableInterface;

/**
 * Represents a shopping cart
 *
 * Class ShoppingCartService
 * @package App\KommaApp\Shop\Cart
 */
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[] $items
     */
    private $items;

    /**
     * @var Discount[] $discounts
     */
    private $discounts;

    /**
     * @var DiscountServiceInterface $discountService
     */
    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->getShoppingCartItemByProductableId($productable->id);
        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 $id
     * @return ShoppingCartItemInterface|false
     */
    private function getShoppingCartItemByProductableId($id)
    {
        foreach($this->items as $item)
        {
            /** @var ShoppingCartItemInterface $item */
            if($item->getProductable()->id == $id) 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);
    }
}