diff --git a/README.md b/README.md index 0b17a53..35b1cf4 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ Laravel 5.5+ ## Table of contents * [Configuration Options](#configuration-options) +* [Custom models](#custom-models) * [Drivers](#drivers) * Using the Package * [Cart Management](#cart-management) @@ -103,38 +104,92 @@ Laravel 5.5+ `cart_manager.php` file contains the following config options for the package: -1. **driver :** *(default: DatabaseDriver)* +1. **cart_model :** *(default: Cart)* +The [cart model](#custom-models) that should be used. You can use the existing model or create your own. + +2. **cart_item_model :** *(default: CartItem)* +The [cart item model](#custom-models) that should be used. You can use the existing model or create your own. + +3. **driver :** *(default: DatabaseDriver)* The [driver](#drivers) that should be used to store and retrieve cart details. You can use existing ones or create your own. -2. **auth_guard :** *(default: web)* +4. **auth_guard :** *(default: web)* The authentication guard that should be used to identify the logged in customer. This package can store carts for guest users as well as logged in users. -3. **shipping_charges :** *(default: 10)* +5. **shipping_charges :** *(default: 10)* The amount that should be applied as shipping of the order. -4. **shipping_charges_threshold :** *(default: 100)* +6. **shipping_charges_threshold :** *(default: 100)* The minimum order amount to avoid the shipping charges. Take a note that order amount is calculated as subtotal of the cart items - discount amount. -5. **tax_percentage :** *(default: 6%)* +7. **tax_percentage :** *(default: 6%)* Tax is applied on subtotal of the cart items - discount amount + shipping charges and rounded to 2 decimals. -6. **round_off_to :** *(default: 0.05)* +8. **round_off_to :** *(default: 0.05)* You may wish to round of the order amount to the nearest decimal point. Options are (0 or 0.05 or 0.1 or 0.5 or 1) -7. **cookie_name :** *(default: cart_identifier)* +9. **cookie_name :** *(default: cart_identifier)* The name of the cookie that this package stores to identify the guests of the web app and store their cart data. -8. **cookie_lifetime :** *(default: 1 week)* +10. **cookie_lifetime :** *(default: 1 week)* Number of minutes for which the cart cookie should be valid in customer's browser. -9. **LC_MONETARY :** *(default: en_US.UTF-8)* +11. **LC_MONETARY :** *(default: en_US.UTF-8)* This option is used to display the various totals of the cart with a currency symbol. We use php's native [money_format()](//php.net/manual/en/function.money-format.php) function to display currency with amount. -10. **cart_data_validity :** *(default: 1 week) (Database driver only)* +12. **cart_data_validity :** *(default: 1 week) (Database driver only)* You may wish to remove old/invalid cart data from the database. You can specify the validity period and run/schedule the [ClearCartDataCommand](#commands) for the same. **[⬆ back to top](#table-of-contents)** +## Custom models + +You can use your own custom Cart and CartItem model that extends the default. + +Example for custom Cart model: + +```php +namespace App; + +use Freshbitsweb\LaravelCartManager\Models\Cart; + +class CustomCart extends Cart +{ + // Set table to carts table + protected $table = 'carts'; + + // User relation + public function user() + { + return $this->belongsTo(User::class, 'auth_user', 'id'); + } + + // Coupon relation (Coupon class is not included in this package) + public function coupon() + { + return $this->belongsTo(Coupon::class, 'coupon_id', 'id'); + } +} +``` + +Example for custom CartItem model: + +```php +namespace App; + +use Freshbitsweb\LaravelCartManager\Models\CartItem; + +class CustomCartItem extends CartItem +{ + protected $table = 'cart_items'; + + public function cart() + { + return $this->belongsTo(CustomCart::class, 'cart_id', 'id'); + } +} +``` + ## Drivers You can set the driver that should be used to store and retrieve cart details in the `cart_manager.php` config file. You can use existing ones or create your own driver. diff --git a/config/cart_manager.php b/config/cart_manager.php index 53f2237..2ff7ec6 100644 --- a/config/cart_manager.php +++ b/config/cart_manager.php @@ -1,6 +1,12 @@ Freshbitsweb\LaravelCartManager\Models\Cart::class, + + // Custom cart item class + 'cart_item_model' => Freshbitsweb\LaravelCartManager\Models\CartItem::class, + // The driver that should be used to manage the cart (database/session/custom) 'driver' => Freshbitsweb\LaravelCartManager\Drivers\DatabaseDriver::class, diff --git a/src/CartManagerServiceProvider.php b/src/CartManagerServiceProvider.php index 42363ca..87988a6 100644 --- a/src/CartManagerServiceProvider.php +++ b/src/CartManagerServiceProvider.php @@ -6,7 +6,7 @@ use Freshbitsweb\LaravelCartManager\Core\Cart; use Freshbitsweb\LaravelCartManager\Contracts\CartDriver; use Freshbitsweb\LaravelCartManager\Observers\CartObserver; -use Freshbitsweb\LaravelCartManager\Models\Cart as CartModel; +use Freshbitsweb\LaravelCartManager\Contracts\Cart as CartContract; use Freshbitsweb\LaravelCartManager\Console\Commands\ClearCartDataCommand; class CartManagerServiceProvider extends ServiceProvider @@ -30,7 +30,7 @@ public function boot() $this->commands([ClearCartDataCommand::class]); } - CartModel::observe(CartObserver::class); + resolve(config('cart_manager.cart_model'))::observe(CartObserver::class); } /** @@ -48,6 +48,9 @@ public function register() // Bind the driver with contract $this->app->bind(CartDriver::class, $this->app['config']['cart_manager']['driver']); + // Bind the custom cart model with contract + $this->app->bind(CartContract::class, $this->app['config']['cart_manager']['cart_model']); + // Bind the cart class $this->app->bind(Cart::class, function ($app) { return new Cart($app->make(CartDriver::class)); diff --git a/src/Console/Commands/ClearCartDataCommand.php b/src/Console/Commands/ClearCartDataCommand.php index b5dd4bb..7c3b62e 100644 --- a/src/Console/Commands/ClearCartDataCommand.php +++ b/src/Console/Commands/ClearCartDataCommand.php @@ -5,8 +5,6 @@ use Carbon\Carbon; use Illuminate\Console\Command; use Illuminate\Support\Facades\Schema; -use Freshbitsweb\LaravelCartManager\Models\Cart; -use Freshbitsweb\LaravelCartManager\Models\CartItem; class ClearCartDataCommand extends Command { @@ -40,14 +38,14 @@ public function handle() $validHours = config('cart_manager.cart_data_validity'); - $query = Cart::where('updated_at', '<', Carbon::now()->subHours($validHours)); + $query = resolve(config('cart_manager.cart_model'))::where('updated_at', '<', Carbon::now()->subHours($validHours)); $cartIds = $query->get(['id']); if ($cartIds->isNotEmpty()) { $cartsDeleted = $query->delete(); - CartItem::whereIn('cart_id', $cartIds->pluck('id')->toArray())->delete(); + resolve(config('cart_manager.cart_item_model'))::whereIn('cart_id', $cartIds->pluck('id')->toArray())->delete(); $this->info("$cartsDeleted older cart record(s) removed from the table."); } else { diff --git a/src/Contracts/Cart.php b/src/Contracts/Cart.php new file mode 100644 index 0000000..bf4fb9c --- /dev/null +++ b/src/Contracts/Cart.php @@ -0,0 +1,11 @@ +cartItemsQuery()) + $cartData = resolve(config('cart_manager.cart_model'))::with($this->cartItemsQuery()) ->where($this->cartIdentifier()) ->first($selectColumns) ; // If there is no cart record for the logged in customer, try with cookie identifier if (! $cartData && Auth::guard(config('cart_manager.auth_guard'))->check()) { - $cartData = Cart::with($this->cartItemsQuery()) + $cartData = resolve(config('cart_manager.cart_model'))::with($this->cartItemsQuery()) ->where($this->getCookieElement()) ->first($selectColumns) ; @@ -68,7 +67,7 @@ protected function cartItemsQuery() protected function assignCustomerToCartRecord() { // Assign the logged in customer to the cart record - Cart::where($this->getCookieElement())->update([ + resolve(config('cart_manager.cart_model'))::where($this->getCookieElement())->update([ 'auth_user' => Auth::guard(config('cart_manager.auth_guard'))->id(), ]); } @@ -101,7 +100,7 @@ public function updateCart($cartId, $cartData) { $cartData = $this->arraySnakeCase($cartData); - Cart::where('id', $cartId)->update($cartData); + resolve(config('cart_manager.cart_model'))::where('id', $cartId)->update($cartData); } /** @@ -116,7 +115,7 @@ public function addCartItem($cartId, $cartItem) $cartItem = $this->arraySnakeCase($cartItem); $cartItem['cart_id'] = $cartId; - CartItem::create($cartItem); + resolve(config('cart_manager.cart_item_model'))::create($cartItem); } /** @@ -127,7 +126,7 @@ public function addCartItem($cartId, $cartItem) */ public function removeCartItem($cartItemId) { - CartItem::destroy($cartItemId); + resolve(config('cart_manager.cart_item_model'))::destroy($cartItemId); } /** @@ -140,7 +139,7 @@ protected function storeCartDetails($cartData) { $cartData = $this->arraySnakeCase($cartData); - $cart = Cart::updateOrCreate( + $cart = resolve(config('cart_manager.cart_model'))::updateOrCreate( $this->cartIdentifier(), array_merge($cartData, $this->getCookieElement()) ); @@ -199,7 +198,7 @@ protected function getCookieElement() */ public function setCartItemQuantity($cartItemId, $newQuantity) { - CartItem::where('id', $cartItemId)->update(['quantity' => $newQuantity]); + resolve(config('cart_manager.cart_item_model'))::where('id', $cartItemId)->update(['quantity' => $newQuantity]); } /** @@ -209,7 +208,7 @@ public function setCartItemQuantity($cartItemId, $newQuantity) */ public function clearData() { - $cart = Cart::where($this->cartIdentifier())->first(); + $cart = resolve(config('cart_manager.cart_model'))::where($this->cartIdentifier())->first(); if ($cart) { $cart->delete(); @@ -242,7 +241,7 @@ private function arraySnakeCase($array) public function updateItemsData($items) { $items->each(function ($item) { - CartItem::where('id', $item->id)->update([ + resolve(config('cart_manager.cart_item_model'))::where('id', $item->id)->update([ 'name' => $item->name, 'price' => $item->price, 'image' => $item->image, diff --git a/src/Drivers/SessionDriver.php b/src/Drivers/SessionDriver.php index c0af632..1335737 100644 --- a/src/Drivers/SessionDriver.php +++ b/src/Drivers/SessionDriver.php @@ -2,6 +2,7 @@ namespace Freshbitsweb\LaravelCartManager\Drivers; +use Freshbitsweb\LaravelCartManager\Contracts\Cart; use Freshbitsweb\LaravelCartManager\Contracts\CartDriver; class SessionDriver implements CartDriver diff --git a/src/Models/Cart.php b/src/Models/Cart.php index 9311006..10edf4a 100644 --- a/src/Models/Cart.php +++ b/src/Models/Cart.php @@ -3,8 +3,9 @@ namespace Freshbitsweb\LaravelCartManager\Models; use Illuminate\Database\Eloquent\Model; +use Freshbitsweb\LaravelCartManager\Contracts\Cart as CartContract; -class Cart extends Model +class Cart extends Model implements CartContract { /** * The attributes that are mass assignable. @@ -21,6 +22,6 @@ class Cart extends Model */ public function items() { - return $this->hasMany(CartItem::class); + return $this->hasMany(config('cart_manager.cart_item_model')); } } diff --git a/src/Models/CartItem.php b/src/Models/CartItem.php index 6c5def4..763fe9f 100644 --- a/src/Models/CartItem.php +++ b/src/Models/CartItem.php @@ -32,4 +32,9 @@ public function toArray() 'quantity' => $this->quantity, ]; } + + public function cart() + { + return $this->belongsTo(); + } } diff --git a/src/Observers/CartObserver.php b/src/Observers/CartObserver.php index 4ef03fd..300f238 100644 --- a/src/Observers/CartObserver.php +++ b/src/Observers/CartObserver.php @@ -2,17 +2,17 @@ namespace Freshbitsweb\LaravelCartManager\Observers; -use Freshbitsweb\LaravelCartManager\Models\Cart; +use Freshbitsweb\LaravelCartManager\Contracts\Cart as CartContract; class CartObserver { /** * Listen to the Cart deleting event. * - * @param \Freshbitsweb\LaravelCartManager\Models\Cart $cart + * @param \Freshbitsweb\LaravelCartManager\Contracts\Cart $cart * @return void */ - public function deleting(Cart $cart) + public function deleting(CartContract $cart) { $cart->items()->delete(); } diff --git a/tests/ClearCartDataCommandTest.php b/tests/ClearCartDataCommandTest.php index 8a76f51..6a970d6 100644 --- a/tests/ClearCartDataCommandTest.php +++ b/tests/ClearCartDataCommandTest.php @@ -3,7 +3,6 @@ namespace Freshbitsweb\LaravelCartManager\Test; use Carbon\Carbon; -use Freshbitsweb\LaravelCartManager\Models\Cart; class ClearCartDataCommandTest extends TestCase { @@ -26,7 +25,7 @@ public function clear_cart_command_removes_invalid_data() $validHours = config('cart_manager.cart_data_validity') + 1; - Cart::where('id', 1)->update(['updated_at' => Carbon::now()->subHours($validHours)]); + resolve(config('cart_manager.cart_model'))::where('id', 1)->update(['updated_at' => Carbon::now()->subHours($validHours)]); $this->artisan('lcm_carts:clear_old');