Fork me on GitHub

Shopping Cart

Provides shpping cart functionality for models.

Cart is a container object that holds items collection and have handy methods to work with it.

It uses user session as a cart data storage.

Installing and configuring

1 way: Registration in the config file

Add to protected/config/main.php:

'import'=>array(
    'ext.yiiext.components.shoppingCart.*'
),
 
'components' => array(
  'shoppingCart' =>
    array(
        'class' => 'ext.yiiext.components.shoppingCart.EShoppingCart',
    ),
)

2 way: Registration by necessity

$cart = Yii::createComponent(array(
    'class' => 'ext.yiiext.components.shoppingCart.EShoppingCart'
));
//Important!
$cart->init();
 
$book = Book::model()->findByPk(1);
$cart->put($book);

Preparing a model

Models that you are planning to put into the cart should implement IECartPosition interface:

class Book extends CActiveRecord implements IECartPosition {
    public static function model($className = __CLASS__) {
        return parent::model($className);
    }
 
    function getId(){
        return 'Book'.$this->id;
    }
 
    function getPrice(){
        return $this->price;
    }
}

API

EShoppingCart::put($position, $quantity)

Adds $quantity items to the cart. If item is already in the cart, item data is being updated and item quantity is summed with $quantity.

$book = Book::model()->findByPk(1);
Yii::app()->shoppingCart->put($book); //1 item with id=1, quantity=1.
Yii::app()->shoppingCart->put($book,2); //1 item with id=1, quantity=3.
$book2 = Book::model()->findByPk(2);
Yii::app()->shoppingCart->put($book2); //2 items with id=1 and id=2.

EShoppingCart::update($position, $quantity)

Updates cart item. If item is already in the cart, item data is being updated and item quantity is set to $quantity. If there is no such item yet it will be added. If $quantity<1 then item will be deleted.

$book = Book::model()->findByPk(1);
Yii::app()->shoppingCart->put($book); //1 item with id=1, quantity=1.
Yii::app()->shoppingCart->update($book,2); //1 item with id=1, quantity=2.

EShoppingCart::remove($key)

Removes item from the cart.

$book = Book::model()->findByPk(1);
Yii::app()->shoppingCart->put($book,2); //1 item with id=1, quantity=2.
Yii::app()->shoppingCart->remove($book->getId()); //no items

EShoppingCart::clear()

Clears all cart items.

Yii::app()->shoppingCart->clear();

EShoppingCart::itemAt($key)

Returns item at key $key.

$position = Yii::app()->shoppingCart->itemAt(1);

EShoppingCart::contains($key)

Tells if cart contains item with id=$key.

$position = Yii::app()->shoppingCart->itemAt();

EShoppingCart::isEmpty()

Tells if cart is empty.

$position = Yii::app()->shoppingCart->isEmpty(1);

EShoppingCart::getCount()

Returns positions count.

Yii::app()->shoppingCart->put($book,2);
Yii::app()->shoppingCart->put($book2,3);
Yii::app()->shoppingCart->getCount(); //2

EShoppingCart::getItemsCount()

Returns items count.

Yii::app()->shoppingCart->put($book,2);
Yii::app()->shoppingCart->put($book2,3);
Yii::app()->shoppingCart->getItemsCount(); //5

EShoppingCart::getCost($withDiscount)

Returns cart total.

Yii::app()->shoppingCart->put($book,2); //price=100
Yii::app()->shoppingCart->put($book2,1); //price=200
Yii::app()->shoppingCart->getCost(); //400

EShoppingCart::getPositions()

Returns an array with all positions.

$positions = Yii::app()->shoppingCart->getPositions();
foreach($positions as $position) {
...
}

IECartPosition::getPrice()

Returns a price for a single item for this position.

$positions = Yii::app()->shoppingCart->getPositions();
foreach($positions as $position) {
$price = $position->getPrice();
}

IECartPosition::getSumPrice($withDiscount)

Returns position price = single item price*items count

