├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── composer.json ├── config └── cart.php ├── src ├── Cart.php ├── CartItem.php ├── CartServiceProvider.php ├── Commands │ └── InstallCommand.php ├── Coupon │ └── Coupon.php ├── Facades │ └── Cart.php └── functions.php └── stub └── CartServiceProvider.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `Cart` will be documented in this file. 4 | 5 | ## v1.1.0 - 2024-08-11 6 | 7 | ### v1.1.0 - 2024-08-11 8 | 9 | #### Added 10 | 11 | - **Coupons Feature**: Introduced a powerful new Coupons feature to enhance discount and promotion management. 12 | 13 | - **Apply Discounts**: Easily apply both percentage-based and fixed amount coupons to your cart with straightforward method calls. 14 | 15 | ```php 16 | use RealRashid\Cart\Facades\Cart; 17 | use App\Coupons\PercentageCoupon; 18 | 19 | // Create and apply a percentage-based coupon 20 | $percentageCoupon = new PercentageCoupon('PERCENT20', 20, '2024-12-31'); 21 | Cart::instance('cart')->applyCoupon($percentageCoupon); 22 | 23 | ``` 24 | - **Custom Coupons**: Develop custom coupon classes to meet your specific business requirements by implementing the `Coupon` interface. For example, here’s how you can create a fixed amount coupon: 25 | 26 | ```php 27 | coupon = $coupon; 41 | } 42 | 43 | public function getCode(): string 44 | { 45 | return $this->coupon->code; 46 | } 47 | 48 | public function isValid(): bool 49 | { 50 | return $this->coupon->isValid(); 51 | } 52 | 53 | public function getDiscountType(): string 54 | { 55 | return 'fixed_amount'; 56 | } 57 | 58 | public function getExpiryDate(): string 59 | { 60 | return $this->coupon->expiry_date; 61 | } 62 | 63 | public function getDiscountAmount(): float 64 | { 65 | return $this->coupon->amount; 66 | } 67 | } 68 | 69 | ``` 70 | - **Manage Coupons**: New methods to efficiently manage applied coupons. 71 | 72 | - **Apply Coupon**: `Cart::applyCoupon($coupon);` 73 | - **Remove Coupon**: `Cart::removeCoupon();` 74 | - **Get Coupon Details**: `Cart::getAppliedCouponDetails();` 75 | 76 | 77 | 78 | #### Updated 79 | 80 | - **Documentation**: Updated to include comprehensive instructions on the new Coupons feature, including examples and best practices. 81 | 82 | ## v1.0.0 - 2024-06-16 83 | 84 | ### [Initial Release] - 2024-06-16 85 | 86 | #### Added 87 | 88 | - Core functionality for managing shopping carts within Laravel applications. 89 | - Flexible configuration options to customize cart instances with specific tax rates and other settings. 90 | - Support for managing multiple cart instances, each with its own configurations. 91 | - Intuitive API for seamless integration and interaction with the cart. 92 | - Tax calculation feature, allowing enabling or disabling tax calculations per cart instance. 93 | - Initial set of facade and service provider to integrate Cart into Laravel projects. 94 | - Unit tests and test cases to ensure reliability and functionality. 95 | - Documentation outlining installation, configuration, and usage of the Cart package. 96 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | Please read and understand the contribution guide before creating an issue or pull request. 6 | 7 | ## Etiquette 8 | 9 | This project is open source, and as such, I dedicate my free time to build and maintain the source code. It is made available in the hope that it will be useful to other developers. It would be unfair to suffer abuse or anger for my hard work. 10 | 11 | Please be considerate when raising issues or presenting pull requests. Let's show that developers are respectful and collaborative. 12 | 13 | It is my duty to ensure that all submissions are of sufficient quality to benefit the project. Respect my decisions, and please do not be upset if your submission is not used. 14 | 15 | ## Viability 16 | 17 | Before requesting or submitting new features, consider whether it will be useful to others. Open source projects are used by many developers with different needs. Think about whether your feature might be beneficial to other users of the project. 18 | 19 | ## Procedure 20 | 21 | Before filing an issue: 22 | 23 | - Attempt to replicate the problem to ensure it wasn't a coincidental incident. 24 | - Check if your feature suggestion is already present in the project. 25 | - Look through the pull requests tab to ensure the bug doesn’t already have a fix in progress. 26 | - Check the pull requests tab to see if the feature is already being worked on. 27 | 28 | Before submitting a pull request: 29 | 30 | - Verify that your feature doesn’t already exist in the codebase. 31 | - Check the pull requests to ensure that someone else hasn’t already submitted the feature or fix. 32 | 33 | ## Requirements 34 | 35 | If there are additional requirements for the project, you will find them listed here: 36 | 37 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)**: Install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer) to apply the conventions easily. 38 | 39 | - **Add tests**: Your patch won’t be accepted if it doesn’t include tests. 40 | 41 | - **Document changes**: Update the `README.md` and any other relevant documentation to reflect changes in behavior. 42 | 43 | - **Respect our release cycle**: Follow [SemVer v2.0.0](https://semver.org/) and avoid randomly breaking public APIs. 44 | 45 | - **One pull request per feature**: If you want to implement multiple features, please submit separate pull requests for each. 46 | 47 | - **Send coherent history**: Ensure each commit in your pull request is meaningful. If you made multiple intermediate commits, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submission. 48 | 49 | **Happy coding**! 50 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) realrashid 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Cart](./docs/public/hero.webp) 2 | 3 | Cart is your definitive guide to Simplifying Shopping Cart Management for Laravel. With streamlined cart operations tailored for Laravel-powered E-commerce, Cart ensures a seamless shopping experience. 4 | 5 | In the world of online retail, effective cart management is crucial. That's where Cart comes in. We've fine-tuned the process, providing you with a comprehensive solution for all things cart-related. 6 | 7 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/realrashid/cart.svg?style=flat-square)](https://packagist.org/packages/realrashid/cart) 8 | [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/realrashid/cart/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/realrashid/cart/actions?query=workflow%3Arun-tests+branch%3Amain) 9 | [![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/realrashid/cart/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/realrashid/cart/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) 10 | [![Total Downloads](https://img.shields.io/packagist/dt/realrashid/cart.svg?style=flat-square)](https://packagist.org/packages/realrashid/cart) 11 | 12 | ## Documentation 13 | 14 | Ready to explore all the features and options Cart offers? Dive into our comprehensive documentation: 15 | 16 | - [Installation Guide](https://realrashid.github.io/cart/guide/installation) 17 | - [Usage Instructions](https://realrashid.github.io/cart/usage/usage) 18 | - [Demo App](https://realrashid.github.io/cart/demo/demo) 19 | 20 | ## Testing 21 | 22 | ```bash 23 | composer test 24 | ``` 25 | 26 | ## Changelog 27 | 28 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 29 | 30 | ## Contributing 31 | 32 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 33 | 34 | ## Security Vulnerabilities 35 | 36 | If you discover a security vulnerability in PlanCraft, please help us maintain the security of this project by responsibly disclosing it to us. To report a security vulnerability, please send an email to [realrashid@gmail.com](mailto:realrashid@gmail.com). We'll address the issue as promptly as possible. 37 | 38 | ## Credits 39 | 40 | - [Rashid Ali](https://github.com/realrashid) 41 | - [All Contributors](../../contributors) 42 | 43 | ## Support My Work 44 | 45 | If you find PlanCraft helpful and would like to support my work, you can buy me a coffee. Your support will help keep this project alive and thriving. It's a small token of appreciation that goes a long way. 46 | 47 | [![Buy me a coffee](https://cdn.buymeacoffee.com/buttons/default-orange.png)](https://www.buymeacoffee.com/realrashid) 48 | 49 | ## License 50 | 51 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 52 | 53 |
54 |

