Files
LaravelShoppingcart/src/CartItem.php

510 lines
13 KiB
PHP

<?php
namespace Gloudemans\Shoppingcart;
use Gloudemans\Shoppingcart\Contracts\Buyable;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
class CartItem implements Arrayable, Jsonable
{
/**
* The rowID of the cart item.
*
* @var string
*/
public $rowId;
/**
* The ID of the cart item.
*
* @var int|string
*/
public $id;
/**
* The quantity for this cart item.
*
* @var int|float
*/
public $qty;
/**
* The name of the cart item.
*
* @var string
*/
public $name;
/**
* The price without TAX of the cart item.
*
* @var float
*/
public $price;
/**
* The weight of the product.
*
* @var float
*/
public $weight;
/**
* The options for this cart item.
*
* @var array
*/
public $options;
/**
* The FQN of the associated model.
*
* @var string|null
*/
private $associatedModel = null;
/**
* The tax rate for the cart item.
*
* @var int|float
*/
private $taxRate = 0;
/**
* The discount rate for the cart item.
*
* @var float
*/
private $discountRate = 0;
/**
* CartItem constructor.
*
* @param int|string $id
* @param string $name
* @param float $price
* @param array $options
*/
public function __construct($id, $name, $price, $weight = 0, array $options = [])
{
if (empty($id)) {
throw new \InvalidArgumentException('Please supply a valid identifier.');
}
if (empty($name)) {
throw new \InvalidArgumentException('Please supply a valid name.');
}
if (strlen($price) < 0 || !is_numeric($price)) {
throw new \InvalidArgumentException('Please supply a valid price.');
}
if (strlen($weight) < 0 || !is_numeric($weight)) {
throw new \InvalidArgumentException('Please supply a valid weight.');
}
$this->id = $id;
$this->name = $name;
$this->price = floatval($price);
$this->weight = floatval($weight);
$this->options = new CartItemOptions($options);
$this->rowId = $this->generateRowId($id, $options);
}
/**
* Returns the formatted weight.
*
* @param int $decimals
* @param string $decimalPoint
* @param string $thousandSeperator
*
* @return string
*/
public function weight($decimals = null, $decimalPoint = null, $thousandSeperator = null)
{
return $this->numberFormat($this->weight, $decimals, $decimalPoint, $thousandSeperator);
}
/**
* Returns the formatted price without TAX.
*
* @param int $decimals
* @param string $decimalPoint
* @param string $thousandSeperator
*
* @return string
*/
public function price($decimals = null, $decimalPoint = null, $thousandSeperator = null)
{
return $this->numberFormat($this->price, $decimals, $decimalPoint, $thousandSeperator);
}
/**
* Returns the formatted price with discount applied.
*
* @param int $decimals
* @param string $decimalPoint
* @param string $thousandSeperator
*
* @return string
*/
public function priceTarget($decimals = null, $decimalPoint = null, $thousandSeperator = null)
{
return $this->numberFormat($this->priceTarget, $decimals, $decimalPoint, $thousandSeperator);
}
/**
* Returns the formatted price with TAX.
*
* @param int $decimals
* @param string $decimalPoint
* @param string $thousandSeperator
*
* @return string
*/
public function priceTax($decimals = null, $decimalPoint = null, $thousandSeperator = null)
{
return $this->numberFormat($this->priceTax, $decimals, $decimalPoint, $thousandSeperator);
}
/**
* Returns the formatted subtotal.
* Subtotal is price for whole CartItem without TAX.
*
* @param int $decimals
* @param string $decimalPoint
* @param string $thousandSeperator
*
* @return string
*/
public function subtotal($decimals = null, $decimalPoint = null, $thousandSeperator = null)
{
return $this->numberFormat($this->subtotal, $decimals, $decimalPoint, $thousandSeperator);
}
/**
* Returns the formatted total.
* Total is price for whole CartItem with TAX.
*
* @param int $decimals
* @param string $decimalPoint
* @param string $thousandSeperator
*
* @return string
*/
public function total($decimals = null, $decimalPoint = null, $thousandSeperator = null)
{
return $this->numberFormat($this->total, $decimals, $decimalPoint, $thousandSeperator);
}
/**
* Returns the formatted tax.
*
* @param int $decimals
* @param string $decimalPoint
* @param string $thousandSeperator
*
* @return string
*/
public function tax($decimals = null, $decimalPoint = null, $thousandSeperator = null)
{
return $this->numberFormat($this->tax, $decimals, $decimalPoint, $thousandSeperator);
}
/**
* Returns the formatted tax.
*
* @param int $decimals
* @param string $decimalPoint
* @param string $thousandSeperator
*
* @return string
*/
public function taxTotal($decimals = null, $decimalPoint = null, $thousandSeperator = null)
{
return $this->numberFormat($this->taxTotal, $decimals, $decimalPoint, $thousandSeperator);
}
/**
* Returns the formatted discount.
*
* @param int $decimals
* @param string $decimalPoint
* @param string $thousandSeperator
*
* @return string
*/
public function discount($decimals = null, $decimalPoint = null, $thousandSeperator = null)
{
return $this->numberFormat($this->discount, $decimals, $decimalPoint, $thousandSeperator);
}
/**
* Returns the formatted total discount for this cart item.
*
* @param int $decimals
* @param string $decimalPoint
* @param string $thousandSeperator
*
* @return string
*/
public function discountTotal($decimals = null, $decimalPoint = null, $thousandSeperator = null)
{
return $this->numberFormat($this->discountTotal, $decimals, $decimalPoint, $thousandSeperator);
}
/**
* Set the quantity for this cart item.
*
* @param int|float $qty
*/
public function setQuantity($qty)
{
if (empty($qty) || !is_numeric($qty)) {
throw new \InvalidArgumentException('Please supply a valid quantity.');
}
$this->qty = $qty;
}
/**
* Update the cart item from a Buyable.
*
* @param \Gloudemans\Shoppingcart\Contracts\Buyable $item
*
* @return void
*/
public function updateFromBuyable(Buyable $item)
{
$this->id = $item->getBuyableIdentifier($this->options);
$this->name = $item->getBuyableDescription($this->options);
$this->price = $item->getBuyablePrice($this->options);
$this->priceTax = $this->price + $this->tax;
}
/**
* Update the cart item from an array.
*
* @param array $attributes
*
* @return void
*/
public function updateFromArray(array $attributes)
{
$this->id = array_get($attributes, 'id', $this->id);
$this->qty = array_get($attributes, 'qty', $this->qty);
$this->name = array_get($attributes, 'name', $this->name);
$this->price = array_get($attributes, 'price', $this->price);
$this->weight = array_get($attributes, 'weight', $this->weight);
$this->priceTax = $this->price + $this->tax;
$this->options = new CartItemOptions(array_get($attributes, 'options', $this->options));
$this->rowId = $this->generateRowId($this->id, $this->options->all());
}
/**
* Associate the cart item with the given model.
*
* @param mixed $model
*
* @return \Gloudemans\Shoppingcart\CartItem
*/
public function associate($model)
{
$this->associatedModel = is_string($model) ? $model : get_class($model);
return $this;
}
/**
* Set the tax rate.
*
* @param int|float $taxRate
*
* @return \Gloudemans\Shoppingcart\CartItem
*/
public function setTaxRate($taxRate)
{
$this->taxRate = $taxRate;
return $this;
}
/**
* Set the discount rate.
*
* @param int|float $discountRate
*
* @return \Gloudemans\Shoppingcart\CartItem
*/
public function setDiscountRate($discountRate)
{
$this->discountRate = $discountRate;
return $this;
}
/**
* Get an attribute from the cart item or get the associated model.
*
* @param string $attribute
*
* @return mixed
*/
public function __get($attribute)
{
if (property_exists($this, $attribute)) {
return $this->{$attribute};
}
switch ($attribute) {
case 'discount':
return $this->price * ($this->discountRate / 100);
case 'priceTarget':
return $this->price - $this->discount;
case 'subtotal':
return $this->priceTarget * $this->qty;
case 'tax':
return $this->priceTarget * ($this->taxRate / 100);
case 'priceTax':
return $this->priceTarget + $this->tax;
case 'total':
return $this->priceTax * $this->qty;
case 'taxTotal':
return $this->tax * $this->qty;
case 'discountTotal':
return $this->discount * $this->qty;
case 'weightTotal':
return $this->weight * $this->qty;
case 'model':
if (isset($this->associatedModel)) {
return with(new $this->associatedModel())->find($this->id);
}
case 'modelFQCN':
if (isset($this->associatedModel)) {
return $this->associatedModel;
}
default:
return;
}
}
/**
* Create a new instance from a Buyable.
*
* @param \Gloudemans\Shoppingcart\Contracts\Buyable $item
* @param array $options
*
* @return \Gloudemans\Shoppingcart\CartItem
*/
public static function fromBuyable(Buyable $item, array $options = [])
{
return new self($item->getBuyableIdentifier($options), $item->getBuyableDescription($options), $item->getBuyablePrice($options), $item->getBuyableWeight($options), $options);
}
/**
* Create a new instance from the given array.
*
* @param array $attributes
*
* @return \Gloudemans\Shoppingcart\CartItem
*/
public static function fromArray(array $attributes)
{
$options = array_get($attributes, 'options', []);
return new self($attributes['id'], $attributes['name'], $attributes['price'], $attributes['weight'], $options);
}
/**
* Create a new instance from the given attributes.
*
* @param int|string $id
* @param string $name
* @param float $price
* @param array $options
*
* @return \Gloudemans\Shoppingcart\CartItem
*/
public static function fromAttributes($id, $name, $price, $weight, array $options = [])
{
return new self($id, $name, $price, $weight, $options);
}
/**
* Generate a unique id for the cart item.
*
* @param string $id
* @param array $options
*
* @return string
*/
protected function generateRowId($id, array $options)
{
ksort($options);
return md5($id.serialize($options));
}
/**
* Get the instance as an array.
*
* @return array
*/
public function toArray()
{
return [
'rowId' => $this->rowId,
'id' => $this->id,
'name' => $this->name,
'qty' => $this->qty,
'price' => $this->price,
'weight' => $this->weight,
'options' => $this->options->toArray(),
'discount' => $this->discount,
'tax' => $this->tax,
'subtotal' => $this->subtotal,
];
}
/**
* Convert the object to its JSON representation.
*
* @param int $options
*
* @return string
*/
public function toJson($options = 0)
{
return json_encode($this->toArray(), $options);
}
/**
* Get the formatted number.
*
* @param float $value
* @param int $decimals
* @param string $decimalPoint
* @param string $thousandSeperator
*
* @return string
*/
private function numberFormat($value, $decimals, $decimalPoint, $thousandSeperator)
{
if (is_null($decimals)) {
$decimals = config('cart.format.decimals', 2);
}
if (is_null($decimalPoint)) {
$decimalPoint = config('cart.format.decimal_point', '.');
}
if (is_null($thousandSeperator)) {
$thousandSeperator = config('cart.format.thousand_separator', ',');
}
return number_format($value, $decimals, $decimalPoint, $thousandSeperator);
}
}