├── LICENSE ├── README.md ├── composer.json ├── config └── shopping-cart.php ├── migrations └── 2017_06_26_000000_create_shopping_cart_table.php └── src ├── CartItem.php ├── Coupons ├── Coupon.php ├── FixedDiscountCoupon.php └── PercentDiscountCoupon.php ├── Facades └── ShoppingCart.php ├── Repositories ├── ShoppingCartDatabaseRepository.php ├── ShoppingCartRedisRepository.php └── ShoppingCartRepositoryInterface.php ├── ServiceProvider.php └── ShoppingCart.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Alexander Melihov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Laravel Shopping Cart 2 | ===================== 3 | 4 | [![GitHub Workflow Status](https://github.com/melihovv/laravel-shopping-cart/workflows/Run%20tests/badge.svg)](https://github.com/melihovv/laravel-shopping-cart/actions) 5 | [![styleci](https://styleci.io/repos/95455977/shield)](https://styleci.io/repos/95455977) 6 | 7 | [![Packagist](https://img.shields.io/packagist/v/melihovv/laravel-shopping-cart.svg)](https://packagist.org/packages/melihovv/laravel-shopping-cart) 8 | [![Packagist](https://poser.pugx.org/melihovv/laravel-shopping-cart/d/total.svg)](https://packagist.org/packages/melihovv/laravel-shopping-cart) 9 | [![Packagist](https://img.shields.io/packagist/l/melihovv/laravel-shopping-cart.svg)](https://packagist.org/packages/melihovv/laravel-shopping-cart) 10 | 11 | ## Install 12 | 13 | Install via composer 14 | ``` 15 | composer require melihovv/laravel-shopping-cart 16 | ``` 17 | 18 | ### Publish configuration file and migrations 19 | 20 | ``` 21 | php artisan vendor:publish --provider="Melihovv\ShoppingCart\ServiceProvider" 22 | ``` 23 | 24 | ### Run migrations 25 | 26 | ``` 27 | php artisan migrate 28 | ``` 29 | 30 | ## Overview 31 | 32 | * [Usage](#usage) 33 | * [Instances](#instances) 34 | * [Storage](#storage) 35 | * [Coupons](#coupons) 36 | 37 | ## Usage 38 | 39 | Regiser facade in config/app.php 40 | ``` 41 | 'Cart' => 'Melihovv\ShoppingCart\Facades\ShoppingCart', 42 | ``` 43 | or 44 | ``` 45 | use Melihovv\ShoppingCart\Facades\ShoppingCart as Cart; 46 | ``` 47 | in the below examples. 48 | 49 | The shopping cart gives you the following methods to use: 50 | 51 | ### Cart::add() 52 | 53 | Add an item to the shopping cart. 54 | 55 | ```php 56 | $cartItem = Cart::add($id, $name, $price, $quantity); 57 | $cartItem = Cart::add($id, $name, $price, $quantity, [ 58 | 'color' => 'white', 59 | ]); 60 | ``` 61 | 62 | ### Cart::remove() 63 | 64 | Remove the item with the specified unique id from the shopping cart. Unique id 65 | is used to store items with the same `$id`, but different `$options`. 66 | 67 | ```php 68 | $cartItem = Cart::add($id, $name, $price, $quantity); 69 | 70 | // ... 71 | 72 | Cart::remove($cartItem->getUniqueId()) 73 | ``` 74 | 75 | ### Cart::has() 76 | 77 | Check if the shopping cart contains the item with the specified unique id. 78 | 79 | ```php 80 | $cartItem = Cart::add($id, $name, $price, $quantity); 81 | 82 | // ... 83 | 84 | if (Cart::has($cartItem->getUniqueId())) { 85 | // Do smth. 86 | } 87 | ``` 88 | 89 | ### Cart::get() 90 | 91 | Get an item in the shopping cart by its unique id. 92 | 93 | ```php 94 | $cartItem = Cart::add($id, $name, $price, $quantity); 95 | 96 | // ... 97 | 98 | $cartItem = Cart::get($cartItem->getUniqueId()); 99 | ``` 100 | 101 | ### Cart::content() 102 | 103 | Get all items in the shopping cart. 104 | 105 | ### Cart::clear() 106 | 107 | Clear the shopping cart. 108 | 109 | ### Cart::count() 110 | 111 | Return number of items in the shopping cart. This method does not summarize 112 | quantities of item. For example, there are 3 books and 1 iPhone in the 113 | shopping cart, so this method returns 2. 114 | 115 | ### Cart::getTotal() 116 | 117 | Return total price of all items in the shopping cart. 118 | 119 | ```php 120 | Cart::add(1, 'iPhone 7', 500, 1); 121 | Cart::add(1, 'iPad Pro', 700, 2); 122 | Cart::getTotal(); // return 1900 123 | ``` 124 | 125 | ## Instances 126 | 127 | The package supports multiple instances of the cart. Some examples: 128 | 129 | ```php 130 | Cart::instance('shopping')->add('192ao12', 'Product 1', 100, 10); 131 | 132 | // Store and get the content of the 'shopping' cart 133 | Cart::store->content(); 134 | 135 | Cart::instance('wishlist')->add('sdjk922', 'Product 2', 50, 1, ['size' => 'medium']); 136 | 137 | // Store and get the content of the 'wishlist' cart 138 | Cart::store()->content(); 139 | 140 | // If you want to get the content of the 'shopping' cart again 141 | Cart::instance('shopping')->restore()->content(); 142 | ``` 143 | 144 | **The default cart instance is called `default`, so when you're not using 145 | instances,`Cart::content();` is the same as `Cart::instance('default')->content()`.** 146 | 147 | ### Cart::instance() 148 | 149 | Set current instance name. 150 | 151 | ### Cart::currentInstance() 152 | 153 | Get current instance name. 154 | 155 | ## Storage 156 | 157 | Currently there are two possible storage to persist shopping cart: 158 | * Database 159 | * Redis 160 | 161 | You can choose one by specifying repository class name in config 162 | 163 | ```php 164 | // config/shopping-cart.php 165 | 166 | 'repository' => \Melihovv\ShoppingCart\Repositories\ShoppingCartDatabaseRepository::class, 167 | // or 168 | 'repository' => \Melihovv\ShoppingCart\Repositories\ShoppingCartRedisRepository::class, 169 | ``` 170 | 171 | In order to use redis storage you also need to install `predis/predis` package. 172 | 173 | ### Cart::store() 174 | 175 | Persist current shopping cart instance to storage. 176 | 177 | ```php 178 | Cart::store($user->id); 179 | Cart::instance('cart')->store($user->id); 180 | Cart::instance('wishlist')->store($user->id); 181 | ``` 182 | 183 | ### Cart::restore() 184 | 185 | Restore shopping cart instance to storage. 186 | 187 | ```php 188 | Cart::restore($user->id); 189 | Cart::instance('cart')->restore($user->id); 190 | Cart::instance('wishlist')->restore($user->id); 191 | ``` 192 | 193 | ### Cart::destroy() 194 | 195 | Remove shopping cart instance from storage. 196 | 197 | ```php 198 | Cart::destroy($user->id); 199 | Cart::instance('cart')->destroy($user->id); 200 | Cart::instance('wishlist')->destroy($user->id); 201 | ``` 202 | 203 | ## Coupons 204 | 205 | You can easily add discount coupons to shopping cart. Currently there are two 206 | types of coupons: 207 | 208 | * FixedDiscountCoupon 209 | * PercentDiscountCoupon 210 | 211 | Related methods: 212 | 213 | ### Cart::addCoupon() 214 | 215 | Add coupon to cart. 216 | 217 | ```php 218 | Cart::addCoupon(new FixedDiscountCoupon($name, $discount)); 219 | Cart::addCoupon(new PercentDiscountCoupon($name, 0.1)); // 10% discount 220 | ``` 221 | 222 | ### Cart::coupons() 223 | 224 | Returns all coupons. 225 | 226 | ### Cart::getTotalWithCoupons() 227 | 228 | Returns total price with applied coupons. 229 | 230 | ```php 231 | Cart::add(1, 'iPhone 7', 500, 1); 232 | Cart::add(1, 'iPad Pro', 700, 2); 233 | Cart::addCoupon(new FixedDiscountCoupon($name, 300)); 234 | Cart::getTotal(); // return 1900 - 300 = 1600 235 | ``` 236 | 237 | ## Security 238 | 239 | If you discover any security related issues, please email amelihovv@ya.ru instead of using the issue tracker. 240 | 241 | ## Credits 242 | 243 | - [Alexander Melihov](https://github.com/melihovv) 244 | - [All contributors](https://github.com/melihovv/laravel-shopping-cart/graphs/contributors) 245 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "melihovv/laravel-shopping-cart", 3 | "description": "Shopping cart package for laravel", 4 | "license": "MIT", 5 | "keywords": [ 6 | "cart", 7 | "shopping cart", 8 | "laravel" 9 | ], 10 | "type": "library", 11 | "authors": [ 12 | { 13 | "name": "Alexander Melihov", 14 | "email": "amelihovv@ya.ru" 15 | } 16 | ], 17 | "autoload": { 18 | "psr-4": { 19 | "Melihovv\\ShoppingCart\\": "src" 20 | } 21 | }, 22 | "autoload-dev": { 23 | "psr-4": { 24 | "Melihovv\\ShoppingCart\\Tests\\": "tests" 25 | } 26 | }, 27 | "require": { 28 | "php": ">=7.2", 29 | "ext-json": "*", 30 | "illuminate/container": "^6.0|^7.0|^8.0", 31 | "illuminate/database": "^6.0|^7.0|^8.0", 32 | "illuminate/redis": "^6.0|^7.0|^8.0", 33 | "illuminate/support": "^6.0|^7.0|^8.0" 34 | }, 35 | "require-dev": { 36 | "orchestra/testbench": "^4.0|^5.0|^6.0", 37 | "phpunit/phpunit": "^8.4|^9.0", 38 | "predis/predis": "^1.1" 39 | }, 40 | "scripts": { 41 | "phpunit": "phpunit" 42 | }, 43 | "extra": { 44 | "laravel": { 45 | "providers": [ 46 | "Melihovv\\ShoppingCart\\ServiceProvider" 47 | ] 48 | } 49 | }, 50 | "config": { 51 | "preferred-install": "dist", 52 | "sort-packages": true, 53 | "optimize-autoloader": true 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /config/shopping-cart.php: -------------------------------------------------------------------------------- 1 | \Melihovv\ShoppingCart\Repositories\ShoppingCartDatabaseRepository::class, 16 | 17 | // 'repository' => \Melihovv\ShoppingCart\Repositories\ShoppingCartRedisRepository::class, 18 | 19 | /* 20 | |-------------------------------------------------------------------------- 21 | | Shopping cart database settings 22 | |-------------------------------------------------------------------------- 23 | | 24 | | Here you can set the connection that the package should use when 25 | | storing and restoring a cart. Only if database repository is used. 26 | | 27 | */ 28 | 29 | 'database' => [ 30 | 31 | 'connection' => null, 32 | 33 | 'table' => 'shopping_cart', 34 | 35 | ], 36 | ]; 37 | -------------------------------------------------------------------------------- /migrations/2017_06_26_000000_create_shopping_cart_table.php: -------------------------------------------------------------------------------- 1 | string('id'); 16 | $table->string('instance'); 17 | $table->longText('content'); 18 | $table->nullableTimestamps(); 19 | 20 | $table->primary(['id', 'instance']); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | */ 27 | public function down() 28 | { 29 | Schema::drop('shopping_cart'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/CartItem.php: -------------------------------------------------------------------------------- 1 | id = $id; 86 | $this->name = $name; 87 | $this->price = (float) $price; 88 | $this->quantity = (int) $quantity; 89 | $this->options = $options; 90 | $this->uniqueId = $this->generateUniqueId(); 91 | } 92 | 93 | /** 94 | * Create a new instance from the given array. 95 | * 96 | * @param array $attributes 97 | * 98 | * @throws InvalidArgumentException 99 | * 100 | * @return $this 101 | */ 102 | public static function fromArray(array $attributes) 103 | { 104 | return new self( 105 | $attributes['id'], 106 | $attributes['name'], 107 | $attributes['price'], 108 | $attributes['quantity'], 109 | Arr::get($attributes, 'options', []) 110 | ); 111 | } 112 | 113 | /** 114 | * Generate a unique id for the cart item. 115 | * 116 | * @return string 117 | */ 118 | protected function generateUniqueId() 119 | { 120 | ksort($this->options); 121 | 122 | return md5($this->id.serialize($this->options)); 123 | } 124 | 125 | /** 126 | * Get cart item unique identifier. 127 | * 128 | * @return string 129 | */ 130 | public function getUniqueId() 131 | { 132 | return $this->uniqueId; 133 | } 134 | 135 | /** 136 | * Get total price. 137 | * 138 | * Total price = price * quantity. 139 | * 140 | * @return float 141 | */ 142 | public function getTotal() 143 | { 144 | return $this->price * $this->quantity; 145 | } 146 | 147 | /** 148 | * Get the instance as an array. 149 | * 150 | * @return array 151 | */ 152 | public function toArray() 153 | { 154 | return [ 155 | 'unique_id' => $this->uniqueId, 156 | 'id' => $this->id, 157 | 'name' => $this->name, 158 | 'price' => $this->price, 159 | 'quantity' => $this->quantity, 160 | 'options' => $this->options, 161 | ]; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/Coupons/Coupon.php: -------------------------------------------------------------------------------- 1 | name = $name; 17 | } 18 | 19 | /** 20 | * Apply coupon to total price. 21 | * 22 | * @param $total 23 | * 24 | * @return float Discount. 25 | */ 26 | abstract public function apply($total); 27 | } 28 | -------------------------------------------------------------------------------- /src/Coupons/FixedDiscountCoupon.php: -------------------------------------------------------------------------------- 1 | discount = $discount; 23 | } 24 | 25 | /** 26 | * Apply coupon to total price. 27 | * 28 | * @param $total 29 | * 30 | * @return float Discount. 31 | */ 32 | public function apply($total) 33 | { 34 | return $this->discount; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Coupons/PercentDiscountCoupon.php: -------------------------------------------------------------------------------- 1 | percent = $discount; 23 | } 24 | 25 | /** 26 | * Apply coupon to total price. 27 | * 28 | * @param $total 29 | * 30 | * @return float Discount. 31 | */ 32 | public function apply($total) 33 | { 34 | return $total * $this->percent; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Facades/ShoppingCart.php: -------------------------------------------------------------------------------- 1 | exists($id, $instanceName)) { 20 | $this->update($id, $instanceName, $content); 21 | } else { 22 | $this->create($id, $instanceName, $content); 23 | } 24 | } 25 | 26 | /** 27 | * Find shopping cart by its identifier and instance name. 28 | * 29 | * @param string $id 30 | * @param string $instanceName 31 | * 32 | * @return stdClass|null 33 | */ 34 | public function findByIdAndInstanceName($id, $instanceName) 35 | { 36 | return $this->getConnection()->table($this->getTableName()) 37 | ->where('id', $id) 38 | ->where('instance', $instanceName) 39 | ->first(['id', 'instance', 'content']); 40 | } 41 | 42 | /** 43 | * Remove shopping cart by its identifier and instance name. 44 | * 45 | * @param string $id 46 | * @param string $instanceName 47 | */ 48 | public function remove($id, $instanceName) 49 | { 50 | $this->getConnection()->table($this->getTableName()) 51 | ->where('id', $id) 52 | ->where('instance', $instanceName) 53 | ->delete(); 54 | } 55 | 56 | /** 57 | * Create shopping cart instance. 58 | * 59 | * @param $id 60 | * @param $instanceName 61 | * @param $content 62 | */ 63 | protected function create($id, $instanceName, $content) 64 | { 65 | $this->getConnection()->table($this->getTableName()) 66 | ->insert([ 67 | 'id' => $id, 68 | 'instance' => $instanceName, 69 | 'content' => $content, 70 | ]); 71 | } 72 | 73 | /** 74 | * Update shopping cart instance. 75 | * 76 | * @param $id 77 | * @param $instanceName 78 | * @param $content 79 | */ 80 | protected function update($id, $instanceName, $content) 81 | { 82 | $this->getConnection()->table($this->getTableName()) 83 | ->where('id', $id) 84 | ->where('instance', $instanceName) 85 | ->update(['content' => $content]); 86 | } 87 | 88 | /** 89 | * Check if shopping cart instance exitsts. 90 | * 91 | * @param $id 92 | * @param $instanceName 93 | * 94 | * @return bool 95 | */ 96 | protected function exists($id, $instanceName) 97 | { 98 | return $this->getConnection()->table($this->getTableName()) 99 | ->where('id', $id) 100 | ->where('instance', $instanceName) 101 | ->exists(); 102 | } 103 | 104 | /** 105 | * Get the database connection. 106 | * 107 | * @return \Illuminate\Database\Connection 108 | */ 109 | private function getConnection() 110 | { 111 | $connectionName = $this->getConnectionName(); 112 | 113 | return app(DatabaseManager::class)->connection($connectionName); 114 | } 115 | 116 | /** 117 | * Get the database table name. 118 | * 119 | * @return string 120 | */ 121 | private function getTableName() 122 | { 123 | return config('shopping-cart.database.table', 'shopping_cart'); 124 | } 125 | 126 | /** 127 | * Get the database connection name. 128 | * 129 | * @return string 130 | */ 131 | private function getConnectionName() 132 | { 133 | $connection = config('shopping-cart.database.connection'); 134 | 135 | return is_null($connection) ? config('database.default') : $connection; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/Repositories/ShoppingCartRedisRepository.php: -------------------------------------------------------------------------------- 1 | getKey($id, $instanceName), $content); 20 | } 21 | 22 | /** 23 | * Find shopping cart by its identifier and instance name. 24 | * 25 | * @param string $id 26 | * @param string $instanceName 27 | * 28 | * @return stdClass|null 29 | */ 30 | public function findByIdAndInstanceName($id, $instanceName) 31 | { 32 | $content = Redis::get($this->getKey($id, $instanceName)); 33 | 34 | if ($content === null) { 35 | return; 36 | } 37 | 38 | return (object) [ 39 | 'id' => $id, 40 | 'instance' => $instanceName, 41 | 'content' => $content, 42 | ]; 43 | } 44 | 45 | /** 46 | * Remove shopping cart by its identifier and instance name. 47 | * 48 | * @param string $id 49 | * @param string $instanceName 50 | */ 51 | public function remove($id, $instanceName) 52 | { 53 | Redis::del($this->getKey($id, $instanceName)); 54 | } 55 | 56 | /** 57 | * Get the key to store shopping cart. 58 | * 59 | * @param $id 60 | * @param $instanceName 61 | * 62 | * @return string 63 | */ 64 | protected function getKey($id, $instanceName) 65 | { 66 | return sprintf('%s.%s', $id, $instanceName); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Repositories/ShoppingCartRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | publishes([ 14 | self::CONFIG_PATH => config_path('shopping-cart.php'), 15 | ], 'config'); 16 | 17 | $this->publishes([ 18 | self::MIGRATIONS_PATH => database_path('migrations'), 19 | ], 'migrations'); 20 | 21 | $this->loadMigrationsFrom(self::MIGRATIONS_PATH); 22 | } 23 | 24 | public function register() 25 | { 26 | $this->mergeConfigFrom(self::CONFIG_PATH, 'shopping-cart'); 27 | 28 | $this->app->bind('shopping-cart', function () { 29 | return new ShoppingCart( 30 | $this->app->make( 31 | $this->app['config']->get('shopping-cart.repository') 32 | ) 33 | ); 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/ShoppingCart.php: -------------------------------------------------------------------------------- 1 | repo = $repo; 55 | $this->instance(self::DEFAULT_INSTANCE_NAME); 56 | $this->content = new Collection(); 57 | $this->coupons = new Collection(); 58 | } 59 | 60 | /** 61 | * Add an item to the shopping cart. 62 | * 63 | * If an item is already in the shopping cart then we simply update its 64 | * quantity. 65 | * 66 | * @param string|int $id 67 | * @param string $name 68 | * @param int|float $price 69 | * @param int $quantity 70 | * @param array $options 71 | * 72 | * @return CartItem 73 | */ 74 | public function add($id, $name, $price, $quantity, $options = []) 75 | { 76 | $cartItem = new CartItem($id, $name, $price, $quantity, $options); 77 | $uniqueId = $cartItem->getUniqueId(); 78 | 79 | if ($this->content->has($uniqueId)) { 80 | $cartItem->quantity += $this->content->get($uniqueId)->quantity; 81 | } 82 | 83 | $this->content->put($uniqueId, $cartItem); 84 | 85 | return $cartItem; 86 | } 87 | 88 | /** 89 | * Remove the item with the specified unique id from shopping cart. 90 | * 91 | * @param string|int $uniqueId 92 | * 93 | * @return bool 94 | */ 95 | public function remove($uniqueId) 96 | { 97 | if ($cartItem = $this->get($uniqueId)) { 98 | $this->content->pull($cartItem->getUniqueId()); 99 | 100 | return true; 101 | } 102 | 103 | return false; 104 | } 105 | 106 | /** 107 | * Check if an item with specified unique id is in shopping cart. 108 | * 109 | * @param string|int $uniqueId 110 | * 111 | * @return bool 112 | */ 113 | public function has($uniqueId) 114 | { 115 | return $this->content->has($uniqueId); 116 | } 117 | 118 | /** 119 | * Get the item with the specified unique id from shopping cart. 120 | * 121 | * @param string|int $uniqueId 122 | * 123 | * @return CartItem|null 124 | */ 125 | public function get($uniqueId) 126 | { 127 | return $this->content->get($uniqueId); 128 | } 129 | 130 | /** 131 | * Get shopping cart content. 132 | * 133 | * @return Collection 134 | */ 135 | public function content() 136 | { 137 | return $this->content; 138 | } 139 | 140 | /** 141 | * Get the quantity of the cart item with specified unique id. 142 | * 143 | * @param $uniqueId 144 | * @param $quantity 145 | * 146 | * @return bool 147 | */ 148 | public function setQuantity($uniqueId, $quantity) 149 | { 150 | if ($cartItem = $this->get($uniqueId)) { 151 | $cartItem->quantity = $quantity; 152 | 153 | $this->content->put($cartItem->getUniqueId(), $cartItem); 154 | 155 | return true; 156 | } 157 | 158 | return false; 159 | } 160 | 161 | /** 162 | * Clear shopping cart. 163 | */ 164 | public function clear() 165 | { 166 | $this->content = new Collection(); 167 | } 168 | 169 | /** 170 | * Get the number of item in the shopping cart. 171 | * 172 | * @return int 173 | */ 174 | public function count() 175 | { 176 | return $this->content->count(); 177 | } 178 | 179 | /** 180 | * Get total price without coupons. 181 | * 182 | * @return float 183 | */ 184 | public function getTotal() 185 | { 186 | return $this->content->sum(function (CartItem $cartItem) { 187 | return $cartItem->getTotal(); 188 | }); 189 | } 190 | 191 | /** 192 | * Get total price with coupons. 193 | * 194 | * @return float 195 | */ 196 | public function getTotalWithCoupons() 197 | { 198 | $total = $this->getTotal(); 199 | $totalWithCoupons = $total; 200 | 201 | $this->coupons->each(function (Coupon $coupon) use ($total, &$totalWithCoupons) { 202 | /** 203 | * @var Coupon $coupon 204 | */ 205 | $totalWithCoupons -= $coupon->apply($total); 206 | }); 207 | 208 | return $totalWithCoupons; 209 | } 210 | 211 | /** 212 | * Add coupon. 213 | * 214 | * @param Coupon $coupon 215 | */ 216 | public function addCoupon(Coupon $coupon) 217 | { 218 | $this->coupons->push($coupon); 219 | } 220 | 221 | /** 222 | * Get coupons. 223 | * 224 | * @return Collection 225 | */ 226 | public function coupons() 227 | { 228 | return $this->coupons; 229 | } 230 | 231 | /** 232 | * Set shopping cart instance name. 233 | * 234 | * @param string $name 235 | * 236 | * @return $this 237 | */ 238 | public function instance($name) 239 | { 240 | $name = $name ?: self::DEFAULT_INSTANCE_NAME; 241 | $name = str_replace('shopping-cart.', '', $name); 242 | 243 | $this->instanceName = sprintf('%s.%s', 'shopping-cart', $name); 244 | 245 | return $this; 246 | } 247 | 248 | /** 249 | * Get current shopping cart instance name. 250 | * 251 | * @return string 252 | */ 253 | public function currentInstance() 254 | { 255 | return $this->instanceName; 256 | } 257 | 258 | /** 259 | * Store the current instance of the cart. 260 | * 261 | * @param $id 262 | * 263 | * @return $this 264 | */ 265 | public function store($id) 266 | { 267 | $this->repo->createOrUpdate( 268 | $id, 269 | $this->instanceName, 270 | json_encode(serialize([ 271 | 'content' => $this->content, 272 | 'coupons' => $this->coupons, 273 | ])) 274 | ); 275 | 276 | return $this; 277 | } 278 | 279 | /** 280 | * Store the specified instance of the cart. 281 | * 282 | * @param $id 283 | * 284 | * @return $this 285 | */ 286 | public function restore($id) 287 | { 288 | $cart = $this->repo->findByIdAndInstanceName($id, $this->instanceName); 289 | 290 | if ($cart === null) { 291 | return; 292 | } 293 | 294 | $unserialized = unserialize(json_decode($cart->content)); 295 | $this->content = $unserialized['content']; 296 | $this->coupons = $unserialized['coupons']; 297 | 298 | $this->instance($cart->instance); 299 | 300 | return $this; 301 | } 302 | 303 | /** 304 | * Delete current shopping cart instance from storage. 305 | * 306 | * @param $id 307 | */ 308 | public function destroy($id) 309 | { 310 | $this->repo->remove($id, $this->instanceName); 311 | } 312 | } 313 | --------------------------------------------------------------------------------