$book = Book::model()->findByPk(1); //price = 100
Yii::app()->shoppingCart->put($book,2); //putting 2 items
$positions = Yii::app()->shoppingCart->getPositions();
foreach($positions as $position) {
$price = $position->getSumPrice(); //200 (2*100)
}

IECartPosition::getQuantity()

Returns position items quantity

$book = Book::model()->findByPk(1); //price = 100
Yii::app()->shoppingCart->put($book,2); //putting 2 items
$positions = Yii::app()->shoppingCart->getPositions();
foreach($positions as $position) {
$price = $position->getQuantity(); //2
}

Discounts

There is a single discount system built in. It allows to apply a set of rules that will change cart total or a single position price.

Discount is a class that implements IEDiscount and defines apply() method that describes how exactly discount is applied.

Discount is calculated by applying Position::addDiscountPrice/Position::setDiscountPrice position's method or EShoppingCart::addDiscountPrice/EShoppingCart::setDiscountPrice cart-wide method. This methods are getting one parameter that holds a value of cart total reduction or individual position reduction.

Discount class example:

class TestDiscount extends IEDiscount {
    /**
     * % discount
     */
    public $rate = 30;
 
    public function apply() {
        foreach ($this->shoppingCart as $position) {
            $quantity = $position->getQuantity();
            if ($quantity > 1) {
                $discountPrice = $this->rate * $position->getPrice() / 100;
                $position->addDiscountPrice($discountPrice);
            }
        }
    }
}

This example dicount works like this: if there is more than one item for a single position, there will be $rate % discount for one item and it will be applied to position price.

You can apply unlimited discount rules that will be called one by one:

'shoppingCart' =>
        array(
            'class' => 'ext.yiiext.components.shoppingCart.EShoppingCart',
            'discounts' =>
            array(
                array(
                    'class' => 'ext.yiiext.components.shoppingCart.discounts.TestDiscount',
                    'rate' => 40),
                array('class' => 'otherDiscount'),
            ),
 
        ),

Events

There are 2 events in ShoppingCart implemented in a standard Yii way:

1) onUpdatePosition - is triggered when position is added or updated.

2) onRemovePosition - is triggered when position is deleted.

Usage:

$cN = new CallCenterNotifier();
Yii::app()->shoppingCart->attachEventHandler('onUpdatePosition',array($cN, 'updatePositionInShoppingCart'));
 
$book = Book::model()->findByPk(1);
Yii::app()->shoppingCart->put($book);

When onUpdatePosition event is fired, call center will be notified.

Working with a cart as CMap

ShoppingCart is a child of CMap so you can work with the cart as an array.

$book = Book::model()->findByPk(1);
Yii::app()->shoppingCart[] = $book; //adding new position.
 
//iterating over all positions
foreach(Yii::app()->shoppingCart as $position)
{
...
}

Changelog

0.9

  • Added optional cartId property to EShoppingCart (rak)
  • Renamed onUpdatePoistion to onUpdatePosition (rak)
  • Fixed the bug when ECartPositionBehaviour is attached multiple times (rak)
  • Added ability to connect EShoppingCart by necessity (rak)

0.8

  • Added ECartPositionBehavior::setDiscountPrice (Sam Dark)
  • Added EShoppingCart::setDiscountPrice (Sam Dark)

0.7

  • Updated English readme (Sam Dark)
  • Refactor: renamed variables and methods.
  • Updated documentation.
  • Add Discounts.
  • Add new Methods.
  • Add Events.
  • New Unit tests.

0.6

  • New naming conventions.
  • English readme.

0.5rc2

  • Fixed bug when product count was set to zero when restoring from session.
  • Changed behaviour of put() method.
  • Added update() method. Updates cart object info.

0.5

  • Now only IECartPosition object could be put into cart.
  • Method names changed.
  • Unit tests.
  • PHP native interface checks.
  • Renamed cart class to CShoppingCart.
  • Single model can be put in array style.

0.2

  • Initial relase.

Allows to put models into shopping cart and do various operations with it.

Documentation

Downloads (Tags)

Resources