This extension adds shopping cart for Yii framework 2.0
The preferred way to install this extension is through composer.
Either run
php composer.phar require --prefer-dist omnilight/yii2-shopping-cart "*"
or add
"omnilight/yii2-shopping-cart": "*"
to the require
section of your composer.json.
In your model:
class Product extends ActiveRecord implements CartPositionInterface
{
use CartPositionTrait;
public function getPrice()
{
return $this->price;
}
public function getId()
{
return $this->id;
}
}
In your controller:
public function actionAddToCart($id)
{
$cart = new ShoppingCart();
$model = Product::findOne($id);
if ($model) {
$cart->put($model, 1);
return $this->redirect(['cart-view']);
}
throw new NotFoundHttpException();
}
Also you can use cart as global application component:
[
'components' => [
'cart' => [
'class' => 'yz\shoppingcart\ShoppingCart',
'cartId' => 'my_application_cart',
]
]
]
And use it in the following way:
\Yii::$app->cart->put($cartPosition, 1);
In order to get number of items in the cart:
$itemsCount = \Yii::$app->cart->getCount();
In order to get total cost of items in the cart:
$total = \Yii::$app->cart->getCost();
If the original model that you want to use as cart position is too heavy to be stored in the session, you can create a separate class implementing CartPositionInterface, and original model can implement CartPositionProviderInterface:
// app\models\Product.php
class Product extends ActiveRecord implements CartPositionProviderInterface
{
public function getCartPosition()
{
return \Yii::createObject([
'class' => 'app\models\ProductCartPosition',
'id' => $this->id,
]);
}
}
// app\models\ProductCartPosition.php
class ProductCartPosition extends Object implements CartPositionInterface
{
/**
* @var Product
*/
protected $_product;
public $id;
public function getId()
{
return $this->id;
}
public function getPrice()
{
return $this->getProduct()->price;
}
/**
* @return Product
*/
public function getProduct()
{
if ($this->_product === null) {
$this->_product = Product::findOne($this->id);
}
return $this->_product;
}
}
This way gives us ability to create separate cart positions for the same product, that differs only on some property, for example price or color:
// app\models\ProductCartPosition.php
class ProductCartPosition extends Object implements CartPositionInterface
{
public $id;
public $price;
public $color;
//...
public function getId()
{
return md5(serialize([$this->id, $this->price, $this->color]));
}
//...
}
Discounts are implemented as behaviors that could attached to the cart or it's positions. To use them, follow this steps:
- Define discount class as a subclass of yz\shoppingcart\DiscountBehavior
// app/components/MyDiscount.php
class MyDiscount extends DiscountBehavior
{
/**
* @param CostCalculationEvent $event
*/
public function onCostCalculation($event)
{
// Some discount logic, for example
$event->discountValue = 100;
}
}
- Add this behavior to the cart:
$cart->attachBehavior('myDiscount', ['class' => 'app\components\MyDiscount']);
If discount is suitable not for the whole cart, but for the individual positions, than it is possible to attach discount to the cart position itself:
$cart->getPositionById($positionId)->attachBehavior('myDiscount', ['class' => 'app\components\MyDiscount']);
Note, that the same behavior could be used for both cart and position classes.
- To get total cost with discount applied:
$total = \Yii::$app->cart->getCost(true);
- During the calculation the following events are triggered:
ShoppingCart::EVENT_COST_CALCULATION
once per calculation.CartPositionInterface::EVENT_COST_CALCULATION
for each position in the cart.
You can also subscribe on this events to perform discount calculation:
$cart->on(ShoppingCart::EVENT_COST_CALCULATION, function ($event) {
$event->discountValue = 100;
});