Made with ❤️ from Pakistan

55 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "realrashid/cart", 3 | "description": "Meet Cart — your ultimate solution for seamless shopping cart functionality in Laravel applications. Cart simplifies the complexities of shopping cart operations, from product additions to total calculations, ensuring a frictionless user experience.", 4 | "keywords": [ 5 | "realrashid", "laravel", "cart", "shopping cart", "ecommerce", "laravel cart", "cart management", "shopping", "online retail" 6 | ], 7 | "homepage": "https://github.com/realrashid/cart", 8 | "license": "MIT", 9 | "authors": [ 10 | { 11 | "name": "Rashid Ali", 12 | "email": "realrashid05@gmail.com", 13 | "role": "Developer" 14 | } 15 | ], 16 | "support": { 17 | "email": "realrashid05@gmail.com", 18 | "issues": "https://github.com/realrashid/cart/issues", 19 | "source": "https://github.com/realrashid/cart", 20 | "docs": "https://realrashid.github.io/cart/" 21 | }, 22 | "require": { 23 | "php": "^8.1|^8.2", 24 | "laravel/framework": "^8.0 | ^9.0 | ^10.0 | ^11.0" 25 | }, 26 | "require-dev": { 27 | "laravel/pint": "^1.14", 28 | "nunomaduro/collision": "^8.1.1||^7.10.0", 29 | "orchestra/testbench": "^6.0.0||^7.0.0||^8.20||^9.0.0", 30 | "pestphp/pest": "^2.34", 31 | "pestphp/pest-plugin-arch": "^2.7", 32 | "pestphp/pest-plugin-laravel": "^2.3" 33 | }, 34 | "autoload": { 35 | "psr-4": { 36 | "RealRashid\\Cart\\": "src/", 37 | "RealRashid\\Cart\\Database\\Factories\\": "database/factories/" 38 | }, 39 | "files": [ 40 | "src/functions.php" 41 | ] 42 | }, 43 | "autoload-dev": { 44 | "psr-4": { 45 | "App\\": "tests/Support/app/", 46 | "Database\\Factories\\": "tests/Support/database/factories/", 47 | "RealRashid\\Cart\\Tests\\": "tests/", 48 | "Workbench\\App\\": "workbench/app/" 49 | } 50 | }, 51 | "scripts": { 52 | "post-autoload-dump": "@composer run prepare", 53 | "clear": "@php vendor/bin/testbench package:purge-cart --ansi", 54 | "prepare": "@php vendor/bin/testbench package:discover --ansi", 55 | "build": [ 56 | "@composer run prepare", 57 | "@php vendor/bin/testbench workbench:build --ansi" 58 | ], 59 | "start": [ 60 | "Composer\\Config::disableProcessTimeout", 61 | "@composer run build", 62 | "@php vendor/bin/testbench serve" 63 | ], 64 | "analyse": "vendor/bin/phpstan analyse", 65 | "test": "vendor/bin/pest", 66 | "test-coverage": "vendor/bin/pest --coverage", 67 | "format": "vendor/bin/pint" 68 | }, 69 | "config": { 70 | "sort-packages": true, 71 | "allow-plugins": { 72 | "pestphp/pest-plugin": true, 73 | "phpstan/extension-installer": true 74 | } 75 | }, 76 | "extra": { 77 | "laravel": { 78 | "providers": [ 79 | "RealRashid\\Cart\\CartServiceProvider" 80 | ], 81 | "aliases": { 82 | "Cart": "RealRashid\\Cart\\Facades\\Cart" 83 | } 84 | } 85 | }, 86 | "minimum-stability": "dev", 87 | "prefer-stable": true 88 | } 89 | -------------------------------------------------------------------------------- /config/cart.php: -------------------------------------------------------------------------------- 1 | env('CART_DEFAULT_INSTANCE', 'cart'), 23 | 24 | /* 25 | |-------------------------------------------------------------------------- 26 | | Cart Instances 27 | |-------------------------------------------------------------------------- 28 | | 29 | | Here you can define multiple cart instances, each with its own unique 30 | | configuration settings. 31 | | 32 | | You can then switch between these instances dynamically during runtime. 33 | | 34 | | Each instance can have its own tax settings and other configurations. 35 | | 36 | */ 37 | 'instances' => [ 38 | 39 | // Default Cart Instance Configuration 40 | config('cart.default') => [ 41 | 'tax_enabled' => env('CART_TAX_ENABLED', false), // Enable tax for this instance 42 | 'tax_rate' => env('CART_DEFAULT_TAXRATE', 0.10), // The default tax rate for this cart instance (0.10 represents 10% tax) 43 | ], 44 | 45 | // Wishlist Cart Instance Configuration 46 | 'wishlist' => [ 47 | 'tax_rate' => 0, // No tax for wishlist 48 | 'tax_enabled' => false, // Disable tax for this instance 49 | ], 50 | ], 51 | 52 | ]; 53 | -------------------------------------------------------------------------------- /src/Cart.php: -------------------------------------------------------------------------------- 1 | currentInstance = $instance ?: config('cart.default', 'cart'); 33 | 34 | $this->taxRate = $config['tax_rate'] ?? 0; 35 | 36 | $this->loadFromSession(); 37 | } 38 | 39 | /** 40 | * Get or create an instance of the Cart. 41 | * 42 | * This method allows you to retrieve an existing instance of the Cart class based on the provided 43 | * identifier, or create a new one if it doesn't exist. If no identifier is provided, it will use 44 | * the default identifier specified in the configuration file. 45 | * 46 | * @param string|null $instance The identifier for the cart instance (default is null to use config). 47 | * @return Cart Returns the Cart object. 48 | * 49 | * // Creating a cart instance named 'cart' and adding a product to it 50 | * Cart::instance('cart')->add([ 51 | * 'id' => 3, 52 | * 'name' => 'Product 1', 53 | * 'quantity' => 1, 54 | * 'price' => 10.00, 55 | * 'options' => [ 56 | * 'size' => 'XS', 57 | * 'color' => 'blue' 58 | * ] 59 | * ]); 60 | * 61 | * // Creating a different cart instance named 'wishlist' and adding a different product to it 62 | * Cart::instance('wishlist')->add([ 63 | * 'id' => 2, 64 | * 'name' => 'Product 2', 65 | * 'quantity' => 1, 66 | * 'price' => 10.00, 67 | * 'options' => [ 68 | * 'size' => 'XS', 69 | * 'color' => 'pink' 70 | * ] 71 | * ]); 72 | */ 73 | public function instance($instance = null) 74 | { 75 | // If no identifier is provided, use the default from the configuration 76 | $instance = $instance ?: config('cart.default', 'cart'); 77 | 78 | // Retrieve configuration for this instance 79 | $config = config("cart.instances.$instance", []); 80 | 81 | // If the instance doesn't already exist, create a new one 82 | if (!isset(static::$instances[$instance])) { 83 | // Pass the configuration to the constructor 84 | static::$instances[$instance] = new static($instance, $config); 85 | } 86 | 87 | // Return the existing or newly created instance 88 | return static::$instances[$instance] = new static($instance, $config); 89 | } 90 | 91 | /** 92 | * Add an item to the cart. 93 | * 94 | * Handles both single items and multi-items (items as an array). 95 | * Multi-item example: add([['id' => 1, 'quantity' => 2], ['id' => 2, 'quantity' => 1]]); 96 | * 97 | * @param mixed $id The unique identifier for the item, or an array of items. 98 | * @param string|null $name The name of the item (optional). 99 | * @param int $quantity The quantity of the item to add (default is 1). 100 | * @param float|null $price The price of the item (optional). 101 | * @param array $options Additional options for the item (optional). 102 | * @param float|null $taxrate The tax rate for the item (optional). 103 | * @return Cart Returns the Cart object for method chaining. 104 | * 105 | * Usage Example: 106 | * 107 | * // Adding a single item without specifying name, price, and taxrate 108 | * Cart::add(1, null, 2); 109 | * 110 | * // Adding a single item with all details 111 | * Cart::add(2, 'Sample Product', 1, 10.00, ['color' => 'red'], 0.1); 112 | * 113 | * // Adding multiple items at once 114 | * $items = [ 115 | * ['id' => 3, 'quantity' => 2, 'price' => 15.00, 'options' => ['size' => 'small']], 116 | * ['id' => 4, 'quantity' => 1, 'price' => 20.00, 'options' => ['size' => 'large']], 117 | * ]; 118 | * Cart::add($items); 119 | */ 120 | public function add($id, string $name = null, int $quantity = 1, float $price = null, array $options = [], float $taxrate = null) 121 | { 122 | if (!is_int($quantity) || $quantity <= 0) { 123 | throw new InvalidArgumentException('Quantity must be a positive integer.'); 124 | } 125 | 126 | // if (! isset($id) || ! isset($name) || ! isset($quantity)) { 127 | // throw new InvalidArgumentException('Invalid attributes provided for cart item.'); 128 | // } 129 | 130 | // Check if it's a multi-item addition 131 | if ($this->isMultiItem($id)) { 132 | $this->addMultiItem($id); 133 | 134 | return $this; // Return the Cart object for method chaining. 135 | } 136 | 137 | // Handle both single item addition and array item addition 138 | if (is_array($id)) { 139 | $options = Arr::get($id, 'options', []); 140 | 141 | // If the item already exists, update its quantity 142 | if ($this->has($id['id'])) { 143 | $this->updateQuantity($id['id'], $this->items->get($id['id'])->getQuantity() + $quantity); 144 | 145 | return $this; // Return the Cart object for method chaining. 146 | } 147 | 148 | // Create a new CartItem 149 | $cartItem = $this->createCartItem( 150 | $id['id'] ?? null, 151 | $id['name'] ?? null, 152 | $id['quantity'] ?? 1, 153 | $id['price'] ?? null, 154 | $options, 155 | $id['taxrate'] ?? null 156 | ); 157 | } else { 158 | // If the item already exists, update its quantity 159 | if ($this->has($id)) { 160 | $this->updateQuantity($id, $this->items->get($id)->getQuantity() + $quantity); 161 | 162 | return $this; // Return the Cart object for method chaining. 163 | } 164 | 165 | // Create a new CartItem 166 | $cartItem = $this->createCartItem($id, $name, $quantity, $price, $options, $taxrate); 167 | } 168 | 169 | // Add the CartItem to the items collection and save to session 170 | $this->items->put($cartItem->getId(), $cartItem); 171 | $this->saveToSession(); 172 | 173 | return $this; // Return the Cart object for method chaining. 174 | } 175 | 176 | /** 177 | * Update the quantity of an item in the cart. 178 | * 179 | * If the new quantity is less than or equal to 0, the item will be removed from the cart. 180 | * Otherwise, the quantity of the item will be updated. 181 | * 182 | * @param mixed $id The unique identifier of the item. 183 | * @param int $quantity The new quantity for the item. 184 | * 185 | * Usage Example: 186 | * 187 | * // Updating quantity of an item with ID 1 to 3 188 | * Cart::updateQuantity(1, 3); 189 | * 190 | * // Attempting to update quantity to a value less than or equal to 0 will remove the item 191 | * Cart::updateQuantity(2, 0); // Item with ID 2 will be removed from the cart 192 | */ 193 | public function updateQuantity($id, $quantity) 194 | { 195 | // Check if the new quantity is a positive integer 196 | if (!is_int($quantity)) { 197 | throw new InvalidArgumentException('Quantity must be a positive integer.'); 198 | } 199 | 200 | // Check if the item exists in the cart 201 | if ($this->has($id)) { 202 | // Check if the new quantity is less than or equal to 0 203 | if ($quantity <= 0) { 204 | // If so, remove the item from the cart 205 | $this->remove($id); 206 | } else { 207 | // Otherwise, update the quantity of the item 208 | $this->items->get($id)->updateQuantity($quantity); 209 | } 210 | 211 | // Save the updated cart to the session 212 | $this->saveToSession(); 213 | } 214 | // If the item doesn't exist, no action is taken. 215 | } 216 | 217 | /** 218 | * Update the details of an item in the cart. 219 | * 220 | * @param mixed $id The unique identifier of the item. 221 | * @param array $details An array containing the details to update 222 | * (e.g., ['name' => 'New Name', 'price' => 30.00, 'options' => ['size' => 'XL']). 223 | * 224 | * Usage Example: 225 | * 226 | * // Updating details of an item with ID 1 227 | * Cart::updateDetails(1, [ 228 | * 'name' => 'New Name', 229 | * 'price' => 30.00, 230 | * 'options' => ['size' => 'XL'] 231 | * ]); 232 | */ 233 | public function updateDetails($id, $details) 234 | { 235 | // Check if the item exists in the cart 236 | if ($this->has($id)) { 237 | // Retrieve the cart item 238 | $cartItem = $this->items->get($id); 239 | 240 | // Update the details if provided 241 | if (isset($details['name'])) { 242 | $cartItem->updateName($details['name']); 243 | } 244 | 245 | if (isset($details['price'])) { 246 | $cartItem->updatePrice($details['price']); 247 | } 248 | 249 | if (isset($details['options'])) { 250 | $cartItem->updateOptions($details['options']); 251 | } 252 | 253 | // Save the updated cart to the session 254 | $this->saveToSession(); 255 | } 256 | } 257 | 258 | /** 259 | * Update the name of the item. 260 | * 261 | * @param mixed $id The unique identifier of the item. 262 | * @param string $name The new name for the item. 263 | * 264 | * Usage Example: 265 | * 266 | * // Updating the name of an item with ID 1 267 | * Cart::updateName(1, 'New Name'); 268 | */ 269 | public function updateName($id, $name) 270 | { 271 | // Check if the item exists in the cart 272 | if ($this->has($id)) { 273 | // Retrieve the cart item and update its name 274 | $cartItem = $this->items->get($id); 275 | $cartItem->updateName($name); 276 | 277 | // Save the updated cart to the session 278 | $this->saveToSession(); 279 | } 280 | } 281 | 282 | /** 283 | * Update the price of the item. 284 | * 285 | * @param mixed $id The unique identifier of the item. 286 | * @param float $price The new price for the item. 287 | * 288 | * Usage Example: 289 | * 290 | * // Updating the price of an item with ID 1 291 | * Cart::updatePrice(1, 30.00); 292 | */ 293 | public function updatePrice($id, $price) 294 | { 295 | // Check if the item exists in the cart 296 | if ($this->has($id)) { 297 | // Retrieve the cart item and update its price 298 | $cartItem = $this->items->get($id); 299 | $cartItem->updatePrice($price); 300 | 301 | // Save the updated cart to the session 302 | $this->saveToSession(); 303 | } 304 | } 305 | 306 | /** 307 | * Update the options of the item. 308 | * 309 | * @param mixed $id The unique identifier of the item. 310 | * @param array $options The new options for the item. 311 | * 312 | * Usage Example: 313 | * 314 | * // Updating the options of an item with ID 1 315 | * Cart::updateOptions(1, ['size' => 'XL']); 316 | */ 317 | public function updateOptions($id, $options) 318 | { 319 | // Check if the item exists in the cart 320 | if ($this->has($id)) { 321 | // Retrieve the cart item and update its options 322 | $cartItem = $this->items->get($id); 323 | $cartItem->updateOptions($options); 324 | 325 | // Save the updated cart to the session 326 | $this->saveToSession(); 327 | } 328 | } 329 | 330 | /** 331 | * Remove an item from the cart. 332 | * 333 | * @param mixed $id The unique identifier of the item to be removed. 334 | * 335 | * Usage Example: 336 | * 337 | * // Removing an item with ID 1 from the cart 338 | * Cart::remove(1); 339 | */ 340 | public function remove($id) 341 | { 342 | // Check if the item exists in the cart 343 | if ($this->has($id)) { 344 | // Use the 'forget' method to remove the item from the items collection 345 | $this->items->forget($id); 346 | 347 | // After removing the item, the collection is updated. 348 | 349 | // Save the updated cart to the session 350 | $this->saveToSession(); 351 | } 352 | // If the item doesn't exist, no action is taken. 353 | } 354 | 355 | /** 356 | * Clear the entire cart, removing all items. 357 | * 358 | * Usage Example: 359 | * 360 | * // Clearing the entire cart 361 | * Cart::clear(); 362 | */ 363 | public function clear() 364 | { 365 | // Set the items collection to an empty collection, effectively clearing all items. 366 | $this->items = collect([]); 367 | 368 | // Remove cart data from session 369 | Session::forget($this->getSessionKey()); 370 | 371 | // Save the updated cart to the session 372 | $this->saveToSession(); 373 | 374 | // This ensures that the cleared cart is stored in the session for future use. 375 | } 376 | 377 | /** 378 | * Check if an item with a given ID exists in the cart. 379 | * 380 | * @param mixed $id The unique identifier of the item. 381 | * @return bool Returns true if the item exists, otherwise false. 382 | * 383 | * Usage Example: 384 | * 385 | * // Checking if an item with ID 1 exists in the cart 386 | * $exists = Cart::has(1); 387 | * if ($exists) { 388 | * echo "Item with ID 1 exists in the cart."; 389 | * } else { 390 | * echo "Item with ID 1 does not exist in the cart."; 391 | * } 392 | */ 393 | public function has($id) 394 | { 395 | // Use the 'has' method of the items collection to check if an item with the given ID exists. 396 | return $this->items->has($id); 397 | } 398 | 399 | /** 400 | * Retrieve the item with a given ID from the cart. 401 | * 402 | * @param mixed $id The unique identifier of the item. 403 | * @return mixed|null Returns the item if it exists, otherwise null. 404 | * 405 | * Usage Example: 406 | * 407 | * // Retrieving an item with ID 1 from the cart 408 | * $item = Cart::get(1); 409 | * if ($item) { 410 | * echo "Item found!"; 411 | * // You can now access properties or methods of the retrieved item 412 | * $itemName = $item->getName(); 413 | * $itemPrice = $item->getPrice(); 414 | * } else { 415 | * echo "Item with ID 1 not found in the cart."; 416 | * } 417 | */ 418 | public function get($id) 419 | { 420 | // Use the 'get' method of the items collection to retrieve an item with the given ID. 421 | return $this->items->get($id); 422 | } 423 | 424 | /** 425 | * Retrieve all items in the cart as a collection of objects. 426 | * This includes various information about each item. 427 | * 428 | * @return Json A collection containing information about each item in the cart. 429 | * 430 | * Usage Example: 431 | * 432 | * // Get all items in the cart as a collection of objects 433 | * $items = Cart::all(); 434 | * foreach ($items as $item) { 435 | * echo "Item ID: " . $item->id . "
"; 436 | * echo "Item Name: " . $item->name . "
"; 437 | * echo "Item Price: " . $item->price . "
"; 438 | * echo "Item Quantity: " . $item->quantity . "
"; 439 | * // Access other properties as needed 440 | * if (!is_null($item->model)) { 441 | * echo "Associated Model: " . $item->model->name . "
"; 442 | * } 443 | * } 444 | */ 445 | public function all() 446 | { 447 | // Map through each item in the cart 448 | return json_decode($this->items->map(function (CartItem $item) { 449 | // If the item has an associated model, try to associate it with the model. 450 | if ($item->getModel()) { 451 | // Associate the item with its corresponding model 452 | $item->associateModel($item->getModel()::findOrFail($item->getId())); 453 | } 454 | 455 | // Return an object with detailed information about the item. 456 | return [ 457 | 'id' => $item->getId(), 458 | 'name' => $item->getName(), 459 | 'price' => $item->getPrice(), 460 | 'quantity' => $item->getQuantity(), 461 | 'options' => $item->getOptions(), 462 | 'model' => $item->getModel(), 463 | 'taxrate' => $item->getTaxRate(), 464 | ]; 465 | })->toJson()); 466 | } 467 | 468 | /** 469 | * Check if the cart is empty. 470 | * 471 | * @return bool True if the cart is empty, otherwise false. 472 | * 473 | * This method checks if the cart contains any items. 474 | * 475 | * Usage Example: 476 | * 477 | * // Check if the cart is empty 478 | * if (Cart::instance('cart')->empty()) { 479 | * echo "The cart is empty."; 480 | * } else { 481 | * echo "The cart is not empty."; 482 | * } 483 | */ 484 | public function empty() 485 | { 486 | // Use the `isEmpty()` method of the items collection to check if the cart items collection is empty. 487 | return $this->items->isEmpty(); 488 | } 489 | 490 | /** 491 | * Get the total number of items in the cart. 492 | * 493 | * @return int The total number of items in the cart. 494 | * 495 | * Usage Example: 496 | * 497 | * // Get the total number of items in the cart 498 | * $totalItems = Cart::count(); 499 | * echo "Total Items: " . $totalItems; 500 | */ 501 | public function count() 502 | { 503 | // Use the 'count' method of the items collection to get the total number of items. 504 | return $this->items->count(); 505 | } 506 | 507 | /** 508 | * Calculate the total taxes for all items in the cart. 509 | * 510 | * @return float The total taxes for all items in the cart. 511 | * 512 | * Usage Example: 513 | * 514 | * // Calculate the total taxes for all items in the cart 515 | * $totalTaxes = Cart::tax(); 516 | * echo "Total Taxes: " . $totalTaxes; 517 | */ 518 | public function tax() 519 | { 520 | return $this->items->sum(function (CartItem $item) { 521 | // Calculate taxes for each item and sum them up. 522 | return $item->tax(); 523 | }); 524 | } 525 | 526 | /** 527 | * Calculate the total subtotal (pre-tax) price for all items in the cart. 528 | * 529 | * @return float The total subtotal price for all items in the cart. 530 | * 531 | * Usage Example: 532 | * 533 | * // Calculate the total subtotal for all items in the cart 534 | * $totalSubtotal = Cart::subtotal(); 535 | * echo "Total Subtotal: " . $totalSubtotal; 536 | */ 537 | public function subtotal() 538 | { 539 | return $this->items->sum(function (CartItem $item) { 540 | // Calculate the subtotal for each item and sum them up. 541 | return $item->subtotal(); 542 | }); 543 | } 544 | 545 | /** 546 | * Calculate the total price (including taxes) for all items in the cart. 547 | * 548 | * @return float The total price for all items in the cart. 549 | * 550 | * Usage Example: 551 | * 552 | * // Calculate the total price for all items in the cart 553 | * $totalPrice = Cart::total(); 554 | * echo "Total Price: " . $totalPrice; 555 | */ 556 | public function total() 557 | { 558 | $total = $this->items->sum(function (CartItem $item) { 559 | // Calculate the total price for each item and sum them up. 560 | return $item->total(); 561 | }); 562 | 563 | // Retrieve applied coupon from session 564 | $this->appliedCoupon = Session::get('appliedCoupon'); 565 | 566 | if ($this->appliedCoupon) { 567 | $discountAmount = $this->appliedCoupon->getDiscountAmount(); 568 | if ($this->appliedCoupon->getDiscountType() === 'percentage') { 569 | $discount = $total * ($discountAmount / 100); 570 | $total -= $discount; 571 | } elseif ($this->appliedCoupon->getDiscountType() === 'fixed_amount') { 572 | $total -= $discountAmount; 573 | } 574 | 575 | // Ensure total does not go below zero 576 | $total = max($total, 0); 577 | } 578 | 579 | return $total; 580 | } 581 | 582 | /** 583 | * Associate a model with a specific item in the cart. 584 | * 585 | * @param string $id The unique identifier of the cart item. 586 | * @param mixed $model The associated model to be linked with the item. 587 | * 588 | * Usage Example: 589 | * 590 | * // $id is the unique identifier of the cart item, and $product is the associated model. 591 | * Cart::associate($id, $product); 592 | */ 593 | public function associate($id, $model) 594 | { 595 | // Retrieve the cart item with the given row ID 596 | $cartItem = $this->items->get($id); 597 | 598 | // Associate the provided model with it. 599 | $cartItem->associateModel($model); 600 | 601 | // Save the updated cart state to the session. 602 | $this->items->put($id, $cartItem); 603 | $this->saveToSession(); 604 | } 605 | 606 | /** 607 | * Get the tax rate for the cart instance. 608 | * 609 | * @return float|null The tax rate for the cart instance. 610 | */ 611 | public function getTaxRate() 612 | { 613 | // Return the tax rate of the cart instance 614 | return $this->taxRate; 615 | } 616 | 617 | /** 618 | * Apply a coupon to the current session. 619 | * 620 | * @param Coupon $coupon The coupon object to apply. 621 | * 622 | * @throws \Exception If the coupon is not valid. 623 | * 624 | * @return $this 625 | * 626 | * Usage Example: 627 | * 628 | * // Create a percentage-based coupon with code 'PERCENT20', 20% discount, valid until '2024-12-31'. 629 | * $percentageCoupon = new PercentageCoupon('PERCENT20', 20, '2024-12-31'); 630 | * 631 | * // Apply the percentage coupon to the 'cart' instance of the Cart class. 632 | * Cart::instance('cart')->applyCoupon($percentageCoupon); 633 | */ 634 | public function applyCoupon(Coupon $coupon) 635 | { 636 | // Check if the coupon is valid and not expired 637 | if (!$coupon->isValid()) { 638 | throw new \Exception('Coupon is not valid or has expired.'); 639 | } 640 | 641 | // Set the applied coupon to the current instance 642 | $this->appliedCoupon = $coupon; 643 | 644 | // Store the applied coupon in session for persistence 645 | Session::put('appliedCoupon', $this->appliedCoupon); 646 | 647 | // Return $this to allow method chaining 648 | return $this; 649 | } 650 | 651 | /** 652 | * Remove the currently applied coupon from the session. 653 | * 654 | * @return $this 655 | * 656 | * Usage Example: 657 | * 658 | * // Remove the currently applied coupon from the 'cart' instance of the Cart class. 659 | * Cart::instance('cart')->removeCoupon(); 660 | */ 661 | public function removeCoupon() 662 | { 663 | // Remove coupon from session 664 | Session::forget('appliedCoupon'); 665 | 666 | // Clear applied coupon property 667 | $this->appliedCoupon = null; 668 | 669 | // Return $this to allow method chaining 670 | return $this; 671 | } 672 | 673 | /** 674 | * Retrieve the details of the applied coupon from the session. 675 | * 676 | * @return stdClass|null An object containing coupon details (code, type, discountAmount), or null if no coupon is applied. 677 | */ 678 | public function getAppliedCouponDetails() 679 | { 680 | // Retrieve the applied coupon object from the session 681 | $this->appliedCoupon = Session::get('appliedCoupon'); 682 | 683 | // If no coupon is applied, return null 684 | if (!$this->appliedCoupon) { 685 | return null; 686 | } 687 | 688 | // Create a stdClass object to store coupon details 689 | $couponDetails = new \stdClass(); 690 | $couponDetails->code = $this->appliedCoupon->getCode(); 691 | $couponDetails->type = $this->appliedCoupon->getDiscountType(); 692 | 693 | // Calculate the discount amount based on coupon type 694 | if ($this->appliedCoupon->getDiscountType() === 'percentage') { 695 | $discountAmount = $this->subtotal() * ($this->appliedCoupon->getDiscountAmount() / 100); 696 | $couponDetails->discountAmount = round($discountAmount, 2); 697 | } elseif ($this->appliedCoupon->getDiscountType() === 'fixed_amount') { 698 | $couponDetails->discountAmount = $this->appliedCoupon->getDiscountAmount(); 699 | } else { 700 | $couponDetails->discountAmount = 0; 701 | } 702 | 703 | return $couponDetails; 704 | } 705 | 706 | /** 707 | * Check if the provided item is a multi-item (an array of items). 708 | * 709 | * @param mixed $item The item to be checked. 710 | * @return bool True if the item is a multi-item, false otherwise. 711 | */ 712 | private function isMultiItem($item) 713 | { 714 | // Check if the item is an array and if its first element is also an array. 715 | if (!is_array($item)) { 716 | return false; 717 | } 718 | 719 | return is_array(head($item)); 720 | } 721 | 722 | /** 723 | * Add multiple items to the cart. 724 | * 725 | * @param array $items An array of items to be added to the cart. 726 | */ 727 | private function addMultiItem(array $items) 728 | { 729 | foreach ($items as $item) { 730 | // For each item in the provided array, call the 'add' method to add it to the cart. 731 | $this->add( 732 | $item['id'], // Item ID 733 | $item['name'] ?? null, // Item name (defaulting to null if not provided) 734 | $item['quantity'] ?? 1, // Item quantity (defaulting to 1 if not provided) 735 | $item['price'] ?? null, // Item price (defaulting to null if not provided) 736 | $item['options'] ?? [], // Item options (defaulting to an empty array if not provided) 737 | $item['taxrate'] ?? null // Item tax rate (defaulting to null if not provided) 738 | ); 739 | } 740 | } 741 | 742 | /** 743 | * Create a new CartItem instance. 744 | * 745 | * @param mixed $id The unique identifier of the item. 746 | * @param string|null $name The name of the item (or null if not provided). 747 | * @param int $quantity The quantity of the item. 748 | * @param float|null $price The price of the item (or null if not provided). 749 | * @param array $options An array of options for the item. 750 | * @param mixed|null $taxrate The tax rate for the item (or null if not provided). 751 | * @return CartItem The created CartItem instance. 752 | */ 753 | private function createCartItem($id, $name, $quantity, $price, $options, $taxrate) 754 | { 755 | // Check if tax is enabled in the configuration 756 | $taxEnabled = config("cart.instances.$this->currentInstance.tax_enabled"); 757 | 758 | // Create a new CartItem instance with the provided attributes 759 | $cartItem = new CartItem($id, $name, $price, $quantity, $options, null, $taxrate); 760 | 761 | // If tax is enabled and a tax rate is provided, set the tax rate 762 | if ($taxEnabled && isset($taxrate)) { 763 | $cartItem->setTaxRate($taxrate); 764 | } 765 | // If tax is enabled but tax rate is not provided, use default tax rate or throw an exception 766 | elseif ($taxEnabled && !isset($taxrate)) { 767 | // Retrieve the default tax rate from the configuration (again, for clarity) 768 | $defaultTaxRate = config("cart.instances.$this->currentInstance.tax_rate"); 769 | 770 | // If default tax rate is not provided in the configuration, throw an exception 771 | if ($defaultTaxRate === null) { 772 | throw new InvalidArgumentException('Default tax rate is not set in the configuration. Please configure a default tax rate.'); 773 | } 774 | 775 | // Set the default tax rate 776 | $cartItem->setTaxRate($defaultTaxRate); 777 | } 778 | 779 | // Return the created CartItem instance 780 | return $cartItem; 781 | } 782 | 783 | /** 784 | * Get the session key for the current cart instance. 785 | * 786 | * The session key is used to uniquely identify the cart instance in the session. 787 | * 788 | * @return string The session key for the current cart instance. 789 | */ 790 | protected function getSessionKey() 791 | { 792 | return 'cart_' . $this->currentInstance; 793 | } 794 | 795 | /** 796 | * Load cart items from the session into the 'items' collection for the current instance. 797 | * 798 | * This method retrieves the cart items stored in the session for the current instance and 799 | * populates the 'items' collection with CartItem objects. 800 | */ 801 | protected function loadFromSession() 802 | { 803 | // Initialize a new collection to store cart items 804 | $this->items = collect(); 805 | 806 | // Get the session key for the current cart instance 807 | $sessionKey = $this->getSessionKey(); 808 | 809 | // Check if the session contains cart items for the current instance 810 | if (Session::has($sessionKey)) { 811 | // Retrieve the cart items from the session 812 | $cartItems = collect(Session::get($sessionKey)); 813 | 814 | // Iterate through each cart item and create a CartItem object 815 | $cartItems->each(function ($item) { 816 | $cartItem = new CartItem( 817 | $item['id'], 818 | $item['name'], 819 | $item['price'], 820 | $item['quantity'], 821 | $item['options'], 822 | $item['model'], 823 | $item['taxrate'] 824 | ); 825 | 826 | // Add the CartItem to the 'items' collection with its unique identifier 827 | $this->items->put($item['id'], $cartItem); 828 | }); 829 | } 830 | } 831 | 832 | /** 833 | * Save cart items from the 'items' collection to the session for the current instance. 834 | * 835 | * This method takes the cart items stored in the 'items' collection and prepares them for 836 | * storage in the session. It filters out any non-CartItem objects, maps the properties of 837 | * each CartItem, and then stores them in the session using the session key for the current instance. 838 | */ 839 | protected function saveToSession() 840 | { 841 | // Get the session key for the current cart instance 842 | $sessionKey = $this->getSessionKey(); 843 | 844 | // Prepare the cart items for storage in the session 845 | $cartItems = $this->items 846 | ->filter(function ($item) { 847 | return $item instanceof CartItem; 848 | }) 849 | ->map(function (CartItem $item) { 850 | return [ 851 | 'id' => $item->getId(), 852 | 'name' => $item->getName(), 853 | 'price' => $item->getPrice(), 854 | 'quantity' => $item->getQuantity(), 855 | 'options' => $item->getOptions(), 856 | 'model' => $item->getModel(), 857 | 'taxrate' => $item->getTaxRate(), 858 | ]; 859 | }) 860 | ->toArray(); 861 | 862 | // Store the prepared cart items in the session 863 | Session::put($sessionKey, $cartItems); 864 | } 865 | } 866 | -------------------------------------------------------------------------------- /src/CartItem.php: -------------------------------------------------------------------------------- 1 | id = $id; 61 | $this->name = $name; 62 | $this->price = $price; 63 | $this->quantity = $quantity; 64 | $this->options = $options; 65 | $this->model = $model; 66 | $this->taxrate = $taxrate; 67 | } 68 | 69 | /** 70 | * Get the unique identifier of the item. 71 | * 72 | * @return mixed Unique identifier. 73 | */ 74 | public function getId() 75 | { 76 | // Return the unique identifier of the item 77 | return $this->id; 78 | } 79 | 80 | /** 81 | * Get the name of the item. 82 | * 83 | * @return string Item name. 84 | */ 85 | public function getName() 86 | { 87 | // Return the name of the item 88 | return $this->name; 89 | } 90 | 91 | /** 92 | * Get the price of the item. 93 | * 94 | * @return float Item price. 95 | */ 96 | public function getPrice() 97 | { 98 | // Return the price of the item 99 | return $this->price; 100 | } 101 | 102 | /** 103 | * Get the quantity of the item. 104 | * 105 | * @return int Item quantity. 106 | */ 107 | public function getQuantity() 108 | { 109 | // Return the quantity of the item 110 | return $this->quantity; 111 | } 112 | 113 | /** 114 | * Get the additional options for the item. 115 | * 116 | * @return array Array of options. 117 | */ 118 | public function getOptions() 119 | { 120 | // Return the options of the item 121 | return $this->options; 122 | } 123 | 124 | /** 125 | * Get the associated model (if any). 126 | * 127 | * @return mixed Associated model or null. 128 | */ 129 | public function getModel() 130 | { 131 | // Return the associated model of the item (if any) 132 | return $this->model; 133 | } 134 | 135 | /** 136 | * Get the tax rate for the item (if set). 137 | * 138 | * @return mixed Tax rate or null. 139 | */ 140 | public function getTaxRate() 141 | { 142 | // Return the tax rate of the item 143 | return $this->taxrate; 144 | } 145 | 146 | /** 147 | * Set the tax rate for the item. 148 | * 149 | * @param float|null $taxrate Tax rate for the item (optional). 150 | */ 151 | public function setTaxRate(float $taxrate = null) 152 | { 153 | // Set the tax rate for the item 154 | $this->taxrate = $taxrate; 155 | } 156 | 157 | /** 158 | * Update the name of the item. 159 | * 160 | * @param string $name The new name for the item. 161 | */ 162 | public function updateName(string $name): void 163 | { 164 | // Set the new name for the item 165 | $this->name = $name; 166 | } 167 | 168 | /** 169 | * Update the price of the item. 170 | * 171 | * @param float $price The new price for the item. 172 | */ 173 | public function updatePrice(float $price): void 174 | { 175 | // Set the new price for the item 176 | $this->price = $price; 177 | } 178 | 179 | /** 180 | * Update the options of the item. 181 | * 182 | * @param array $options The new options for the item. 183 | */ 184 | public function updateOptions(array $options): void 185 | { 186 | // Set the new options for the item 187 | $this->options = $options; 188 | } 189 | 190 | /** 191 | * Update the quantity of the item. 192 | * 193 | * @param int $quantity New quantity value. 194 | */ 195 | public function updateQuantity($quantity) 196 | { 197 | // Set the new quantity value for the item 198 | $this->quantity = $quantity; 199 | } 200 | 201 | /** 202 | * Associate a model with the item. 203 | * 204 | * @param mixed $model Associated model. 205 | * 206 | * @throws Exception If the supplied model class does not exist. 207 | */ 208 | public function associateModel(Model $model) 209 | { 210 | // Check if the associated model is a string and if the class exists 211 | if (is_string($model) && ! class_exists($model)) { 212 | // If the class does not exist, throw an exception 213 | throw new Exception("The supplied model {$model} does not exist."); 214 | } 215 | 216 | // Set the associated model 217 | $this->model = $model; 218 | } 219 | 220 | /** 221 | * Calculate the subtotal for the item (price * quantity). 222 | * 223 | * @return float Subtotal value. 224 | */ 225 | public function subtotal() 226 | { 227 | // Calculate and return the subtotal 228 | return $this->price * $this->quantity; 229 | } 230 | 231 | /** 232 | * Calculate the tax amount for the item (subtotal * tax rate). 233 | * 234 | * @return float Tax amount. 235 | */ 236 | public function tax() 237 | { 238 | // Check if a tax rate is set for the item 239 | if (isset($this->taxrate)) { 240 | // Calculate tax amount: subtotal * (taxrate / 100) 241 | return $this->subtotal() * ($this->taxrate / 100); 242 | } 243 | 244 | // If no tax rate is set, return 0 245 | return 0; 246 | } 247 | 248 | /** 249 | * Calculate the total amount for the item (subtotal + tax). 250 | * 251 | * @return float Total amount. 252 | */ 253 | public function total() 254 | { 255 | return $this->subtotal() + $this->tax(); 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /src/CartServiceProvider.php: -------------------------------------------------------------------------------- 1 | registerHelpers(); 19 | 20 | // Publishing is only necessary when using the CLI. 21 | if ($this->app->runningInConsole()) { 22 | $this->bootForConsole(); 23 | } 24 | } 25 | 26 | /** 27 | * Register helpers file 28 | * 29 | * @author Rashid Ali 30 | */ 31 | public function registerHelpers(): void 32 | { 33 | // Load the helpers in src/functions.php 34 | if (file_exists($file = __DIR__.'/functions.php')) { 35 | require $file; 36 | } 37 | } 38 | 39 | /** 40 | * Register any package services. 41 | */ 42 | public function register(): void 43 | { 44 | $this->mergeConfigFrom(__DIR__.'/../config/cart.php', 'cart-config'); 45 | 46 | // Register the main class to use with the facade 47 | $this->app->singleton('cart', function ($app) { 48 | return $this->app->make(Cart::class); 49 | }); 50 | } 51 | 52 | /** 53 | * Console-specific booting. 54 | */ 55 | protected function bootForConsole(): void 56 | { 57 | // Publishing the Service Provider file. 58 | $this->publishes([ 59 | __DIR__.'/../stub/CartServiceProvider.php' => app_path('Providers/CartServiceProvider.php'), 60 | ], 'cart-provider'); 61 | 62 | // Publishing the configuration file. 63 | $this->publishes([ 64 | __DIR__.'/../config/cart.php' => config_path('cart.php'), 65 | ], 'cart-config'); 66 | 67 | // Registering package commands. 68 | $this->commands([ 69 | InstallCommand::class, 70 | ]); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Commands/InstallCommand.php: -------------------------------------------------------------------------------- 1 | option('force'); 33 | 34 | // Define the path to CartServiceProvider and config file. 35 | $providerPath = app_path('Providers/CartServiceProvider.php'); 36 | $configPath = config_path('cart.php'); 37 | 38 | // Check if Cart scaffolding is already installed. 39 | $providerInstalled = file_exists($providerPath); 40 | $configInstalled = file_exists($configPath); 41 | 42 | // If --force is used, and both config and provider are installed, ask for confirmation. 43 | if ($force && ($providerInstalled || $configInstalled)) { 44 | if (!$this->confirm('Cart scaffolding is already installed. Do you want to republish the scaffolding?')) { 45 | $this->info('Installation process aborted.'); 46 | 47 | return; 48 | } 49 | } 50 | 51 | // If scaffolding is already installed without --force, exit with a message. 52 | if (!$force && ($providerInstalled || $configInstalled)) { 53 | $this->info('Cart scaffolding already installed. Use --force to republish.'); 54 | return; 55 | } 56 | 57 | // Publish Cart scaffolding. 58 | $this->comment('Initiating the publication of Cart scaffolding...'); 59 | $this->callSilent('vendor:publish', ['--tag' => 'cart-provider', '--force' => $force]); 60 | $this->callSilent('vendor:publish', ['--tag' => 'cart-config', '--force' => $force]); 61 | 62 | // Output success message. 63 | $this->info('Cart scaffolding installed successfully.'); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Coupon/Coupon.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | function cart() 22 | { 23 | return app('cart'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /stub/CartServiceProvider.php: -------------------------------------------------------------------------------- 1 |