Fork me on GitHub

Shopping Cart

Компонент для реализации корзины моделей.

Корзина - объект контейнер, для хранения коллекции позиций, и методами для работы с этой коллекцией.

Состояние корзины между запросами хранится в сессии пользователя.

Установка и настройка

1 вариант: Подключение через конфиг

В protected/config/main.php добавить:

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

2 вариант: Подключение по необходимости

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

Подготавливаем модель

Модели, которым необходимо дать возможность добавления в корзину, должны реализовать интерфейс IECartPosition:

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)

Добавляет в корзину позицию товара в количестве $quantity. Если позиция товара уже была в корзине, то данные модели обновляются, а количество увеличивается на $quantity

$book = Book::model()->findByPk(1);
Yii::app()->shoppingCart->put($book); //в корзине 1 позиция с id=1 в количестве 1 единица.
Yii::app()->shoppingCart->put($book,2); //в корзине 1 позиция с id=1 в количестве 3 единицы.
$book2 = Book::model()->findByPk(2);
Yii::app()->shoppingCart->put($book2); //в корзине 2 позиции с id=1 и id=2

EShoppingCart::update($position, $quantity)

Обновляет в корзине позицию товара. Если позиция товара уже была в корзине, то данные модели обновляются, а количество установится в $quantity. Если позиции не было в корзине, то она добавляется в ней. Если установлено $quantity<1, то позиция удаляется из корзины

$book = Book::model()->findByPk(1);
Yii::app()->shoppingCart->put($book); //в корзине 1 позиция с id=1 в количестве 1 единица.
Yii::app()->shoppingCart->update($book,2); //в корзине 1 позиция с id=1 в количестве 2 единицы.

EShoppingCart::remove($key)

Удаляет позицию из корзины

$book = Book::model()->findByPk(1);
Yii::app()->shoppingCart->put($book,2); //в корзине 1 позиция с id=1 в количестве 2 единицы.
Yii::app()->shoppingCart->remove($book->getId()); //в корзине нет позиций

EShoppingCart::clear()

Очищает корзину

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

EShoppingCart::itemAt($key)

Возвращает позицию по ключу

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

EShoppingCart::contains($key)

Возвращает boolean: есть ли в корзине позиция с id=$key?

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

EShoppingCart::isEmpty()

Возвращает true, если корзина пустая.

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

EShoppingCart::getCount()

Возвращает количество позиций

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

EShoppingCart::getItemsCount()

Возвращает количество товаров

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

EShoppingCart::getCost($withDiscount)

Возвращает стоимость всей корзины

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

EShoppingCart::getPositions()

Возвращает массив позиций

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

IECartPosition::getPrice()

Возвращает цену одной единицы позиции

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

IECartPosition::getSumPrice($withDiscount)

Возвращает стоимость позиции = стоимость одной единицы*кол-во

$book = Book::model()->findByPk(1); //цена товара = 100
Yii::app()->shoppingCart->put($book,2); //положим 2 единицы товара
$positions = Yii::app()->shoppingCart->getPositions();
foreach($positions as $position) {
$price = $position->getSumPrice(); //200 (2*100)
}

IECartPosition::getQuantity()

Возвращает кол-во единиц в позиции

$book = Book::model()->findByPk(1); //цена товара = 100
Yii::app()->shoppingCart->put($book,2); //положим 2 единицы товара
$positions = Yii::app()->shoppingCart->getPositions();
foreach($positions as $position) {
$price = $position->getQuantity(); //2
}

Система скидок

Для компонента корзины, реализована простая система скидок.

Система скидок позволяет применять к корзине набор правил для изменения стоимости как корзины в целом так и отдельных позиций.

Скидка - класс наследуемый от IEDiscount и реализующий метод apply.

В методе apply должен быть описан механизм применения скидки.

Применяется она путем вызова метода Position::addDiscountPrice/Position::setDiscountPrice у позиции, либо EShoppingCart::addDiscountPrice/EShoppingCart::setDiscountPrice у корзины. В метод передается значение на которое будет уменьшена стоимость(всей корзины или отдельной позиции соответственно).

Пример класса скидки:

class TestDiscount extends IEDiscount {
    /**
     * Скидка в %
     */
    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);
            }
        }
    }
}

Данная скидка делает следующее: если в корзину был добавлен товар в количестве больше 1, то к одной единице применяется скидка в $rate % , и на эту стоимость уменьшается суммарная стоимость позиции.

К корзине может быть применен не ограниченный набор скидок, которые будут вызываться по цепочке.

Список скидок должен быть описан в конфиге:

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

События.

В ShoppingCart зарегистрированы 2 события. Механизм событий реализован согласно API Yii.

1) onUpdatePosition - срабатывает при добавлении или обновлении позиции в корзину.

2) onRemovePosition - срабатывает при удалении позиции из корзины.

Пример использования:

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

При срабатывание события onUpdatePosition, об этом будет оповещен call center.

CMap - работаем с корзиной, как с массивом.

Класс ShoppingCart наследует CMap, это позволяет работать с корзиной как с массивом.

$book = Book::model()->findByPk(1);
Yii::app()->shoppingCart[] = $book; //добавляем в корзину позицию.
 
//обходим все позиции в корзине циклом.
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