diff --git a/Cart.php b/Cart.php index 2585c52..43ecbd2 100755 --- a/Cart.php +++ b/Cart.php @@ -5,15 +5,14 @@ use Yii; use yii\base\Component; use yii\base\InvalidParamException; -use yii\web\Session; use yii2mod\cart\models\CartItemInterface; +use yii2mod\cart\storage\StorageInterface; /** - * Provides basic cart functionality (adding, removing, clearing, listing items). You can extend this class and + * Class Cart provides basic cart functionality (adding, removing, clearing, listing items). You can extend this class and * override it in the application configuration to extend/customize the functionality + * * @package yii2mod\cart - * @property int $count - * @property Session $session */ class Cart extends Component { @@ -23,20 +22,21 @@ class Cart extends Component const ITEM_PRODUCT = '\yii2mod\cart\models\CartItemInterface'; /** - * @var array cart items + * Override this to provide custom (e.g. database) storage for cart data + * + * @var string|\yii2mod\cart\storage\StorageInterface */ - protected $items; + public $storageClass = '\yii2mod\cart\storage\SessionStorage'; /** - * @var \yii2mod\cart\storage\DatabaseStorage + * @var array cart items */ - private $storage = null; + protected $items; /** - * Override this to provide custom (e.g. database) storage for cart data - * @var string|\yii2mod\cart\storage\StorageInterface + * @var StorageInterface */ - public $storageClass = '\yii2mod\cart\storage\SessionStorage'; + private $_storage; /** * @inheritdoc @@ -78,20 +78,24 @@ public function clear($save = true) { $this->items = []; $save && $this->storage->save($this); + return $this; } /** - * Setter for the storage component - * - * @param \yii2mod\cart\storage\StorageInterface|string $storage - * - * @return Cart + * @return mixed + */ + public function getStorage() + { + return $this->_storage; + } + + /** + * @param mixed $storage */ public function setStorage($storage) { - $this->storage = $storage; - return $this; + $this->_storage = $storage; } /** @@ -106,13 +110,14 @@ public function add(CartItemInterface $element, $save = true) { $this->addItem($element); $save && $this->storage->save($this); + return $this; } /** * @param \yii2mod\cart\models\CartItemInterface $item * - * @internal param $quantity + * @return void */ protected function addItem(CartItemInterface $item) { @@ -127,6 +132,7 @@ protected function addItem(CartItemInterface $item) * @param bool $save * * @throws \yii\base\InvalidParamException + * * @return $this */ public function remove($uniqueId, $save = true) @@ -134,9 +140,11 @@ public function remove($uniqueId, $save = true) if (!isset($this->items[$uniqueId])) { throw new InvalidParamException('Item not found'); } + unset($this->items[$uniqueId]); $save && $this->storage->save($this); + return $this; } @@ -160,6 +168,7 @@ public function getCount($itemType = null) public function getItems($itemType = null) { $items = $this->items; + if (!is_null($itemType)) { $items = array_filter($items, function ($item) use ($itemType) { @@ -167,6 +176,7 @@ function ($item) use ($itemType) { return is_subclass_of($item, $itemType); }); } + return $items; } @@ -185,15 +195,7 @@ public function getAttributeTotal($attribute, $itemType = null) foreach ($this->getItems($itemType) as $model) { $sum += $model->{$attribute}; } - return $sum; - } - - /** - * @return \yii2mod\cart\storage\StorageInterface|string - */ - protected function getStorage() - { - return $this->storage; + return $sum; } } \ No newline at end of file diff --git a/migrations/m160516_095943_init.php b/migrations/m160516_095943_init.php index ac67842..1c8771d 100644 --- a/migrations/m160516_095943_init.php +++ b/migrations/m160516_095943_init.php @@ -7,6 +7,7 @@ class m160516_095943_init extends Migration public function up() { $tableOptions = null; + if ($this->db->driverName === 'mysql') { $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; } diff --git a/migrations/m161109_124936_rename_cart_table.php b/migrations/m161109_124936_rename_cart_table.php new file mode 100644 index 0000000..e21e65d --- /dev/null +++ b/migrations/m161109_124936_rename_cart_table.php @@ -0,0 +1,27 @@ +renameTable('{{%Cart}}', '{{%cart}}'); + } + + public function down() + { + $this->renameTable('{{%cart}}', '{{%Cart}}'); + } + + /* + // Use safeUp/safeDown to run migration code within a transaction + public function safeUp() + { + } + + public function safeDown() + { + } + */ +} diff --git a/models/CartItemInterface.php b/models/CartItemInterface.php index 4ad08a3..47bb639 100755 --- a/models/CartItemInterface.php +++ b/models/CartItemInterface.php @@ -10,18 +10,21 @@ interface CartItemInterface { /** * Returns the price for the cart item + * * @return integer */ public function getPrice(); /** * Returns the label for the cart item (displayed in cart etc) + * * @return string */ public function getLabel(); /** * Returns unique id to associate cart item with product + * * @return string */ public function getUniqueId(); diff --git a/storage/DatabaseStorage.php b/storage/DatabaseStorage.php index e01345e..b7a32cb 100755 --- a/storage/DatabaseStorage.php +++ b/storage/DatabaseStorage.php @@ -11,14 +11,12 @@ use yii2mod\cart\Cart; /** - * Database-adapter for cart data storage. Assumes the existence of a table similar to: - * CREATE TABLE `Cart` ( - * `sessionId` varchar(255) NOT NULL, - * `cartData` blob NOT NULL, - * PRIMARY KEY (`sessionId`)) ENGINE=InnoDB; + * Class DatabaseStorage is a database adapter for cart data storage. + * * If userComponent is set, it tries to call getId() from the component and use the result as user identifier. If it * fails, or if $userComponent is not set, it will use sessionId as user identifier - * @package yii2mod\cart\cart\storage + * + * @package yii2mod\cart\storage */ class DatabaseStorage extends Object implements StorageInterface { @@ -35,7 +33,7 @@ class DatabaseStorage extends Object implements StorageInterface /** * @var string Name of the cart table */ - public $table = 'Cart'; + public $table = 'cart'; /** * @var string Name of the @@ -55,12 +53,12 @@ class DatabaseStorage extends Object implements StorageInterface /** * @var Connection */ - private $db; + private $_db; /** * @var User */ - private $user; + private $_user; /** * @inheritdoc @@ -68,13 +66,14 @@ class DatabaseStorage extends Object implements StorageInterface public function init() { parent::init(); - $this->db = Yii::$app->get($this->dbComponent); - if (isset($this->userComponent)) { - $this->user = Yii::$app->get($this->userComponent); + $this->_db = Yii::$app->get($this->dbComponent); + + if ($this->userComponent !== null) { + $this->_user = Yii::$app->get($this->userComponent); } - if (!isset($this->table)) { + if ($this->table === null) { throw new InvalidConfigException('Please specify "table" in cart configuration'); } } @@ -82,10 +81,11 @@ public function init() /** * @param Cart $cart * - * @return mixed + * @return array|mixed */ public function load(Cart $cart) { + $items = []; $identifier = $this->getIdentifier(Yii::$app->session->getId()); $query = new Query(); @@ -93,9 +93,7 @@ public function load(Cart $cart) ->from($this->table) ->where([$this->idField => $identifier]); - $items = []; - - if ($data = $query->createCommand($this->db)->queryScalar()) { + if ($data = $query->createCommand($this->_db)->queryScalar()) { $items = unserialize($data); } @@ -110,9 +108,11 @@ public function load(Cart $cart) protected function getIdentifier($default) { $id = $default; - if ($this->user instanceof User && !$this->user->getIsGuest()) { - $id = $this->user->getId(); + + if ($this->_user instanceof User && !$this->_user->getIsGuest()) { + $id = $this->_user->getId(); } + return $id; } @@ -128,7 +128,7 @@ public function save(Cart $cart) $items = $cart->getItems(); $sessionData = serialize($items); - $command = $this->db->createCommand(); + $command = $this->_db->createCommand(); if (empty($items) && true === $this->deleteIfEmpty) { $command->delete($this->table, [$this->idField => $identifier]); @@ -140,29 +140,27 @@ public function save(Cart $cart) {{{$this->idField}}} = :id ")->bindValues([ ':id' => $identifier, - ':val' => $sessionData, + ':val' => $sessionData ]); } + $command->execute(); } /** + * Assigns cart to logged in user + * * @param $sourceId * @param $destinationId + * + * @return void */ public function reassign($sourceId, $destinationId) { - $command = $this->db->createCommand(); + $command = $this->_db->createCommand(); + $command->delete($this->table, [$this->idField => $destinationId])->execute(); - $command->setSql(" - UPDATE {{{$this->table}}} - SET - {{{$this->idField}}} = :userId - WHERE - {{{$this->idField}}} = :sessionId - ")->bindValues([ - ':userId' => $destinationId, - ':sessionId' => $sourceId - ])->execute(); + + $command->update($this->table, [$this->idField => $destinationId], [$this->idField => $sourceId])->execute(); } } \ No newline at end of file diff --git a/storage/SessionStorage.php b/storage/SessionStorage.php index 585d701..65718be 100644 --- a/storage/SessionStorage.php +++ b/storage/SessionStorage.php @@ -7,9 +7,9 @@ use yii2mod\cart\Cart; /** - * Class SessionStorage + * Class SessionStorage is a session adapter for cart data storage. + * * @property \yii\web\Session session - * @package yii2mod\cart\cart */ class SessionStorage extends Object implements StorageInterface { @@ -24,9 +24,11 @@ class SessionStorage extends Object implements StorageInterface public function load(Cart $cart) { $cartData = []; + if (false !== ($session = ($this->session->get($this->key, false)))) { $cartData = unserialize($session); } + return $cartData; } @@ -36,6 +38,7 @@ public function load(Cart $cart) public function save(Cart $cart) { $sessionData = serialize($cart->getItems()); + $this->session->set($this->key, $sessionData); } diff --git a/storage/StorageInterface.php b/storage/StorageInterface.php index adc0f0e..7fc4c58 100644 --- a/storage/StorageInterface.php +++ b/storage/StorageInterface.php @@ -6,20 +6,19 @@ /** * Interface StorageInterface - * @package yii2mod\cart\cart + * @package yii2mod\cart\storage */ interface StorageInterface { - /** - * @param \yii2mod\cart\Cart $cart + * @param Cart $cart * - * @return void + * @return array|mixed */ public function load(Cart $cart); /** - * @param \yii2mod\cart\Cart $cart + * @param Cart $cart * * @return void */ diff --git a/tests/CartTest.php b/tests/CartTest.php index 99a9c1e..22e6fde 100644 --- a/tests/CartTest.php +++ b/tests/CartTest.php @@ -3,7 +3,7 @@ namespace yii2mod\cart\tests; use Yii; -use yii2mod\cart\tests\data\ProductModel; +use yii2mod\cart\tests\data\Product; /** * Class CartTest @@ -19,7 +19,7 @@ public function testEmptyCart() public function testAddItem() { $cart = Yii::$app->cart; - $product = ProductModel::findOne(1); + $product = Product::findOne(1); $cart->add($product); $this->assertContains($product, $cart->getItems()); @@ -28,7 +28,7 @@ public function testAddItem() public function testRemoveItem() { $cart = Yii::$app->cart; - $product = ProductModel::findOne(1); + $product = Product::findOne(1); $cart->add($product); $this->assertContains($product, $cart->getItems()); @@ -40,7 +40,7 @@ public function testRemoveItem() public function testClearCart() { $cart = Yii::$app->cart; - $product = ProductModel::findOne(1); + $product = Product::findOne(1); $cart->add($product); $this->assertEquals(1, $cart->getCount()); diff --git a/tests/TestCase.php b/tests/TestCase.php index 9df17cb..1eb718e 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -4,7 +4,6 @@ use Yii; use yii\helpers\ArrayHelper; -use yii\web\DbSession; /** * This is the base class for all yii framework unit tests. @@ -76,27 +75,28 @@ protected function setupTestDbData() // Structure : - $db->createCommand()->createTable('Cart', [ - 'sessionId' => 'string PRIMARY KEY', - 'cartData' => 'text', + $db->createCommand()->createTable('cart', [ + 'sessionId' => 'string primary key', + 'cartData' => 'text' ])->execute(); - $db->createCommand()->createTable('Product', [ + $db->createCommand()->createTable('product', [ 'id' => 'pk', 'name' => 'string', 'price' => 'decimal' ])->execute(); - $db->createCommand()->createTable('Session', [ - 'id' => 'CHAR(40) NOT NULL PRIMARY KEY', + $db->createCommand()->createTable('session', [ + 'id' => 'char(40) not null primary key', 'expire' => 'integer', - 'data' => 'LONGBLOB' + 'data' => 'longblob' ])->execute(); // Data : - - $db->createCommand()->batchInsert('Product', ['name', 'price'], [ - ['Product', 10], + + $db->createCommand()->insert('product', [ + 'name' => 'Amazon Kindle', + 'price' => 100 ])->execute(); } } \ No newline at end of file diff --git a/tests/data/ProductModel.php b/tests/data/Product.php similarity index 83% rename from tests/data/ProductModel.php rename to tests/data/Product.php index ca4f6c8..4e33bb2 100644 --- a/tests/data/ProductModel.php +++ b/tests/data/Product.php @@ -6,24 +6,22 @@ use yii2mod\cart\models\CartItemInterface; /** - * Class ProductModel + * Class Product * * @property integer $id * @property string $name * @property string $price */ -class ProductModel extends ActiveRecord implements CartItemInterface +class Product extends ActiveRecord implements CartItemInterface { - /** * @return string */ public static function tableName() { - return 'Product'; + return 'product'; } - /** * @return string */ diff --git a/widgets/CartGrid.php b/widgets/CartGrid.php index 6081fc7..e887d4c 100644 --- a/widgets/CartGrid.php +++ b/widgets/CartGrid.php @@ -14,24 +14,18 @@ */ class CartGrid extends Widget { - /** - * @var + * @var \yii\data\BaseDataProvider */ public $cartDataProvider; /** - * Grid view columns - * @var + * @var array GridView columns */ - public $cartColumns = [ - 'id', - 'label', - ]; + public $cartColumns = ['id', 'label']; /** - * GridView options - * @var array + * @var array GridView options */ public $gridOptions = []; @@ -41,7 +35,7 @@ class CartGrid extends Widget public $itemType = Cart::ITEM_PRODUCT; /** - * Setting defaults + * @inheritdoc */ public function init() { @@ -56,7 +50,7 @@ public function init() } /** - * @return string + * @inheritdoc */ public function run() { @@ -66,7 +60,9 @@ public function run() } /** - * Get grid options + * Return grid options + * + * @return array */ public function getGridOptions() { @@ -75,4 +71,4 @@ public function getGridOptions() 'columns' => $this->cartColumns ]); } -} +} \ No newline at end of file