mirror of
https://github.com/wearepixel/laravel-cart.git
synced 2026-11-14 22:01:48 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e810eb4ef4 | ||
|
|
4cf078277d | ||
|
|
7adf5ecd1f | ||
|
|
158cf38f14 | ||
|
|
0f07b9ae8a | ||
|
|
ec99aa0563 | ||
|
|
8d6e1bcc26 | ||
|
|
b92dce9ca4 | ||
|
|
2196f58f01 | ||
|
|
ed4d112665 | ||
|
|
f60bf92157 | ||
|
|
a231ed8c43 | ||
|
|
599051631c | ||
|
|
b3ef4c38fc | ||
|
|
a45121ca63 | ||
|
|
5505f121c7 | ||
|
|
472d505041 | ||
|
|
c6c4240c5f | ||
|
|
54d7c8a54f | ||
|
|
a8d743eb9b | ||
|
|
b7381573e8 | ||
|
|
d4d4df7d58 | ||
|
|
6ea2cb3b8b | ||
|
|
7a2c41e02d | ||
|
|
9a59857825 | ||
|
|
43238b6f2e | ||
|
|
c0f0fcd2f0 | ||
|
|
185c4572ae | ||
|
|
c111cda3aa | ||
|
|
ab9eb6c873 | ||
|
|
7ee26add8d | ||
|
|
05318b7b13 | ||
|
|
4d2efcdeae | ||
|
|
a269c188e4 | ||
|
|
2ccba20119 | ||
|
|
313a4f7aa2 | ||
|
|
4a312a37e2 | ||
|
|
274a8504af | ||
|
|
4f22672ca5 | ||
|
|
61475a7060 | ||
|
|
6604cf984d | ||
|
|
7d955d722c | ||
|
|
54d94d8d12 | ||
|
|
e49ebe02e0 | ||
|
|
28b451583d | ||
|
|
3673f360b7 | ||
|
|
f6447ad4d9 | ||
|
|
b102dd2356 | ||
|
|
25fc662c05 | ||
|
|
57328c2f64 | ||
|
|
4d19211f2c | ||
|
|
8cee4f6208 | ||
|
|
0ec0668bcf | ||
|
|
9a4b5382bd | ||
|
|
95054f41a4 | ||
|
|
0a9bcc2832 | ||
|
|
8c8c90c170 | ||
|
|
18c753f39b | ||
|
|
d12a566366 | ||
|
|
66fd4c9099 | ||
|
|
d48f54cf16 | ||
|
|
24f64e712c | ||
|
|
85ae0c30c5 |
@@ -3,15 +3,15 @@ version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "develop"
|
||||
target-branch: "master"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "deps"
|
||||
- package-ecosystem: "composer"
|
||||
directory: "/"
|
||||
target-branch: "develop"
|
||||
target-branch: "master"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "deps"
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
name: PHP Formatting
|
||||
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
php-formatting:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: "Run Pint"
|
||||
uses: aglipanci/laravel-pint-action@latest
|
||||
with:
|
||||
verboseMode: true
|
||||
configPath: "pint.json"
|
||||
pintVersion: 1.17.2
|
||||
|
||||
- name: Commit changes
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: "Apply Laravel Pint"
|
||||
commit_options: '--no-verify --signoff'
|
||||
file_pattern: "*.php"
|
||||
commit_user_name: "Pixel Tech"
|
||||
commit_user_email: "tech@wearepixel.com.au"
|
||||
commit_author: "Pixel Tech<tech@wearepixel.com.au>"
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
php: ['8.1','8.2', '8.3']
|
||||
php: ['8.2', '8.3', '8.4']
|
||||
stability: [prefer-stable]
|
||||
|
||||
steps:
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
.idea
|
||||
.phpunit.result.cache
|
||||
READMETODO.md
|
||||
build
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Pixel <hello@wearepixel.com.au>
|
||||
Copyright (c) Joel Male <joel@joelmale.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,63 +1,114 @@
|
||||
[](https://packagist.org/packages/wearepixel/laravel-cart)
|
||||
[](https://github.com/wearepixel/laravel-cart/actions?query=workflow%3ATests+branch%3Amaster)
|
||||
[](https://packagist.org/packages/wearepixel/laravel-cart)
|
||||
[](https://packagist.org/packages/wearepixel/laravel-cart)
|
||||
<a name="top"></a>
|
||||
[](https://joelmale.com)
|
||||
[](https://packagist.org/packages/joelwmale/laravel-cart)
|
||||
[](https://github.com/joelwmale/laravel-cart/actions?query=workflow%3ATests+branch%3Amaster)
|
||||
[](https://packagist.org/packages/joelwmale/laravel-cart)
|
||||
[](#)
|
||||
[](https://packagist.org/packages/joelwmale/laravel-cart)
|
||||
[](#-license)
|
||||
|
||||
A Cart Implementation for Laravel.
|
||||
|
||||
Supported Laravel Versions: 9, 10, 11
|
||||
Supported Laravel Versions: 10, 11, and 12.
|
||||
|
||||
## Quick Demo
|
||||
For Laravel 9.0 and below, please use version [1.0](https://github.com/joelwmale/laravel-cart/releases/tag/1.0.12)
|
||||
|
||||
```php
|
||||
// Add an item to the cart
|
||||
\Cart::add(1, 'Product 1', 19.99, 2, ['size' => 'large']);
|
||||
## Table of Contents
|
||||
- [Getting Started](#-getting-started)
|
||||
- [Demo](#-deni)
|
||||
- [Documentation](#-documentation)
|
||||
- [Configuration](#configuration)
|
||||
- [Basic Usage](#basic-usage)
|
||||
- [Conditions](#conditions)
|
||||
- [Cart Items](#cart-items)
|
||||
- [Database Support](#database-support)
|
||||
- [Events](#events)
|
||||
- [Credits](#-credits)
|
||||
- [License](#-license)
|
||||
|
||||
// Get the cart contents
|
||||
$cartContents = \Cart::getContent();
|
||||
|
||||
// Update item quantity by its id
|
||||
\Cart::update(1, ['quantity' => 3]);
|
||||
|
||||
// Remove an item from the cart by its id
|
||||
\Cart::remove(1);
|
||||
|
||||
// Get cart total
|
||||
\$total = Cart::getTotal();
|
||||
|
||||
// Clear the entire cart
|
||||
\Cart::clear();
|
||||
```
|
||||
|
||||
## Installing
|
||||
## 🚀 Getting Started
|
||||
### 🔥 Installing
|
||||
|
||||
Install the package through [Composer](http://getcomposer.org/).
|
||||
|
||||
`composer require "wearepixel/laravel-cart"`
|
||||
`composer require joelwmale/laravel-cart`
|
||||
|
||||
## Configuration
|
||||
## 🧑🍳 Demo
|
||||
|
||||
```php
|
||||
// Add an item to the cart
|
||||
\Cart::add(
|
||||
1, // any unique id
|
||||
'Product 1', // product name
|
||||
19.99, // product price
|
||||
2, // quantity
|
||||
['size' => 'large'] // an array of extra attributes
|
||||
);
|
||||
|
||||
// get the entire cart
|
||||
$cartContents = \Cart::getContent();
|
||||
|
||||
// update an item already in the cart
|
||||
\Cart::update(
|
||||
1, // the same unique id that was used to add the item
|
||||
['quantity' => 3] // the quantity to update
|
||||
);
|
||||
|
||||
// remove the item by its id
|
||||
\Cart::remove(1);
|
||||
|
||||
// get the total of the cart
|
||||
$total = Cart::getTotal();
|
||||
|
||||
// clear it all when you've finished (like when you've stored the order)
|
||||
\Cart::clear();
|
||||
```
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
### ⚙️ Configuration
|
||||
|
||||
You can publish the configuration file to customize various options.
|
||||
|
||||
```php
|
||||
php artisan vendor:publish --provider="Wearepixel\Cart\CartServiceProvider" --tag="config"
|
||||
php artisan vendor:publish --provider="Joelwmale\Cart\CartServiceProvider" --tag="config"
|
||||
```
|
||||
|
||||
## HOW TO USE
|
||||
#### Formatting Numbers
|
||||
|
||||
- [Usage](#usage)
|
||||
- [Conditions](#conditions)
|
||||
- [Items](#items)
|
||||
- [Associating Models](#associating-models)
|
||||
- [Instances](#instances)
|
||||
- [Exceptions](#exceptions)
|
||||
- [Events](#events)
|
||||
- [Format Response](#format)
|
||||
- [Examples](#examples)
|
||||
- [Using Different Storage](#storage)
|
||||
- [License](#license)
|
||||
The package by default does not use round to format numbers, and instead returns the number using floatval().
|
||||
|
||||
## Usage
|
||||
If you'd prefer this number to be rounded, you can customize the formatting in the configuration file.
|
||||
|
||||
Defaults to false.
|
||||
|
||||
```php
|
||||
'format_numbers' => env('LARAVEL_CART_FORMAT_VALUES', false),
|
||||
'round_mode' => env('LARAVEL_CART_ROUND_MODE', 'down'),
|
||||
```
|
||||
|
||||
#### Decimals
|
||||
|
||||
You can customize the number of decimals in the configuration file.
|
||||
|
||||
Defaults to 2.
|
||||
|
||||
```php
|
||||
'decimals' => env('LARAVEL_CART_DECIMALS', 2),
|
||||
```
|
||||
|
||||
#### Round Mode
|
||||
|
||||
The package uses the `round` function to round the prices. You can customize the rounding mode in the configuration file.
|
||||
|
||||
Defaults to `down`.
|
||||
|
||||
```php
|
||||
'round_mode' => env('LARAVEL_CART_ROUND_MODE', 'down'),
|
||||
```
|
||||
|
||||
|
||||
### Basic Usage
|
||||
|
||||
The cart has a default sessionKey that holds the cart data and stores it in the session.
|
||||
|
||||
@@ -76,7 +127,7 @@ ## Usage
|
||||
\Cart::session(User::first()->id)->add(1, 'Product 1', 19.99, 2, ['size' => 'large']);
|
||||
```
|
||||
|
||||
### Adding to the cart: **Cart::add()**
|
||||
#### Adding to the cart: **Cart::add()**
|
||||
|
||||
There are a few ways to add items to the cart.
|
||||
|
||||
@@ -147,7 +198,7 @@ ### Adding to the cart: **Cart::add()**
|
||||
);
|
||||
```
|
||||
|
||||
### Updating an item on a cart: **Cart::update()**
|
||||
#### Updating an item on a cart: **Cart::update()**
|
||||
|
||||
```php
|
||||
Cart::update(
|
||||
@@ -186,14 +237,14 @@ ### Updating an item on a cart: **Cart::update()**
|
||||
);
|
||||
```
|
||||
|
||||
### Removing an item on a cart: **Cart::remove()**
|
||||
#### Removing an item on a cart: **Cart::remove()**
|
||||
|
||||
```php
|
||||
// Remove an item from the cart by its id
|
||||
Cart::remove(456);
|
||||
```
|
||||
|
||||
### Getting an item on a cart: **Cart::get()**
|
||||
#### Getting an item on a cart: **Cart::get()**
|
||||
|
||||
```php
|
||||
// Get an item from the cart by its id
|
||||
@@ -203,7 +254,7 @@ ### Getting an item on a cart: **Cart::get()**
|
||||
$summedPrice = Cart::get($itemId)->getPriceSum();
|
||||
```
|
||||
|
||||
### Getting the cart content: **Cart::getContent()**
|
||||
#### Getting the cart content: **Cart::getContent()**
|
||||
|
||||
```php
|
||||
// Returns a collection of the cart's contents
|
||||
@@ -223,13 +274,13 @@ ### Getting the cart content: **Cart::getContent()**
|
||||
$cartTotalQuantity = Cart::getTotalQuantity();
|
||||
```
|
||||
|
||||
### Cart subtotal: **Cart::getSubTotal()**
|
||||
#### Cart subtotal: **Cart::getSubTotal()**
|
||||
|
||||
```php
|
||||
$subTotal = Cart::getSubTotal();
|
||||
```
|
||||
|
||||
### Cart subtotal without conditions: **Cart::getSubTotalWithoutConditions()**
|
||||
#### Cart subtotal without conditions: **Cart::getSubTotalWithoutConditions()**
|
||||
|
||||
```php
|
||||
$subTotalWithoutConditions = Cart::getSubTotalWithoutConditions();
|
||||
@@ -241,35 +292,47 @@ ### Cart subtotal without conditions: **Cart::getSubTotalWithoutConditions()**
|
||||
$total = Cart::getTotal();
|
||||
```
|
||||
|
||||
### Check if cart is empty: **Cart::isEmpty()**
|
||||
#### Check if cart is empty: **Cart::isEmpty()**
|
||||
|
||||
```php
|
||||
Cart::isEmpty();
|
||||
```
|
||||
|
||||
### Clearing the Cart: **Cart::clear()**
|
||||
#### Clearing the Cart: **Cart::clear()**
|
||||
|
||||
This clears all items and conditions from the cart.
|
||||
|
||||
```php
|
||||
Cart::clear();
|
||||
```
|
||||
|
||||
## Conditions
|
||||
#### Clearing the cart items only: **Cart::clearItems()**
|
||||
|
||||
Conditions are very useful in terms for adding things like discounts, taxes, shipping costs, etc.
|
||||
This clears all items, but keeps the conditions (useful for when you want to keep the conditions but remove the items)
|
||||
|
||||
Conditions can be added on the entire cart or on individual items.
|
||||
```php
|
||||
Cart::clearItems();
|
||||
```
|
||||
|
||||
### Conditions
|
||||
|
||||
Conditions are very useful for adding things like discounts, taxes, shipping, etc.
|
||||
|
||||
Conditions can be added on the entire cart or on individual items, and can even be applied only at certain cart values.
|
||||
|
||||
Conditions on a cart level should always have a `target` of `subtotal` or `total`. This tells the cart which value to apply the condition to.
|
||||
|
||||
You can provide an optional `minimum` value which should be the dollar value in which the target (subtotal or total) needs to be for the condition to be active and impact the cart.
|
||||
|
||||
You can also provide an `order` to cart conditions which tells the cart in what order to apply the conditions. Item level conditions do not support the `order` parameter.
|
||||
|
||||
### Conditions on the cart
|
||||
#### Conditions on the cart
|
||||
|
||||
#### Adding a condition to the cart: **Cart::condition()**
|
||||
##### Adding a condition to the cart: **Cart::condition()**
|
||||
|
||||
```php
|
||||
// Add a single condition to the cart
|
||||
$condition = new \Wearepixel\Cart\CartCondition([
|
||||
$condition = new \Joelwmale\Cart\CartCondition([
|
||||
'name' => 'Tax: 10%',
|
||||
'type' => 'tax',
|
||||
'target' => 'subtotal', // this condition will be applied to cart's subtotal when getSubTotal() is called.
|
||||
@@ -282,7 +345,7 @@ #### Adding a condition to the cart: **Cart::condition()**
|
||||
Cart::condition($condition);
|
||||
|
||||
// Add multiple conditions
|
||||
$tax = new \Wearepixel\Cart\CartCondition([
|
||||
$tax = new \Joelwmale\Cart\CartCondition([
|
||||
'name' => 'Tax: 10%',
|
||||
'type' => 'tax',
|
||||
'target' => 'subtotal', // this condition will be applied to cart's subtotal when getSubTotal() is called.
|
||||
@@ -290,7 +353,7 @@ #### Adding a condition to the cart: **Cart::condition()**
|
||||
'order' => 2
|
||||
]);
|
||||
|
||||
$shipping = new \Wearepixel\Cart\CartCondition([
|
||||
$shipping = new \Joelwmale\Cart\CartCondition([
|
||||
'name' => 'Shipping: $15',
|
||||
'type' => 'shipping',
|
||||
'target' => 'subtotal', // this condition will be applied to cart's subtotal when getSubTotal() is called.
|
||||
@@ -305,7 +368,7 @@ #### Adding a condition to the cart: **Cart::condition()**
|
||||
Cart::condition([$tax, $shipping]);
|
||||
|
||||
// add condition to only apply on totals, not in subtotal
|
||||
$shipping = new \Wearepixel\Cart\CartCondition([
|
||||
$shipping = new \Joelwmale\Cart\CartCondition([
|
||||
'name' => 'Express Shipping $15',
|
||||
'type' => 'shipping',
|
||||
'target' => 'total',
|
||||
@@ -316,7 +379,7 @@ #### Adding a condition to the cart: **Cart::condition()**
|
||||
Cart::condition($shipping);
|
||||
```
|
||||
|
||||
#### Getting conditions on the cart: **Cart::getConditions()**
|
||||
##### Getting conditions on the cart: **Cart::getConditions()**
|
||||
|
||||
```php
|
||||
// To get all applied conditions on a cart, use below:
|
||||
@@ -329,34 +392,175 @@ #### Getting conditions on the cart: **Cart::getConditions()**
|
||||
$condition->getType(); // the type
|
||||
$condition->getValue(); // the value of the condition
|
||||
$condition->getOrder(); // the order of the condition
|
||||
$condition->getMinimum(); // the minimum dollar amount of the target, needed to activate the condition
|
||||
$condition->getMaximum(); // the maximum dollar amount of the target, needed to keep the condition active
|
||||
$condition->getAttributes(); // the attributes of the condition, returns an empty [] if no attributes added
|
||||
}
|
||||
```
|
||||
|
||||
##### Getting conditions on the cart as an array: **Cart::getConditions(array: true)**
|
||||
|
||||
You can get all cart conditions in array format by passing "array: true". This is useful if you want to store the carts conditions on a Livewire component since by default we have collections inside collections for conditions which Livewire does not support.
|
||||
|
||||
```php
|
||||
$cartConditions = Cart::getConditions(true);
|
||||
$cartConditions = Cart::getConditions(active: true);
|
||||
|
||||
foreach ($cartConditions as $condition) {
|
||||
$condition['name']; // the name of the condition
|
||||
$condition['type']; // the type
|
||||
$condition['value']; // the value of the condition
|
||||
$condition['order']; // the order of the condition
|
||||
$condition['minimum']; // the minimum dollar amount of the target, needed to activate the condition
|
||||
$condition['maximum']; // the maximum dollar amount of the target, needed to keep the condition active
|
||||
$condition['attributes']; // the attributes of the condition, returns an empty [] if no attributes added
|
||||
}
|
||||
```
|
||||
|
||||
##### Getting conditions by name: **Cart::getCondition($conditionName)**
|
||||
|
||||
```php
|
||||
$condition = Cart::getCondition('GST');
|
||||
|
||||
// You can also get a condition that has been applied on the cart by using its name:
|
||||
$condition = Cart::getCondition('Tax: 10%');
|
||||
$condition->getTarget(); // the target of which the condition was applied
|
||||
$condition->getName(); // the name of the condition
|
||||
$condition->getType(); // the type
|
||||
$condition->getValue(); // the value of the condition
|
||||
$condition->getMinimum(); // the minimum dollar amount of the target, needed to activate the condition
|
||||
$condition->getMaximum(); // the maximum dollar amount of the target, needed to keep the condition active
|
||||
$condition->getAttributes(); // the attributes of the condition, returns an empty [] if no attributes added
|
||||
```
|
||||
|
||||
### Calculating condition value: **Cart::getCondition('Tax: 10%')->getCalculatedValue($subTotal)**
|
||||
##### Getting active conditions on the cart: **Cart::getConditions(active: true)**
|
||||
|
||||
You can get only active conditions by passsing `active: true` to the `getConditions()` method.
|
||||
|
||||
This will return conditions that are actively being applied to the cart (i.e if they meet their minimum or maximum value)
|
||||
|
||||
```php
|
||||
$tenPercentOff = new CartCondition([
|
||||
'name' => '10% Off',
|
||||
'type' => 'discount',
|
||||
'target' => 'subtotal',
|
||||
'value' => '-10%',
|
||||
'minimum' => 120,
|
||||
'order' => 1,
|
||||
]);
|
||||
|
||||
Cart::getConditions(active: true);
|
||||
|
||||
// will return "10% Off" if the subtotal of the cart is $200.
|
||||
// will return no conditions if the subtotal is $100.
|
||||
|
||||
$shipping = new CartCondition([
|
||||
'name' => 'Shipping',
|
||||
'type' => 'discount',
|
||||
'target' => 'subtotal',
|
||||
'value' => '10',
|
||||
'maximum' => 200,
|
||||
'order' => 1,
|
||||
]);
|
||||
|
||||
Cart::getConditions(active: true);
|
||||
|
||||
// will return "Shipping" if the subtotal of the cart is less than or equal 200
|
||||
// will return no conditions if the subtotal is $210
|
||||
```
|
||||
|
||||
##### Calculating condition value
|
||||
|
||||
There are 2 ways to calculate the value of a condition:
|
||||
|
||||
1. Using the `getCalculatedValue` method on the condition instance
|
||||
2. Using the `getCalculatedValueForCondition` method on the cart instance and passing the condition name
|
||||
|
||||
##### Using the `getCalculatedValue` method on the condition instance
|
||||
|
||||
```php
|
||||
$subTotal = Cart::getSubTotal();
|
||||
$condition = Cart::getCondition('VAT 12.5%');
|
||||
$condition = Cart::getCondition('10% GST');
|
||||
$conditionCalculatedValue = $condition->getCalculatedValue($subTotal);
|
||||
```
|
||||
|
||||
### Condition on items
|
||||
##### Using the `getCalculatedValueForCondition` method on the cart instance
|
||||
|
||||
This method automatically calculates the value of a condition by it's name based on the order of the conditions.
|
||||
|
||||
```php
|
||||
Cart::add([
|
||||
'id' => 1,
|
||||
'name' => 'Apple iPhone 15',
|
||||
'price' => 200,
|
||||
'quantity' => 1,
|
||||
'attributes' => [],
|
||||
]);
|
||||
|
||||
$couponDiscount = new CartCondition([
|
||||
'name' => 'Coupon Discount',
|
||||
'type' => 'discount',
|
||||
'target' => 'subtotal',
|
||||
'value' => '-200',
|
||||
'order' => 1,
|
||||
]);
|
||||
|
||||
$giftCard = new CartCondition([
|
||||
'name' => 'Gift Card',
|
||||
'type' => 'discount',
|
||||
'target' => 'subtotal',
|
||||
'value' => '-200',
|
||||
'order' => 2,
|
||||
]);
|
||||
|
||||
Cart::getCalculatedValueForCondition('Coupon Discount'); // returns 200
|
||||
Cart::getCalculatedValueForCondition('Gift Card'); // returns 0 as the coupon discount is applied first and brings the subtotal to 0
|
||||
```
|
||||
|
||||
##### Adding conditions that activate once a minimum value is met
|
||||
|
||||
You can add a `minimum` amount required for a condition to activate.
|
||||
|
||||
This is useful for applying discounts only after certain cart values, i.e: 10% off for any purchases over $120.
|
||||
|
||||
```php
|
||||
$tenPercentOff = new CartCondition([
|
||||
'name' => '10% Off',
|
||||
'type' => 'discount',
|
||||
'target' => 'subtotal',
|
||||
'value' => '-10%',
|
||||
'minimum' => 120,
|
||||
'order' => 1,
|
||||
]);
|
||||
|
||||
Cart::condition($tenPercentOff)
|
||||
```
|
||||
|
||||
##### Adding conditions that only activate up to a maximum value
|
||||
|
||||
You can add a `maximum` amount required for a condition to activate.
|
||||
|
||||
This is useful for applying discounts up until amounts, i.e shipping for anything below $200, and free shipping above.
|
||||
|
||||
```php
|
||||
$shipping = new CartCondition([
|
||||
'name' => 'Shipping',
|
||||
'type' => 'discount',
|
||||
'target' => 'subtotal',
|
||||
'value' => '12',
|
||||
'maximum' => 200,
|
||||
'order' => 1,
|
||||
]);
|
||||
|
||||
Cart::condition($shipping)
|
||||
```
|
||||
|
||||
#### Conditions on items
|
||||
|
||||
Item conditions are useful if you have discounts to be applied specifically on an item and not on the whole cart value.
|
||||
|
||||
```php
|
||||
|
||||
// lets create first our condition instance
|
||||
$saleCondition = new \Wearepixel\Cart\CartCondition([
|
||||
$saleCondition = new \Joelwmale\Cart\CartCondition([
|
||||
'name' => '50% Off',
|
||||
'type' => 'tax',
|
||||
'value' => '-50%',
|
||||
@@ -376,7 +580,7 @@ ### Condition on items
|
||||
Cart::add($product);
|
||||
|
||||
// You can of course also do multiple conditions on an item
|
||||
$saleCondition = new \Wearepixel\Cart\CartCondition([
|
||||
$saleCondition = new \Joelwmale\Cart\CartCondition([
|
||||
'name' => 'SALE 5%',
|
||||
'type' => 'sale',
|
||||
'value' => '-5%',
|
||||
@@ -410,7 +614,7 @@ ### Condition on items
|
||||
$cartSubTotal = Cart::getSubTotal();
|
||||
```
|
||||
|
||||
#### Add condition to existing Item on the cart: **Cart::addItemCondition($productId, $itemCondition)**
|
||||
##### Add a condition to an existing item on the cart: **Cart::addItemCondition($productId, $itemCondition)**
|
||||
|
||||
Adding Condition to an existing Item on the cart is simple as well.
|
||||
|
||||
@@ -424,31 +628,39 @@ #### Add condition to existing Item on the cart: **Cart::addItemCondition($produ
|
||||
Cart::addItemCondition(456, $condition);
|
||||
```
|
||||
|
||||
### Clearing Cart Conditions: **Cart::clearCartConditions()**
|
||||
#### Clearing Cart Conditions: **Cart::clearCartConditions()**
|
||||
|
||||
This clears all cart level conditions, and does not affect item level conditions.
|
||||
|
||||
```php
|
||||
Cart::clearCartConditions()
|
||||
```
|
||||
|
||||
### Remove a specific cart condtion: **Cart::removeCartCondition($conditionName)**
|
||||
If you wish to clear all conditions from all items and the cart, use **Cart::clearAllConditions()**
|
||||
|
||||
```php
|
||||
Cart::clearAllConditions()
|
||||
```
|
||||
|
||||
##### Remove a specific cart condtion: **Cart::removeCartCondition($conditionName)**
|
||||
|
||||
```php
|
||||
Cart::removeCartCondition('Summer Sale 5%')
|
||||
```
|
||||
|
||||
### Remove a specific item condition: **Cart::removeItemCondition($itemId, $conditionName)**
|
||||
##### Remove a specific item condition: **Cart::removeItemCondition($itemId, $conditionName)**
|
||||
|
||||
```php
|
||||
Cart::removeItemCondition(456, 'SALE 5%')
|
||||
```
|
||||
|
||||
### Clear all item conditions: **Cart::clearItemConditions($itemId)**
|
||||
##### Clear all item conditions: **Cart::clearItemConditions($itemId)**
|
||||
|
||||
```php
|
||||
Cart::clearItemConditions(456)
|
||||
```
|
||||
|
||||
### Get conditions by type: **Cart::getConditionsByType($type)**
|
||||
#### Get conditions by type: **Cart::getConditionsByType($type)**
|
||||
|
||||
This returns all conditions that has been added to the cart by the type specified.
|
||||
|
||||
@@ -456,13 +668,13 @@ ### Get conditions by type: **Cart::getConditionsByType($type)**
|
||||
$tax = Cart::getConditionsByType('tax');
|
||||
```
|
||||
|
||||
### Remove conditions by type: **Cart::removeConditionsByType($type)**
|
||||
##### Remove conditions by type: **Cart::removeConditionsByType($type)**
|
||||
|
||||
```php
|
||||
Cart::removeConditionsByType('tax');
|
||||
```
|
||||
|
||||
## Cart Items
|
||||
### Cart Items
|
||||
|
||||
The method **Cart::getContent()** returns a collection of items.
|
||||
|
||||
@@ -484,8 +696,153 @@ ## Cart Items
|
||||
$item->getPriceSumWithConditions();
|
||||
```
|
||||
|
||||
## Credits
|
||||
### Storage Options
|
||||
|
||||
Huge credits to the original maintainer of the package, located at [darryldecode/laravelshoppingcart](https://github.com/darryldecode/laravelshoppingcart)
|
||||
By default the cart is stored in the session, but there are times you may want to store the cart in the database.
|
||||
|
||||
We have forked this package to update it to Laravel 11 and to add some features and support for newer PHP versions.
|
||||
For instance, you may want to store the cart in the database so that the cart can be retrieved even after the user logs out or closes the browser, or you may want to add cart timeouts and support for multiple computers.
|
||||
|
||||
#### Session
|
||||
|
||||
The cart is stored in the session by default, using Laravel's in-built SessionManager.
|
||||
|
||||
#### Database Support
|
||||
|
||||
To get started, you'll need to create a new model for your Cart, the package requires only 3 columns, but you're free to extend this as you wish and add more columns.
|
||||
|
||||
You can utilise the [events](#events) provided by the package to store additional information alongside the cart.
|
||||
|
||||
```php
|
||||
$table->string('session_id'); // this handles the session id of the cart
|
||||
$table->text('items'); // this will store the cart items
|
||||
$table->text('conditions'); // this will store the cart level conditions
|
||||
```
|
||||
|
||||
Then add some json casts to your model and fillable columns:
|
||||
|
||||
```php
|
||||
protected $guarded = [];
|
||||
|
||||
protected $casts = [
|
||||
'items' => 'array',
|
||||
'conditions' => 'array',
|
||||
];
|
||||
```
|
||||
|
||||
Then update the configuration file to use the database driver:
|
||||
|
||||
```php
|
||||
'driver' => 'database',
|
||||
|
||||
'storage' => [
|
||||
'session',
|
||||
'database' => [
|
||||
'model' => \App\Models\Cart::class, // your model here
|
||||
'id' => 'session_id',
|
||||
'items' => 'items',
|
||||
'conditions' => 'conditions',
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
The package provides a few events that you can listen to in order to manipulate the cart or take actions based on cart events.
|
||||
|
||||
#### LaravelCart.Created
|
||||
|
||||
This fires every time a cart is instantiated (i.e every time \Cart::add() is called)
|
||||
|
||||
```
|
||||
Event::listen('LaravelCart.Added', function () {
|
||||
// cart was created
|
||||
});
|
||||
```
|
||||
|
||||
#### LaravelCart.Adding
|
||||
|
||||
This fires every time an item is being added to the cart
|
||||
|
||||
```
|
||||
Event::listen('LaravelCart.Adding', function ($item) {
|
||||
// item is being added
|
||||
});
|
||||
```
|
||||
|
||||
#### LaravelCart.Added
|
||||
|
||||
This fires every time an item is successfully added to the cart
|
||||
|
||||
```
|
||||
Event::listen('LaravelCart.Added', function ($item) {
|
||||
// item was added
|
||||
});
|
||||
```
|
||||
|
||||
#### LaravelCart.Updating
|
||||
|
||||
This fires every time an item is being updated
|
||||
|
||||
```
|
||||
Event::listen('LaravelCart.Updating', function ($item) {
|
||||
// item is being updated
|
||||
});
|
||||
```
|
||||
|
||||
#### LaravelCart.Updated
|
||||
|
||||
This fires every time an item is successfully updated
|
||||
|
||||
```
|
||||
Event::listen('LaravelCart.Updated', function ($item) {
|
||||
// item was updated
|
||||
});
|
||||
```
|
||||
|
||||
#### LaravelCart.Removing
|
||||
|
||||
This fires every time an item is being removed
|
||||
|
||||
```
|
||||
Event::listen('LaravelCart.Removing', function ($item) {
|
||||
// item is being removed
|
||||
});
|
||||
```
|
||||
|
||||
#### LaravelCart.Removed
|
||||
|
||||
This fires every time an item is successfully removed
|
||||
|
||||
```
|
||||
Event::listen('LaravelCart.Removed', function ($item) {
|
||||
// item was removed
|
||||
});
|
||||
```
|
||||
|
||||
#### LaravelCart.Clearing
|
||||
|
||||
This fires every time the cart is being cleared
|
||||
|
||||
```
|
||||
Event::listen('LaravelCart.Clearing', function () {
|
||||
// cart is being cleared
|
||||
});
|
||||
```
|
||||
|
||||
#### LaravelCart.Cleared
|
||||
|
||||
This fires every time the cart is successfully cleared
|
||||
|
||||
```
|
||||
Event::listen('LaravelCart.Cleared', function () {
|
||||
// cart was cleared
|
||||
});
|
||||
```
|
||||
|
||||
## 🫡 Credits
|
||||
|
||||
This package was orignally created by [darryldecode](https://github.com/darryldecode) but has since seen almost no updates. I have decided to take the old package and transform it into a new package with new features and updates.
|
||||
|
||||
## 📓 License
|
||||
|
||||
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
|
||||
+21
-13
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wearepixel/laravel-cart",
|
||||
"version": "1.0.0",
|
||||
"name": "joelwmale/laravel-cart",
|
||||
"version": "1.2.0",
|
||||
"description": "A cart implementation for Laravel",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
@@ -15,33 +15,41 @@
|
||||
},
|
||||
{
|
||||
"name": "Joel Male",
|
||||
"email": "joel@wearepixel.com.au"
|
||||
"email": "joel@joelmale.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"illuminate/support": "^9.0|^10.0|^11.0",
|
||||
"illuminate/validation": "^9.0|^10.0|^11.0",
|
||||
"illuminate/translation": "^9.0|^10.0|^11.0"
|
||||
"php": ">=8.2",
|
||||
"illuminate/support": "^10.0|^11.0|^12.0",
|
||||
"illuminate/auth": "^10.0|^11.0|^12.0",
|
||||
"illuminate/container": "^10.0|^11.0|^12.0",
|
||||
"illuminate/database": "^10.0|^11.0|^12.0",
|
||||
"illuminate/validation": "^10.0|^11.0|^12.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.4.2",
|
||||
"laravel/pint": "dev-main",
|
||||
"pestphp/pest": "2.34.4"
|
||||
"mockery/mockery": "^1.6",
|
||||
"laravel/pint": "^1.21",
|
||||
"pestphp/pest": "^3.0",
|
||||
"larapack/dd": "dev-master"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Wearepixel\\Cart\\": "src/"
|
||||
"Joelwmale\\Cart\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Wearepixel\\Cart\\CartServiceProvider"
|
||||
"Joelwmale\\Cart\\CartServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"Cart": "Wearepixel\\Cart\\Facades\\CartFacade"
|
||||
"Cart": "Joelwmale\\Cart\\Facades\\CartFacade"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Generated
+3558
-1304
File diff suppressed because it is too large
Load Diff
+15
-20
@@ -3,34 +3,29 @@
|
||||
return [
|
||||
/*
|
||||
* ---------------------------------------------------------------
|
||||
* formatting
|
||||
* Formatting
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* the formatting of shopping cart values
|
||||
*/
|
||||
'format_numbers' => env('SHOPPING_FORMAT_VALUES', false),
|
||||
'format_numbers' => env('LARAVEL_CART_FORMAT_VALUES', false),
|
||||
|
||||
'decimals' => env('SHOPPING_DECIMALS', 0),
|
||||
'decimals' => env('LARAVEL_CART_DECIMALS', 0),
|
||||
|
||||
'dec_point' => env('SHOPPING_DEC_POINT', '.'),
|
||||
|
||||
'thousands_sep' => env('SHOPPING_THOUSANDS_SEP', ','),
|
||||
'round_mode' => env('LARAVEL_CART_ROUND_MODE', 'down'),
|
||||
|
||||
/*
|
||||
* ---------------------------------------------------------------
|
||||
* persistence
|
||||
* Storage
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* the configuration for persisting cart
|
||||
*/
|
||||
'storage' => null,
|
||||
'driver' => 'session',
|
||||
|
||||
/*
|
||||
* ---------------------------------------------------------------
|
||||
* events
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* the configuration for cart events
|
||||
*/
|
||||
'events' => null,
|
||||
'storage' => [
|
||||
'session',
|
||||
'database' => [
|
||||
'model' => '',
|
||||
'id' => '',
|
||||
'items' => '',
|
||||
'conditions' => '',
|
||||
],
|
||||
],
|
||||
];
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -1,17 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.4/phpunit.xsd"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Unit">
|
||||
<directory suffix="Test.php">./tests/Unit</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<source>
|
||||
<source>
|
||||
<include>
|
||||
<directory suffix=".php">./src</directory>
|
||||
</include>
|
||||
</source>
|
||||
<testsuites>
|
||||
<testsuite name="Laravel Cart Test Suite">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<env name="DB_CONNECTION" value="testing"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
+236
-240
@@ -1,100 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart;
|
||||
namespace Joelwmale\Cart;
|
||||
|
||||
use Wearepixel\Cart\Helpers\Helpers;
|
||||
use Wearepixel\Cart\Validators\CartItemValidator;
|
||||
use Wearepixel\Cart\Exceptions\InvalidItemException;
|
||||
use Wearepixel\Cart\Exceptions\UnknownModelException;
|
||||
use Wearepixel\Cart\Exceptions\InvalidConditionException;
|
||||
use Joelwmale\Cart\Helpers\Helpers;
|
||||
use Joelwmale\Cart\Validators\CartItemValidator;
|
||||
use Joelwmale\Cart\Exceptions\InvalidItemException;
|
||||
use Joelwmale\Cart\Exceptions\UnknownModelException;
|
||||
use Joelwmale\Cart\Exceptions\InvalidConditionException;
|
||||
|
||||
class Cart
|
||||
{
|
||||
/**
|
||||
* the item storage
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* the event dispatcher
|
||||
*/
|
||||
protected $events;
|
||||
|
||||
/**
|
||||
* the cart session key
|
||||
*/
|
||||
protected $instanceName;
|
||||
|
||||
/**
|
||||
* the session key use for the cart
|
||||
*/
|
||||
protected $sessionKey;
|
||||
|
||||
/**
|
||||
* the session key use to persist cart items
|
||||
*/
|
||||
protected $sessionKeyCartItems;
|
||||
|
||||
/**
|
||||
* the session key use to persist cart conditions
|
||||
*/
|
||||
protected $sessionKeyCartConditions;
|
||||
|
||||
/**
|
||||
* Configuration to pass to ItemCollection
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* This holds the currently added item id in cart for association
|
||||
*/
|
||||
protected $currentItemId;
|
||||
|
||||
/**
|
||||
* The number of decimals to use when formatting prices
|
||||
*/
|
||||
protected $decimals;
|
||||
|
||||
/**
|
||||
* The decimal point character
|
||||
*/
|
||||
protected $decPoint;
|
||||
|
||||
/**
|
||||
* our object constructor
|
||||
*/
|
||||
public function __construct($session, $events, $instanceName, $session_key, $config)
|
||||
public function __construct($sessionStorage, $events, $instanceName, $sessionKey, $config)
|
||||
{
|
||||
$this->validateConfig($config);
|
||||
|
||||
$this->events = $events;
|
||||
$this->session = $session;
|
||||
$this->session = new CartSession($sessionStorage, $sessionKey, $config);
|
||||
$this->instanceName = $instanceName;
|
||||
$this->sessionKey = $session_key;
|
||||
$this->sessionKeyCartItems = $this->sessionKey . '_cart_items';
|
||||
$this->sessionKeyCartConditions = $this->sessionKey . '_cart_conditions';
|
||||
$this->config = $config;
|
||||
$this->currentItemId = null;
|
||||
$this->fireEvent('created');
|
||||
|
||||
$this->fireEvent('Created');
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the session key
|
||||
*
|
||||
* @param string $sessionKey the session key or identifier
|
||||
* @return $this|bool
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function session($sessionKey)
|
||||
private function validateConfig($config)
|
||||
{
|
||||
if (! $sessionKey) {
|
||||
throw new \Exception('Session key is required.');
|
||||
if ($config['driver'] == 'database') {
|
||||
if (! isset($config['storage']['database']['model'])) {
|
||||
throw new \Exception('You need to set a model for the database driver in the cart configuration.');
|
||||
}
|
||||
|
||||
$this->sessionKey = $sessionKey;
|
||||
$this->sessionKeyCartItems = $this->sessionKey . '_cart_items';
|
||||
$this->sessionKeyCartConditions = $this->sessionKey . '_cart_conditions';
|
||||
if (! isset($config['storage']['database']['id'])) {
|
||||
throw new \Exception('You need to set an id (for the session) for the database driver in the cart configuration.');
|
||||
}
|
||||
|
||||
return $this;
|
||||
if (! isset($config['storage']['database']['items'])) {
|
||||
throw new \Exception('You need to set an items key for the database driver in the cart configuration.');
|
||||
}
|
||||
|
||||
if (! isset($config['storage']['database']['conditions'])) {
|
||||
throw new \Exception('You need to set a conditions key for the database driver in the cart configuration.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,20 +68,16 @@ public function getInstanceName()
|
||||
|
||||
/**
|
||||
* get an item on a cart by item ID
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($itemId)
|
||||
public function get($itemId): ?ItemCollection
|
||||
{
|
||||
return $this->getContent()->get($itemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if an item exists by item ID
|
||||
*
|
||||
* @return bool
|
||||
* check if we have this item in the cart by item ID
|
||||
*/
|
||||
public function has($itemId)
|
||||
public function has($itemId): bool
|
||||
{
|
||||
return $this->getContent()->has($itemId);
|
||||
}
|
||||
@@ -131,29 +86,28 @@ public function has($itemId)
|
||||
* add item to the cart, it can be an array or multi dimensional array
|
||||
*
|
||||
* @param string|array $id
|
||||
* @param string $name
|
||||
* @param float $price
|
||||
* @param int $quantity
|
||||
* @param array $attributes
|
||||
* @param CartCondition|array $conditions
|
||||
* @param string $associatedModel
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidItemException
|
||||
*/
|
||||
public function add($id, $name = null, $price = null, $quantity = null, $attributes = [], $conditions = [], $associatedModel = null)
|
||||
{
|
||||
// if the first argument is an array,
|
||||
// we will need to call add again
|
||||
public function add(
|
||||
string|int|array $id,
|
||||
?string $name = null,
|
||||
?float $price = null,
|
||||
int|float|null $quantity = null,
|
||||
array $attributes = [],
|
||||
array|CartCondition $conditions = [],
|
||||
?string $associatedModel = null
|
||||
): self {
|
||||
// check if we are adding an array of items
|
||||
if (is_array($id)) {
|
||||
// the first argument is an array, now we will need to check if it is a multi dimensional
|
||||
// array, if so, we will iterate through each item and call add again
|
||||
// check if we are adding a multi dimensional array
|
||||
if (Helpers::isMultiArray($id)) {
|
||||
foreach ($id as $item) {
|
||||
$this->add(
|
||||
$item['id'],
|
||||
$item['name'],
|
||||
$item['price'],
|
||||
isset($item['price']) ? $item['price'] : null,
|
||||
$item['quantity'],
|
||||
Helpers::issetAndHasValueOrAssignDefault($item['attributes'], []),
|
||||
Helpers::issetAndHasValueOrAssignDefault($item['conditions'], []),
|
||||
@@ -164,7 +118,7 @@ public function add($id, $name = null, $price = null, $quantity = null, $attribu
|
||||
$this->add(
|
||||
$id['id'],
|
||||
$id['name'],
|
||||
$id['price'],
|
||||
isset($id['price']) ? $id['price'] : null,
|
||||
$id['quantity'],
|
||||
Helpers::issetAndHasValueOrAssignDefault($id['attributes'], []),
|
||||
Helpers::issetAndHasValueOrAssignDefault($id['conditions'], []),
|
||||
@@ -175,6 +129,7 @@ public function add($id, $name = null, $price = null, $quantity = null, $attribu
|
||||
return $this;
|
||||
}
|
||||
|
||||
// if we are here, we are adding a single item
|
||||
$data = [
|
||||
'id' => $id,
|
||||
'name' => $name,
|
||||
@@ -191,16 +146,11 @@ public function add($id, $name = null, $price = null, $quantity = null, $attribu
|
||||
// validate data
|
||||
$item = $this->validate($data);
|
||||
|
||||
// get the cart
|
||||
$cart = $this->getContent();
|
||||
|
||||
// if the item is already in the cart we will just update it
|
||||
if ($cart->has($id)) {
|
||||
|
||||
if ($this->get($id)) {
|
||||
$this->update($id, $item);
|
||||
} else {
|
||||
|
||||
$this->addRow($id, $item);
|
||||
$this->addItem($id, $item);
|
||||
}
|
||||
|
||||
$this->currentItemId = $id;
|
||||
@@ -209,37 +159,23 @@ public function add($id, $name = null, $price = null, $quantity = null, $attribu
|
||||
}
|
||||
|
||||
/**
|
||||
* update a cart
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* the $data will be an associative array, you don't need to pass all the data, only the key value
|
||||
* of the item you want to update on it
|
||||
* @return bool
|
||||
* Update a cart item with whatever data is passed in
|
||||
*/
|
||||
public function update($id, $data)
|
||||
public function update(int|string $id, array $data): bool
|
||||
{
|
||||
if ($this->fireEvent('updating', $data) === false) {
|
||||
if ($this->fireEvent('Updating', 'item', $data) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cart = $this->getContent();
|
||||
|
||||
$item = $cart->pull($id);
|
||||
$item = $cart->get($id);
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
// if the key is currently "quantity" we will need to check if an arithmetic
|
||||
// symbol is present so we can decide if the update of quantity is being added
|
||||
// or being reduced.
|
||||
if ($key == 'quantity') {
|
||||
// we will check if quantity value provided is array,
|
||||
// if it is, we will need to check if a key "relative" is set
|
||||
// and we will evaluate its value if true or false,
|
||||
// this tells us how to treat the quantity value if it should be updated
|
||||
// relatively to its current quantity value or just totally replace the value
|
||||
if (is_array($value)) {
|
||||
if (isset($value['relative'])) {
|
||||
if ((bool) $value['relative']) {
|
||||
if (isset($value['relative']) && $value['relative'] === true) {
|
||||
$item = $this->updateQuantityRelative($item, $key, $value['value']);
|
||||
} else {
|
||||
$item = $this->updateQuantityNotRelative($item, $key, $value['value']);
|
||||
@@ -255,11 +191,12 @@ public function update($id, $data)
|
||||
}
|
||||
}
|
||||
|
||||
// update the item in the cart
|
||||
$cart->put($id, $item);
|
||||
|
||||
$this->save($cart);
|
||||
|
||||
$this->fireEvent('updated', $item);
|
||||
$this->fireEvent('Updated', 'item', $item);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -285,11 +222,11 @@ public function setConfig($config)
|
||||
public function addItemCondition($productId, $itemCondition)
|
||||
{
|
||||
if ($product = $this->get($productId)) {
|
||||
$conditionInstance = '\\Wearepixel\\Cart\\CartCondition';
|
||||
$conditionInstance = '\\Joelwmale\\Cart\\CartCondition';
|
||||
|
||||
if ($itemCondition instanceof $conditionInstance) {
|
||||
// we need to copy first to a temporary variable to hold the conditions
|
||||
// to avoid hitting this error "Indirect modification of overloaded element of Wearepixel\Cart\ItemCollection has no effect"
|
||||
// to avoid hitting this error "Indirect modification of overloaded element of Joelwmale\Cart\ItemCollection has no effect"
|
||||
// this is due to laravel Collection instance that implements Array Access
|
||||
// // see link for more info: http://stackoverflow.com/questions/20053269/indirect-modification-of-overloaded-element-of-splfixedarray-has-no-effect
|
||||
$itemConditionTempHolder = $product['conditions'];
|
||||
@@ -318,7 +255,7 @@ public function remove($id)
|
||||
{
|
||||
$cart = $this->getContent();
|
||||
|
||||
if ($this->fireEvent('removing', $id) === false) {
|
||||
if ($this->fireEvent('Removing', 'item', $id) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -326,41 +263,46 @@ public function remove($id)
|
||||
|
||||
$this->save($cart);
|
||||
|
||||
$this->fireEvent('removed', $id);
|
||||
$this->fireEvent('Removed', 'item', $id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* clear cart
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
if ($this->fireEvent('clearing') === false) {
|
||||
if ($this->fireEvent('Clearing') === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->session->put(
|
||||
$this->sessionKeyCartItems,
|
||||
[]
|
||||
);
|
||||
$this->session->clear();
|
||||
|
||||
$this->fireEvent('cleared');
|
||||
$this->fireEvent('Cleared');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function clearItems()
|
||||
{
|
||||
if ($this->fireEvent('Clearing') === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->session->clearItems();
|
||||
|
||||
$this->fireEvent('Cleared');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* add a condition on the cart
|
||||
*
|
||||
* @param CartCondition|array $condition
|
||||
* @return $this
|
||||
* Adds a condition to the cart
|
||||
*/
|
||||
/**
|
||||
* Adds a condition to the cart
|
||||
*
|
||||
* @throws InvalidConditionException
|
||||
*/
|
||||
public function condition($condition)
|
||||
public function condition(array|CartCondition $condition): self
|
||||
{
|
||||
if (is_array($condition)) {
|
||||
foreach ($condition as $c) {
|
||||
@@ -371,7 +313,7 @@ public function condition($condition)
|
||||
}
|
||||
|
||||
if (! $condition instanceof CartCondition) {
|
||||
throw new InvalidConditionException('Argument 1 must be an instance of \'Wearepixel\Cart\CartCondition\'');
|
||||
throw new InvalidConditionException('Argument 1 must be an instance of \'Joelwmale\Cart\CartCondition\'');
|
||||
}
|
||||
|
||||
$conditions = $this->getConditions();
|
||||
@@ -384,7 +326,9 @@ public function condition($condition)
|
||||
|
||||
$conditions->put($condition->getName(), $condition);
|
||||
|
||||
$conditions = $conditions->sortBy(function ($condition, $key) {
|
||||
$conditions = $conditions->reject(function ($condition) {
|
||||
return empty($condition);
|
||||
})->sortBy(function ($condition, $key) {
|
||||
return $condition->getOrder();
|
||||
});
|
||||
|
||||
@@ -396,11 +340,34 @@ public function condition($condition)
|
||||
/**
|
||||
* get conditions applied on the cart
|
||||
*
|
||||
* @return CartConditionCollection
|
||||
* @param bool $active - If true, only conditions actually applied on the cart are returned
|
||||
*/
|
||||
public function getConditions()
|
||||
public function getConditions(bool $array = false, bool $active = false): CartConditionCollection|array
|
||||
{
|
||||
return new CartConditionCollection($this->session->get($this->sessionKeyCartConditions));
|
||||
$conditions = new CartConditionCollection($this->session->getConditions());
|
||||
|
||||
$conditions = $conditions->reject(function ($condition) {
|
||||
return empty($condition);
|
||||
})
|
||||
->transform(function ($condition) {
|
||||
return $condition instanceof CartCondition ? $condition : new CartCondition($condition);
|
||||
});
|
||||
|
||||
if ($active) {
|
||||
return $conditions->filter(function (CartCondition $condition) {
|
||||
$amount = $condition->getTarget() == 'subtotal' ? $this->getSubTotal(false) : $this->getTotal();
|
||||
|
||||
return $condition->getMinimum() === null || $condition->getMinimum() <= $amount;
|
||||
})->filter(function (CartCondition $condition) {
|
||||
$amount = $condition->getTarget() == 'subtotal' ? $this->getSubTotal(false) : $this->getTotal();
|
||||
|
||||
return $condition->getMaximum() === null || $condition->getMaximum() >= $amount;
|
||||
});
|
||||
}
|
||||
|
||||
return $array ? $conditions->map(function (CartCondition $condition) {
|
||||
return $condition->toArray();
|
||||
})->toArray() : $conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,12 +396,8 @@ public function getConditionsByType($type)
|
||||
|
||||
/**
|
||||
* Remove all the condition with the $type specified
|
||||
* Please Note that this will only remove condition added on cart bases, not those conditions added
|
||||
* specifically on an per item bases
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeConditionsByType($type)
|
||||
public function removeConditionsByType(string $type)
|
||||
{
|
||||
$this->getConditionsByType($type)->each(function ($condition) {
|
||||
$this->removeCartCondition($condition->getName());
|
||||
@@ -442,12 +405,7 @@ public function removeConditionsByType($type)
|
||||
}
|
||||
|
||||
/**
|
||||
* removes a condition on a cart by condition name,
|
||||
* this can only remove conditions that are added on cart bases not conditions that are added on an item/product.
|
||||
* If you wish to remove a condition that has been added for a specific item/product, you may
|
||||
* use the removeItemCondition(itemId, conditionName) method instead.
|
||||
*
|
||||
* @return void
|
||||
* Remove a condition from the cart
|
||||
*/
|
||||
public function removeCartCondition($conditionName)
|
||||
{
|
||||
@@ -497,7 +455,7 @@ public function removeItemCondition($itemId, $conditionName)
|
||||
// on the given condition name the user wants to remove, if so,
|
||||
// lets just make $item['conditions'] an empty array as there's just 1 condition on it anyway
|
||||
else {
|
||||
$conditionInstance = 'Wearepixel\\Cart\\CartCondition';
|
||||
$conditionInstance = 'Joelwmale\\Cart\\CartCondition';
|
||||
|
||||
if ($item['conditions'] instanceof $conditionInstance) {
|
||||
if ($tempConditionsHolder->getName() == $conditionName) {
|
||||
@@ -533,18 +491,25 @@ public function clearItemConditions($itemId)
|
||||
}
|
||||
|
||||
/**
|
||||
* clears all conditions on a cart,
|
||||
* this does not remove conditions that has been added specifically to an item/product.
|
||||
* If you wish to remove a specific condition to a product, you may use the method: removeItemCondition($itemId, $conditionName)
|
||||
*
|
||||
* @return void
|
||||
* Clear cart conditions (this does not clear item conditions)
|
||||
*/
|
||||
public function clearCartConditions()
|
||||
public function clearCartConditions(): void
|
||||
{
|
||||
$this->session->put(
|
||||
$this->sessionKeyCartConditions,
|
||||
[]
|
||||
);
|
||||
$this->session->putConditions([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all conditions from all items and the cart
|
||||
*/
|
||||
public function clearAllConditions(): void
|
||||
{
|
||||
$cart = $this->getContent();
|
||||
|
||||
$cart->each(function ($item) {
|
||||
$this->clearItemConditions($item->id);
|
||||
});
|
||||
|
||||
$this->clearCartConditions();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -564,85 +529,108 @@ public function getSubTotalWithoutConditions($formatted = true)
|
||||
return Helpers::formatValue(floatval($sum), $formatted, $this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* get cart sub total
|
||||
*
|
||||
* @param bool $formatted
|
||||
* @return float
|
||||
*/
|
||||
public function getSubTotal($formatted = true)
|
||||
public function getSubTotal($formatted = true): int|float|string
|
||||
{
|
||||
$cart = $this->getContent();
|
||||
$subTotal = 0.00;
|
||||
|
||||
$sum = $cart->sum(function (ItemCollection $item) {
|
||||
// add all the items together with conditions applied
|
||||
$subTotalSum = $this->getContent()->sum(function (ItemCollection $item) {
|
||||
return $item->getPriceSumWithConditions(false);
|
||||
});
|
||||
|
||||
// get the conditions that are meant to be applied
|
||||
// on the subtotal and apply it here before returning the subtotal
|
||||
$conditions = $this
|
||||
->getConditions()
|
||||
->filter(function (CartCondition $cond) {
|
||||
return $cond->getTarget() === 'subtotal';
|
||||
$conditionsForSubtotal = $this->getConditions()
|
||||
->filter(function (CartCondition $condition) {
|
||||
return $condition->getTarget() === 'subtotal';
|
||||
})
|
||||
->filter(function (CartCondition $condition) use ($subTotalSum) {
|
||||
return $condition->getMinimum() === null || $condition->getMinimum() <= $subTotalSum;
|
||||
})
|
||||
->filter(function (CartCondition $condition) use ($subTotalSum) {
|
||||
return $condition->getMaximum() === null || $condition->getMaximum() >= $subTotalSum;
|
||||
})
|
||||
->sortBy(function (CartCondition $condition) {
|
||||
return $condition->getOrder();
|
||||
});
|
||||
|
||||
// if there is no conditions, lets just return the sum
|
||||
if (! $conditions->count()) {
|
||||
return Helpers::formatValue($sum, $formatted, $this->config);
|
||||
if ($conditionsForSubtotal->isEmpty()) {
|
||||
return Helpers::formatValue($subTotalSum, $formatted, $this->config);
|
||||
}
|
||||
|
||||
// there are conditions, lets apply it
|
||||
$newTotal = 0.00;
|
||||
$process = 0;
|
||||
$index = 0;
|
||||
|
||||
$conditions->each(function (CartCondition $cond) use ($sum, &$newTotal, &$process) {
|
||||
$conditionsForSubtotal->each(function (CartCondition $condition) use ($subTotalSum, &$subTotal, &$index) {
|
||||
$toBeCalculated = $index > 0 ? $subTotal : $subTotalSum;
|
||||
|
||||
// if this is the first iteration, the toBeCalculated
|
||||
// should be the sum as initial point of value.
|
||||
$toBeCalculated = ($process > 0) ? $newTotal : $sum;
|
||||
$subTotal = $condition->applyCondition($toBeCalculated);
|
||||
|
||||
$newTotal = $cond->applyCondition($toBeCalculated);
|
||||
|
||||
$process++;
|
||||
$index++;
|
||||
});
|
||||
|
||||
return Helpers::formatValue((float) $newTotal, $formatted, $this->config);
|
||||
return Helpers::formatValue($subTotal, $formatted, $this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* the new total in which conditions are already applied
|
||||
*
|
||||
* @return float
|
||||
* Get the total of the cart with conditions applied
|
||||
*/
|
||||
public function getTotal()
|
||||
public function getTotal(): int|float
|
||||
{
|
||||
$total = 0.00;
|
||||
$subTotal = $this->getSubTotal(false);
|
||||
|
||||
$newTotal = 0.00;
|
||||
|
||||
$process = 0;
|
||||
|
||||
$conditions = $this
|
||||
->getConditions()
|
||||
->filter(function (CartCondition $cond) {
|
||||
return $cond->getTarget() === 'total';
|
||||
$conditionsForTotal = $this->getConditions()
|
||||
->filter(function (CartCondition $condition) {
|
||||
return $condition->getTarget() === 'total';
|
||||
})
|
||||
->filter(function (CartCondition $condition) use ($subTotal) {
|
||||
return $condition->getMinimum() === null || $condition->getMinimum() <= $subTotal;
|
||||
})
|
||||
->filter(function (CartCondition $condition) use ($subTotal) {
|
||||
return $condition->getMaximum() === null || $condition->getMaximum() >= $subTotal;
|
||||
})
|
||||
->sortBy(function (CartCondition $condition) {
|
||||
return $condition->getOrder();
|
||||
});
|
||||
|
||||
// if no conditions were added, just return the sub total
|
||||
if (! $conditions->count()) {
|
||||
if (! $conditionsForTotal->count()) {
|
||||
return Helpers::formatValue($subTotal, $this->config['format_numbers'], $this->config);
|
||||
}
|
||||
|
||||
$conditions
|
||||
->each(function (CartCondition $cond) use ($subTotal, &$newTotal, &$process) {
|
||||
$toBeCalculated = ($process > 0) ? $newTotal : $subTotal;
|
||||
$index = 0;
|
||||
|
||||
$newTotal = $cond->applyCondition($toBeCalculated);
|
||||
$conditionsForTotal->each(function (CartCondition $condition) use ($subTotal, &$total, &$index) {
|
||||
$toBeCalculated = ($index > 0) ? $total : $subTotal;
|
||||
|
||||
$process++;
|
||||
$total = $condition->applyCondition($toBeCalculated);
|
||||
|
||||
$index++;
|
||||
});
|
||||
|
||||
return Helpers::formatValue($newTotal, $this->config['format_numbers'], $this->config);
|
||||
return Helpers::formatValue($total, $this->config['format_numbers'], $this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the calculated value for a condition by it's name
|
||||
*/
|
||||
public function getCalculatedValueForCondition(string $conditionName): int|float
|
||||
{
|
||||
$conditions = $this->getConditions();
|
||||
|
||||
$subTotal = $this->getSubTotalWithoutConditions(false);
|
||||
|
||||
foreach ($conditions as $condition) {
|
||||
$conditionValue = $condition->getCalculatedValue($subTotal);
|
||||
|
||||
if ($condition->getName() === $conditionName) {
|
||||
return $conditionValue;
|
||||
}
|
||||
|
||||
$subTotal -= $conditionValue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -665,24 +653,16 @@ public function getTotalQuantity()
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the cart
|
||||
*
|
||||
* @return CartCollection
|
||||
*/
|
||||
public function getContent()
|
||||
public function getContent(): CartCollection
|
||||
{
|
||||
return (new CartCollection($this->session->get($this->sessionKeyCartItems)))->reject(function ($item) {
|
||||
return (new CartCollection($this->session->getItems()))->transform(function ($item) {
|
||||
return $item instanceof ItemCollection ? $item : new ItemCollection($item, $this->config);
|
||||
})->reject(function ($item) {
|
||||
return ! ($item instanceof ItemCollection);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* check if cart is empty
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmpty()
|
||||
public function isEmpty($test = null)
|
||||
{
|
||||
return $this->getContent()->isEmpty();
|
||||
}
|
||||
@@ -698,15 +678,24 @@ protected function validate($item)
|
||||
{
|
||||
$rules = [
|
||||
'id' => 'required',
|
||||
'price' => 'required|numeric',
|
||||
'quantity' => 'required|numeric|min:0.1',
|
||||
'name' => 'required',
|
||||
'quantity' => 'required|numeric|min:0.1',
|
||||
];
|
||||
|
||||
$validator = CartItemValidator::make($item, $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
throw new InvalidItemException($validator->messages()->first());
|
||||
if ($validator->errors()->first('id') === 'validation.required') {
|
||||
throw new InvalidItemException('The id field is required.');
|
||||
}
|
||||
|
||||
if ($validator->errors()->first('name') === 'validation.required') {
|
||||
throw new InvalidItemException('The name field is required.');
|
||||
}
|
||||
|
||||
if ($validator->errors()->first('quantity') === 'validation.min.numeric') {
|
||||
throw new InvalidItemException('The quantity must be at least 0.1.');
|
||||
}
|
||||
}
|
||||
|
||||
return $item;
|
||||
@@ -717,9 +706,9 @@ protected function validate($item)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function addRow($id, $item)
|
||||
protected function addItem($id, $item)
|
||||
{
|
||||
if ($this->fireEvent('adding', $item) === false) {
|
||||
if ($this->fireEvent('Adding', 'item', $item) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -729,7 +718,7 @@ protected function addRow($id, $item)
|
||||
|
||||
$this->save($cart);
|
||||
|
||||
$this->fireEvent('added', $item);
|
||||
$this->fireEvent('Added', 'item', $item);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -741,7 +730,7 @@ protected function addRow($id, $item)
|
||||
*/
|
||||
protected function save($cart)
|
||||
{
|
||||
$this->session->put($this->sessionKeyCartItems, $cart);
|
||||
$this->session->putItems($cart);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -749,7 +738,7 @@ protected function save($cart)
|
||||
*/
|
||||
protected function saveConditions($conditions)
|
||||
{
|
||||
$this->session->put($this->sessionKeyCartConditions, $conditions);
|
||||
$this->session->putConditions($conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -767,7 +756,7 @@ protected function itemHasConditions($item)
|
||||
return count($item['conditions']) > 0;
|
||||
}
|
||||
|
||||
$conditionInstance = 'Wearepixel\\Cart\\CartCondition';
|
||||
$conditionInstance = 'Joelwmale\\Cart\\CartCondition';
|
||||
|
||||
if ($item['conditions'] instanceof $conditionInstance) {
|
||||
return true;
|
||||
@@ -784,7 +773,7 @@ protected function itemHasConditions($item)
|
||||
protected function updateQuantityRelative($item, $key, $value)
|
||||
{
|
||||
if (preg_match('/\-/', $value) == 1) {
|
||||
$value = (int) str_replace('-', '', $value);
|
||||
$value = (float) str_replace('-', '', $value);
|
||||
|
||||
// we will not allowed to reduced quantity to 0, so if the given value
|
||||
// would result to item quantity of 0, we will not do it.
|
||||
@@ -792,9 +781,9 @@ protected function updateQuantityRelative($item, $key, $value)
|
||||
$item[$key] -= $value;
|
||||
}
|
||||
} elseif (preg_match('/\+/', $value) == 1) {
|
||||
$item[$key] += (int) str_replace('+', '', $value);
|
||||
$item[$key] += (float) str_replace('+', '', $value);
|
||||
} else {
|
||||
$item[$key] += (int) $value;
|
||||
$item[$key] += (float) $value;
|
||||
}
|
||||
|
||||
return $item;
|
||||
@@ -807,7 +796,7 @@ protected function updateQuantityRelative($item, $key, $value)
|
||||
*/
|
||||
protected function updateQuantityNotRelative($item, $key, $value)
|
||||
{
|
||||
$item[$key] = (int) $value;
|
||||
$item[$key] = (float) $value;
|
||||
|
||||
return $item;
|
||||
}
|
||||
@@ -820,12 +809,19 @@ public function setDecimals($decimals)
|
||||
$this->decimals = $decimals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
protected function fireEvent($name, $value = [])
|
||||
protected function fireEvent($name, $type = null, $data = null)
|
||||
{
|
||||
return $this->events->dispatch($this->getInstanceName() . '.' . $name, array_values([$value, $this]), true);
|
||||
$eventData = [
|
||||
'session_key' => $this->session->sessionKey,
|
||||
'session_driver' => $this->session->driver,
|
||||
'session_model' => $this->session->getSessionModel(),
|
||||
];
|
||||
|
||||
if ($type) {
|
||||
$eventData[$type] = $data;
|
||||
}
|
||||
|
||||
return $this->events->dispatch('LaravelCart.' . $name, array_values([$eventData, $this]), true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart;
|
||||
namespace Joelwmale\Cart;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class CartCollection extends Collection
|
||||
{
|
||||
}
|
||||
class CartCollection extends Collection {}
|
||||
|
||||
+38
-12
@@ -1,22 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart;
|
||||
namespace Joelwmale\Cart;
|
||||
|
||||
use Wearepixel\Cart\Helpers\Helpers;
|
||||
use Wearepixel\Cart\Validators\CartConditionValidator;
|
||||
use Wearepixel\Cart\Exceptions\InvalidConditionException;
|
||||
use Joelwmale\Cart\Helpers\Helpers;
|
||||
use Joelwmale\Cart\Validators\CartConditionValidator;
|
||||
use Joelwmale\Cart\Exceptions\InvalidConditionException;
|
||||
|
||||
class CartCondition
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $args;
|
||||
|
||||
/**
|
||||
* the parsed raw value of the condition
|
||||
*/
|
||||
public $parsedRawValue;
|
||||
private $parsedRawValue = 0;
|
||||
|
||||
/**
|
||||
* @param array $args (name, type, target, value)
|
||||
@@ -65,6 +62,22 @@ public function getType()
|
||||
return $this->args['type'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum value of this condition
|
||||
*/
|
||||
public function getMinimum(): int|float|null
|
||||
{
|
||||
return $this->args['minimum'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum value of this condition
|
||||
*/
|
||||
public function getMaximum(): int|float|null
|
||||
{
|
||||
return $this->args['maximum'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the additional attributes of a condition
|
||||
*
|
||||
@@ -77,14 +90,20 @@ public function getAttributes()
|
||||
|
||||
/**
|
||||
* the value of this the condition
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue()
|
||||
public function getValue(): int|float|string
|
||||
{
|
||||
return $this->args['value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of this condition
|
||||
*/
|
||||
public function setValue($value): void
|
||||
{
|
||||
$this->args['value'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the order to apply this condition. If no argument order is applied we return 0 as
|
||||
* indicator that no assignment has been made
|
||||
@@ -123,9 +142,11 @@ public function applyCondition($totalOrSubTotalOrPrice)
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCalculatedValue($totalOrSubTotalOrPrice)
|
||||
public function getCalculatedValue($totalOrSubTotalOrPrice = null): int|float
|
||||
{
|
||||
if ($totalOrSubTotalOrPrice) {
|
||||
$this->apply($totalOrSubTotalOrPrice, $this->getValue());
|
||||
}
|
||||
|
||||
return $this->parsedRawValue;
|
||||
}
|
||||
@@ -245,4 +266,9 @@ protected function validate($args)
|
||||
throw new InvalidConditionException($validator->messages()->first());
|
||||
}
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->args;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart;
|
||||
namespace Joelwmale\Cart;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart;
|
||||
namespace Joelwmale\Cart;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
@@ -35,24 +35,19 @@ public function register()
|
||||
$this->mergeConfigFrom(__DIR__ . '/../config/config.php', 'cart');
|
||||
|
||||
$this->app->singleton('cart', function ($app) {
|
||||
$storageClass = config('cart.storage');
|
||||
$eventsClass = config('cart.events');
|
||||
$config = config('cart');
|
||||
$events = $app['events'];
|
||||
|
||||
$storage = $storageClass ? new $storageClass : $app['session'];
|
||||
$events = $eventsClass ? new $eventsClass : $app['events'];
|
||||
$instanceName = 'cart';
|
||||
|
||||
// default session or cart identifier. This will be overridden when calling Cart::session($sessionKey)->add() etc..
|
||||
// like when adding a cart for a specific user name. Session Key can be string or maybe a unique identifier to bind a cart
|
||||
// to a specific user, this can also be a user ID
|
||||
$session_key = '4yTlTDKu3oJOfzD';
|
||||
$storage = $config['driver'] === 'database'
|
||||
? new $config['storage']['database']['model']
|
||||
: $app['session'];
|
||||
|
||||
return new Cart(
|
||||
$storage,
|
||||
$events,
|
||||
$instanceName,
|
||||
$session_key,
|
||||
config('cart')
|
||||
'cart',
|
||||
session()->getId(),
|
||||
$config
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace Joelwmale\Cart;
|
||||
|
||||
class CartSession
|
||||
{
|
||||
private $customStorage;
|
||||
|
||||
public $sessionKey;
|
||||
public $driver;
|
||||
|
||||
private $session;
|
||||
|
||||
private $sessionId = null;
|
||||
private $itemsKey = null;
|
||||
private $conditionsKey = null;
|
||||
|
||||
public function __construct($session, $sessionKey, $config)
|
||||
{
|
||||
$this->sessionKey = $sessionKey;
|
||||
$this->driver = $config['driver'];
|
||||
|
||||
if ($this->driver === 'session') {
|
||||
$this->customStorage = false;
|
||||
$this->session = $session;
|
||||
$this->itemsKey = $this->sessionKey . '_cart_items';
|
||||
$this->conditionsKey = $this->sessionKey . '_cart_conditions';
|
||||
} elseif ($this->driver === 'database') {
|
||||
$this->customStorage = true;
|
||||
|
||||
$this->sessionId = $config['storage']['database']['id'];
|
||||
$this->itemsKey = $config['storage']['database']['items'];
|
||||
$this->conditionsKey = $config['storage']['database']['conditions'];
|
||||
|
||||
$this->session = $session->firstOrNew([$this->sessionId => $this->sessionKey]);
|
||||
|
||||
$this->session[$this->itemsKey] = $this->session[$this->itemsKey] ?? [];
|
||||
$this->session[$this->conditionsKey] = $this->session[$this->conditionsKey] ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
public function isInternalSession($session)
|
||||
{
|
||||
return in_array(is_object($session) ? get_class($session) : $session, [
|
||||
'Illuminate\Session\SessionManager',
|
||||
'Joelwmale\Cart\Tests\Helpers\SessionMock',
|
||||
]);
|
||||
}
|
||||
|
||||
public function has($key)
|
||||
{
|
||||
return $this->session->has($key) ?? $this->session;
|
||||
}
|
||||
|
||||
public function getItems()
|
||||
{
|
||||
return $this->driver == 'session' ? $this->session->get($this->itemsKey) : $this->session[$this->itemsKey];
|
||||
}
|
||||
|
||||
public function getConditions()
|
||||
{
|
||||
return $this->driver == 'session' ? $this->session->get($this->conditionsKey) : $this->session[$this->conditionsKey];
|
||||
}
|
||||
|
||||
public function putItems($value)
|
||||
{
|
||||
if ($this->driver == 'session') {
|
||||
return $this->session->put($this->itemsKey, $value);
|
||||
}
|
||||
|
||||
// convert any conditions to arrays
|
||||
$value = is_array($value) ? $value : $value->toArray();
|
||||
|
||||
foreach ($value as $key => $item) {
|
||||
if ($item['conditions']) {
|
||||
if (is_array($item['conditions'])) {
|
||||
$value[$key]['conditions'] = collect($item['conditions'])->map(function ($condition) {
|
||||
return $condition->toArray();
|
||||
});
|
||||
} else {
|
||||
$value[$key]['conditions'] = $item['conditions']->toArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->session[$this->itemsKey] = $value;
|
||||
$this->session->save();
|
||||
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
public function putConditions($value)
|
||||
{
|
||||
if ($this->driver == 'session') {
|
||||
return $this->session->put($this->conditionsKey, $value);
|
||||
}
|
||||
|
||||
if (! empty($value)) {
|
||||
$value = $value->mapWithKeys(function ($condition) {
|
||||
return [$condition->getName() => $condition->toArray()];
|
||||
});
|
||||
}
|
||||
|
||||
$this->session[$this->conditionsKey] = $value;
|
||||
$this->session->save();
|
||||
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
public function clearItems()
|
||||
{
|
||||
if ($this->driver == 'session') {
|
||||
$this->session->forget($this->itemsKey);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->session[$this->itemsKey] = [];
|
||||
|
||||
return $this->session->save();
|
||||
}
|
||||
|
||||
public function clear()
|
||||
{
|
||||
if ($this->driver == 'session') {
|
||||
$this->session->forget($this->itemsKey);
|
||||
$this->session->forget($this->conditionsKey);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$deleted = $this->session->delete();
|
||||
|
||||
$this->session = [
|
||||
$this->itemsKey => [],
|
||||
$this->conditionsKey => [],
|
||||
];
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
public function getSessionModel()
|
||||
{
|
||||
return $this->session;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart\Exceptions;
|
||||
namespace Joelwmale\Cart\Exceptions;
|
||||
|
||||
class InvalidConditionException extends \Exception {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart\Exceptions;
|
||||
namespace Joelwmale\Cart\Exceptions;
|
||||
|
||||
class InvalidItemException extends \Exception {}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart\Exceptions;
|
||||
namespace Joelwmale\Cart\Exceptions;
|
||||
|
||||
class UnknownModelException extends \Exception
|
||||
{
|
||||
}
|
||||
class UnknownModelException extends \Exception {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart\Facades;
|
||||
namespace Joelwmale\Cart\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
|
||||
+26
-16
@@ -1,29 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart\Helpers;
|
||||
namespace Joelwmale\Cart\Helpers;
|
||||
|
||||
class Helpers
|
||||
{
|
||||
/**
|
||||
* normalize price
|
||||
*
|
||||
* @return float
|
||||
* Normalize prices
|
||||
*/
|
||||
public static function normalizePrice($price)
|
||||
public static function normalizePrice($price): ?float
|
||||
{
|
||||
return (is_string($price)) ? floatval($price) : $price;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if array is multi dimensional array
|
||||
* This will only check the first element of the array if it is still an array
|
||||
* to decide that it is a multi dimensional, if you want to check the array strictly
|
||||
* with all on its element, flag the second argument as true
|
||||
*
|
||||
* @param bool $recursive
|
||||
* @return bool
|
||||
* Get the rounding mode
|
||||
*/
|
||||
public static function isMultiArray($array, $recursive = false)
|
||||
public static function roundMode($config): int
|
||||
{
|
||||
if (isset($config['round_mode']) && $config['round_mode'] == 'up') {
|
||||
return PHP_ROUND_HALF_UP;
|
||||
}
|
||||
|
||||
return PHP_ROUND_HALF_DOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if array is multi dimensional array
|
||||
* This will only check if the first element of the array is an array
|
||||
*/
|
||||
public static function isMultiArray(array $array, bool $recursive = false): bool
|
||||
{
|
||||
if ($recursive) {
|
||||
return (count($array) == count($array, COUNT_RECURSIVE)) ? false : true;
|
||||
@@ -35,8 +40,9 @@ public static function isMultiArray($array, $recursive = false)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,10 +62,14 @@ public static function issetAndHasValueOrAssignDefault(&$var, $default = false)
|
||||
|
||||
public static function formatValue($value, $formatNumber, $config)
|
||||
{
|
||||
if (! $value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($formatNumber || $config['format_numbers']) {
|
||||
return floatval(number_format($value, $config['decimals'], $config['dec_point'], $config['thousands_sep']));
|
||||
return round($value, $config['decimals'], self::roundMode($config));
|
||||
} else {
|
||||
return $value;
|
||||
return floatval($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart;
|
||||
namespace Joelwmale\Cart;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
|
||||
+37
-7
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart;
|
||||
namespace Joelwmale\Cart;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Wearepixel\Cart\Helpers\Helpers;
|
||||
use Joelwmale\Cart\Helpers\Helpers;
|
||||
|
||||
class ItemCollection extends Collection
|
||||
{
|
||||
@@ -72,7 +72,7 @@ public function hasConditions()
|
||||
if (is_array($this['conditions'])) {
|
||||
return count($this['conditions']) > 0;
|
||||
}
|
||||
$conditionInstance = 'Wearepixel\\Cart\\CartCondition';
|
||||
$conditionInstance = 'Joelwmale\\Cart\\CartCondition';
|
||||
if ($this['conditions'] instanceof $conditionInstance) {
|
||||
return true;
|
||||
}
|
||||
@@ -91,7 +91,37 @@ public function getConditions()
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this['conditions'];
|
||||
$conditionsArray = [];
|
||||
|
||||
$conditions = $this['conditions'];
|
||||
|
||||
// check if we're already an array of CartConditions
|
||||
foreach ($conditions as $key => $condition) {
|
||||
if ($condition instanceof CartCondition) {
|
||||
return $conditions;
|
||||
}
|
||||
}
|
||||
|
||||
$hasSubArray = false;
|
||||
|
||||
foreach ($conditions as $key => $condition) {
|
||||
if (is_array($condition) && ! $condition instanceof CartCondition) {
|
||||
$hasSubArray = true;
|
||||
$conditionsArray[] = new CartCondition($condition);
|
||||
} elseif ($condition instanceof CartCondition) {
|
||||
$conditionsArray[] = $condition;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $hasSubArray) {
|
||||
if ($conditions instanceof CartCondition) {
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
$conditionsArray[] = new CartCondition($conditions);
|
||||
}
|
||||
|
||||
return $conditionsArray;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,14 +138,14 @@ public function getPriceWithConditions($formatted = true)
|
||||
$processed = 0;
|
||||
|
||||
if ($this->hasConditions()) {
|
||||
if (is_array($this->conditions)) {
|
||||
foreach ($this->conditions as $condition) {
|
||||
if (is_array($this->getConditions())) {
|
||||
foreach ($this->getConditions() as $condition) {
|
||||
($processed > 0) ? $toBeCalculated = $newPrice : $toBeCalculated = $originalPrice;
|
||||
$newPrice = $condition->applyCondition($toBeCalculated);
|
||||
$processed++;
|
||||
}
|
||||
} else {
|
||||
$newPrice = $this['conditions']->applyCondition($originalPrice);
|
||||
$newPrice = $this->getConditions()->applyCondition($originalPrice);
|
||||
}
|
||||
|
||||
return Helpers::formatValue($newPrice, $formatted, $this->config);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart\Validators;
|
||||
namespace Joelwmale\Cart\Validators;
|
||||
|
||||
class CartConditionValidator extends Validator {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart\Validators;
|
||||
namespace Joelwmale\Cart\Validators;
|
||||
|
||||
class CartItemValidator extends Validator {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart\Validators;
|
||||
namespace Joelwmale\Cart\Validators;
|
||||
|
||||
use Illuminate\Validation\Factory;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'format_numbers' => true,
|
||||
'decimals' => 2,
|
||||
'dec_point' => '.',
|
||||
'driver' => 'session',
|
||||
];
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'format_numbers' => true,
|
||||
'decimals' => 2,
|
||||
'round_mode' => 'up',
|
||||
'driver' => 'database',
|
||||
'storage' => [
|
||||
'session',
|
||||
'database' => [
|
||||
'model' => \Joelwmale\Cart\Tests\Helpers\MockCartModel::class,
|
||||
'id' => 'session_id',
|
||||
'items' => 'items',
|
||||
'conditions' => 'conditions',
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'format_numbers' => false,
|
||||
'format_numbers' => true,
|
||||
'decimals' => 2,
|
||||
'dec_point' => '.',
|
||||
'thousands_sep' => ',',
|
||||
'round_mode' => 'up',
|
||||
'driver' => 'session',
|
||||
];
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
'format_numbers' => false,
|
||||
'decimals' => 3,
|
||||
'dec_point' => ',',
|
||||
'thousands_sep' => '.',
|
||||
'driver' => 'session',
|
||||
];
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Joelwmale\Cart\Tests\Helpers;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class MockCartModel extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'session_id',
|
||||
'items',
|
||||
'conditions',
|
||||
];
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
protected $casts = [
|
||||
'items' => 'array',
|
||||
'conditions' => 'array',
|
||||
];
|
||||
|
||||
protected $table = 'carts';
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart\Tests\Helpers;
|
||||
namespace Joelwmale\Cart\Tests\Helpers;
|
||||
|
||||
use Illuminate\Contracts\Database\ModelIdentifier;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Wearepixel\Cart\Tests\Helpers;
|
||||
namespace Joelwmale\Cart\Tests\Helpers;
|
||||
|
||||
class SessionMock
|
||||
{
|
||||
@@ -20,4 +20,9 @@ public function put($key, $value)
|
||||
{
|
||||
$this->session[$key] = $value;
|
||||
}
|
||||
|
||||
public function forget($key)
|
||||
{
|
||||
unset($this->session[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-66
@@ -1,69 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Test Case
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The closure you provide to your test functions is always bound to a specific PHPUnit test
|
||||
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
|
||||
| need to change it using the "pest()" function to bind a different classes or traits.
|
||||
|
|
||||
*/
|
||||
use Tests\TestCase;
|
||||
|
||||
// pest()->extend(Tests\TestCase::class)->in('Feature');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Expectations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When you're writing tests, you often need to check that values meet certain conditions. The
|
||||
| "expect()" function gives you access to a set of "expectations" methods that you can use
|
||||
| to assert different things. Of course, you may extend the Expectation API at any time.
|
||||
|
|
||||
*/
|
||||
|
||||
expect()->extend('toBeOne', function () {
|
||||
return $this->toBe(1);
|
||||
});
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Functions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
|
||||
| project that you don't want to repeat in every file. Here you can also expose helpers as
|
||||
| global functions to help you to reduce the number of lines of code in your test files.
|
||||
|
|
||||
*/
|
||||
|
||||
function fillCart()
|
||||
{
|
||||
$items = [
|
||||
[
|
||||
'id' => 456,
|
||||
'name' => 'Sample Item 1',
|
||||
'price' => 67.99,
|
||||
'quantity' => 1,
|
||||
'attributes' => [],
|
||||
],
|
||||
[
|
||||
'id' => 568,
|
||||
'name' => 'Sample Item 2',
|
||||
'price' => 69.25,
|
||||
'quantity' => 1,
|
||||
'attributes' => [],
|
||||
],
|
||||
[
|
||||
'id' => 856,
|
||||
'name' => 'Sample Item 3',
|
||||
'price' => 50.25,
|
||||
'quantity' => 1,
|
||||
'attributes' => [],
|
||||
],
|
||||
];
|
||||
|
||||
$this->cart->add($items);
|
||||
}
|
||||
uses(TestCase::class)->in(__DIR__);
|
||||
|
||||
+44
-2
@@ -1,10 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Illuminate\Events\Dispatcher;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Capsule\Manager as DB;
|
||||
use PHPUnit\Framework\TestCase as BaseTestCase;
|
||||
|
||||
abstract class TestCase extends BaseTestCase
|
||||
class TestCase extends BaseTestCase
|
||||
{
|
||||
//
|
||||
protected DB $db;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Create a Laravel container
|
||||
$container = Container::getInstance();
|
||||
$dispatcher = new Dispatcher;
|
||||
|
||||
// Setup Capsule (Eloquent ORM)
|
||||
$this->db = new DB($container);
|
||||
$this->db->addConnection([
|
||||
'driver' => 'sqlite',
|
||||
'database' => ':memory:',
|
||||
'prefix' => '',
|
||||
]);
|
||||
$this->db->setAsGlobal();
|
||||
$this->db->bootEloquent();
|
||||
$this->db->getConnection()->setEventDispatcher($dispatcher);
|
||||
|
||||
// Run migrations (optional, for testing models)
|
||||
$this->migrateDatabase();
|
||||
}
|
||||
|
||||
protected function migrateDatabase()
|
||||
{
|
||||
$schema = $this->db->schema();
|
||||
|
||||
$schema->create('carts', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('session_id');
|
||||
$table->text('items');
|
||||
$table->text('conditions');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+1697
-703
File diff suppressed because it is too large
Load Diff
+233
-73
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Wearepixel\Cart\Cart;
|
||||
use Wearepixel\Cart\Tests\Helpers\MockProduct;
|
||||
use Wearepixel\Cart\Tests\Helpers\SessionMock;
|
||||
use Joelwmale\Cart\Cart;
|
||||
use Joelwmale\Cart\Tests\Helpers\MockProduct;
|
||||
use Joelwmale\Cart\Tests\Helpers\SessionMock;
|
||||
|
||||
beforeEach(function () {
|
||||
$events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
|
||||
@@ -21,25 +21,63 @@
|
||||
Mockery::close();
|
||||
});
|
||||
|
||||
test('cart can add item', function () {
|
||||
$this->cart->add(455, 'Sample Item', 100.99, 2, []);
|
||||
describe('cart', function () {
|
||||
test('can add an item', function () {
|
||||
$this->cart->add(1, 'Sample Item', 100.99, 2, []);
|
||||
|
||||
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
|
||||
expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1');
|
||||
expect($this->cart->getContent()->first()['id'])->toEqual(455, 'Item added has ID of 455 so first content ID should be 455');
|
||||
expect($this->cart->getContent()->first()['id'])->toEqual(1, 'Item added has ID of 1 so first content ID should be 1');
|
||||
expect($this->cart->getContent()->first()['price'])->toEqual(100.99, 'Item added has price of 100.99 so first content price should be 100.99');
|
||||
});
|
||||
});
|
||||
|
||||
test('cart can add item with no price', function () {
|
||||
test('can add an item in cents', function () {
|
||||
$this->cart->add(1, 'Sample Item', 10099, 2, []);
|
||||
|
||||
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
|
||||
expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1');
|
||||
expect($this->cart->getContent()->first()['id'])->toEqual(1, 'Item added has ID of 1 so first content ID should be 1');
|
||||
expect($this->cart->getContent()->first()['price'])->toEqual(10099, 'Item added has price of 100.99 so first content price should be 100.99');
|
||||
});
|
||||
|
||||
test('can add an item with no price', function () {
|
||||
$this->cart->add(455, 'Sample Item', 0, 2, []);
|
||||
|
||||
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
|
||||
expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1');
|
||||
expect($this->cart->getContent()->first()['id'])->toEqual(455, 'Item added has ID of 455 so first content ID should be 455');
|
||||
expect($this->cart->getTotal())->toEqual(0, 'Total should be 0');
|
||||
});
|
||||
});
|
||||
|
||||
test('cart can add items as array', function () {
|
||||
test('can add an item an array with no price', function () {
|
||||
$this->cart->add([
|
||||
'id' => 455,
|
||||
'name' => 'Sample Item',
|
||||
'quantity' => 2,
|
||||
]);
|
||||
|
||||
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
|
||||
expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1');
|
||||
expect($this->cart->getContent()->first()['id'])->toEqual(455, 'Item added has ID of 455 so first content ID should be 455');
|
||||
expect($this->cart->getTotal())->toEqual(0, 'Total should be 0');
|
||||
});
|
||||
|
||||
test('can add an item without attributes', function () {
|
||||
$item = [
|
||||
'id' => 1,
|
||||
'name' => 'Pocket Shorts',
|
||||
'price' => 67.99,
|
||||
'quantity' => 2,
|
||||
];
|
||||
|
||||
$this->cart->add($item);
|
||||
|
||||
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
|
||||
expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1');
|
||||
expect($this->cart->getTotal())->toEqual(135.98, 'Cart total should be 135.98');
|
||||
});
|
||||
|
||||
test('can add items as array', function () {
|
||||
$item = [
|
||||
'id' => 456,
|
||||
'name' => 'Sample Item',
|
||||
@@ -54,29 +92,29 @@
|
||||
expect($this->cart->getContent()->count())->toEqual(1, 'Cart should have 1 item on it');
|
||||
expect($this->cart->getContent()->first()['id'])->toEqual(456, 'The first content must have ID of 456');
|
||||
expect($this->cart->getContent()->first()['name'])->toEqual('Sample Item', 'The first content must have name of "Sample Item"');
|
||||
});
|
||||
});
|
||||
|
||||
test('cart can add items with multidimensional array', function () {
|
||||
test('can add multiple items with an array', function () {
|
||||
$items = [
|
||||
[
|
||||
'id' => 456,
|
||||
'name' => 'Sample Item 1',
|
||||
'price' => 67.99,
|
||||
'quantity' => 4,
|
||||
'id' => 1,
|
||||
'name' => 'Half Button Open Collar',
|
||||
'price' => 71.99,
|
||||
'quantity' => 1,
|
||||
'attributes' => [],
|
||||
],
|
||||
[
|
||||
'id' => 568,
|
||||
'name' => 'Sample Item 2',
|
||||
'price' => 69.25,
|
||||
'quantity' => 4,
|
||||
'id' => 2,
|
||||
'name' => 'Oli Crew Neck',
|
||||
'price' => 59.99,
|
||||
'quantity' => 1,
|
||||
'attributes' => [],
|
||||
],
|
||||
[
|
||||
'id' => 856,
|
||||
'name' => 'Sample Item 3',
|
||||
'price' => 50.25,
|
||||
'quantity' => 4,
|
||||
'id' => 3,
|
||||
'name' => 'Denim Shorts',
|
||||
'price' => 69.99,
|
||||
'quantity' => 3,
|
||||
'attributes' => [],
|
||||
],
|
||||
];
|
||||
@@ -85,25 +123,20 @@
|
||||
|
||||
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
|
||||
expect($this->cart->getContent()->toArray())->toHaveCount(3, 'Cart should have 3 items');
|
||||
});
|
||||
expect($this->cart->getTotal())->toEqual(341.95, 'Cart should have a total of 341.95');
|
||||
});
|
||||
|
||||
test('cart can add item without attributes', function () {
|
||||
test('cart item prices should be normalized when added to cart', function () {
|
||||
// add a price in a string format should be converted to float
|
||||
$this->cart->add(1, 'Book of Languages Item', '100.99', 2, []);
|
||||
|
||||
expect($this->cart->getContent()->first()['price'])->toBeFloat('Cart price should be a float');
|
||||
});
|
||||
|
||||
test('can update a cart item with new attributes and it should be still instance of item attribute collection', function () {
|
||||
$item = [
|
||||
'id' => 456,
|
||||
'name' => 'Sample Item 1',
|
||||
'price' => 67.99,
|
||||
'quantity' => 4,
|
||||
];
|
||||
|
||||
$this->cart->add($item);
|
||||
|
||||
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
|
||||
});
|
||||
|
||||
test('cart update with attribute then attributes should be still instance of item attribute collection', function () {
|
||||
$item = [
|
||||
'id' => 456,
|
||||
'name' => 'Sample Item 1',
|
||||
'id' => 1,
|
||||
'name' => 'Leather Shows',
|
||||
'price' => 67.99,
|
||||
'quantity' => 4,
|
||||
'attributes' => [
|
||||
@@ -111,13 +144,12 @@
|
||||
'color' => 'red',
|
||||
],
|
||||
];
|
||||
|
||||
$this->cart->add($item);
|
||||
|
||||
// lets get the attribute and prove first its an instance of
|
||||
// ItemAttributeCollection
|
||||
$item = $this->cart->get(456);
|
||||
$item = $this->cart->get(1);
|
||||
|
||||
expect($item->attributes)->toBeInstanceOf('Wearepixel\Cart\ItemAttributeCollection');
|
||||
expect($item->attributes)->toBeInstanceOf('Joelwmale\\Cart\\ItemAttributeCollection');
|
||||
|
||||
// now lets update the item with its new attributes
|
||||
// when we get that item from cart, it should still be an instance of ItemAttributeCollection
|
||||
@@ -127,9 +159,161 @@
|
||||
'color' => 'red',
|
||||
],
|
||||
];
|
||||
$this->cart->update(456, $updatedItem);
|
||||
|
||||
expect($item->attributes)->toBeInstanceOf('Wearepixel\Cart\ItemAttributeCollection');
|
||||
$this->cart->update(1, $updatedItem);
|
||||
|
||||
expect($item->attributes)->toBeInstanceOf('Joelwmale\\Cart\\ItemAttributeCollection');
|
||||
});
|
||||
|
||||
test('item orders are preserved by the order they are added', function () {
|
||||
$items = [
|
||||
[
|
||||
'id' => 50,
|
||||
'name' => 'Leather Shows',
|
||||
'price' => 67.99,
|
||||
'quantity' => 4,
|
||||
'attributes' => [
|
||||
'product_id' => '145',
|
||||
'color' => 'red',
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'name' => 'Oli Crew Neck',
|
||||
'price' => 59.99,
|
||||
'quantity' => 1,
|
||||
'attributes' => [],
|
||||
],
|
||||
];
|
||||
|
||||
$this->cart->add($items);
|
||||
|
||||
$items = $this->cart->getContent();
|
||||
|
||||
expect($items->toArray())->toHaveCount(2, 'Cart should have 2 items');
|
||||
expect($items->first()->id)->toEqual(50, 'First item should have ID of 1');
|
||||
expect($items->last()->id)->toEqual(2, 'Last item should have ID of 2');
|
||||
});
|
||||
|
||||
test('item orders are preserved by the order they are added even when items are updated', function () {
|
||||
$items = [
|
||||
[
|
||||
'id' => 50,
|
||||
'name' => 'Leather Shows',
|
||||
'price' => 67.99,
|
||||
'quantity' => 4,
|
||||
'attributes' => [
|
||||
'product_id' => '145',
|
||||
'color' => 'red',
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'name' => 'Oli Crew Neck',
|
||||
'price' => 59.99,
|
||||
'quantity' => 1,
|
||||
'attributes' => [],
|
||||
],
|
||||
];
|
||||
|
||||
$this->cart->add($items);
|
||||
|
||||
$this->cart->update(50, ['name' => 'Updated Name']);
|
||||
|
||||
$items = $this->cart->getContent();
|
||||
|
||||
expect($items->toArray())->toHaveCount(2, 'Cart should have 2 items');
|
||||
expect($items->first()->id)->toEqual(50, 'First item should have ID of 1');
|
||||
expect($items->last()->id)->toEqual(2, 'Last item should have ID of 2');
|
||||
});
|
||||
|
||||
test('can update existing items', function () {
|
||||
$items = [
|
||||
[
|
||||
'id' => 1,
|
||||
'name' => 'Magic The Gathering Card Pack',
|
||||
'price' => 12.99,
|
||||
'quantity' => 3,
|
||||
'attributes' => [],
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'name' => 'Magic The Gathering Card Case',
|
||||
'price' => 39.99,
|
||||
'quantity' => 1,
|
||||
'attributes' => [],
|
||||
],
|
||||
];
|
||||
|
||||
$this->cart->add($items);
|
||||
|
||||
$item = $this->cart->get(1);
|
||||
|
||||
expect($item['name'])->toEqual('Magic The Gathering Card Pack', 'Item name should be "Magic The Gathering Card Pack"');
|
||||
expect($item['price'])->toEqual(12.99, 'Item price should be "12.99"');
|
||||
expect($item['quantity'])->toEqual(3, 'Item quantity should be 3');
|
||||
|
||||
// when cart's item quantity is updated, the subtotal should be updated as well
|
||||
$this->cart->update(1, [
|
||||
'name' => 'Magic The Gathering Card Packs',
|
||||
'quantity' => 2,
|
||||
'price' => 10.20,
|
||||
]);
|
||||
|
||||
$item = $this->cart->get(1);
|
||||
|
||||
expect($item['name'])->toEqual('Magic The Gathering Card Packs', 'Item name should be "Magic The Gathering Card Packs"');
|
||||
expect($item['price'])->toEqual(10.20, 'Item price should be 10.20');
|
||||
expect($item['quantity'])->toEqual(5, 'Item quantity should be 2');
|
||||
});
|
||||
|
||||
test('can update existing item quanties with decimals', function () {
|
||||
$items = [
|
||||
'id' => 1,
|
||||
'name' => 'Fertilizer',
|
||||
'price' => 30,
|
||||
'quantity' => 7.8,
|
||||
'attributes' => [
|
||||
'unit' => 'kilogram',
|
||||
],
|
||||
];
|
||||
|
||||
$this->cart->add($items);
|
||||
|
||||
$item = $this->cart->get(1);
|
||||
|
||||
expect($item['quantity'])->toEqual(7.8, 'Item quantity should be 7.8');
|
||||
|
||||
// when cart's item quantity is updated, the subtotal should be updated as well
|
||||
$this->cart->update(1, [
|
||||
'quantity' => [
|
||||
'relative' => true,
|
||||
'value' => 2.1,
|
||||
],
|
||||
]);
|
||||
|
||||
$item = $this->cart->get(1);
|
||||
|
||||
expect($item['quantity'])->toEqual(9.9, 'Item quantity should be 9.9');
|
||||
});
|
||||
|
||||
test('should throw an exception when no quantity is provided', function () {
|
||||
$this->expectException('Joelwmale\Cart\Exceptions\InvalidItemException');
|
||||
$this->expectExceptionMessage('The quantity must be at least 0.1.');
|
||||
$this->cart->add(455, 'Sample Item', 100.99, 0, []);
|
||||
});
|
||||
|
||||
test('should throw an exception when no id is provided', function () {
|
||||
$this->expectException('Joelwmale\Cart\Exceptions\InvalidItemException');
|
||||
$this->expectExceptionMessage('The id field is required.');
|
||||
$this->cart->add('', 'Sample Item', 100.99, 2, []);
|
||||
});
|
||||
|
||||
test('should throw an exception when no name is provided', function () {
|
||||
$this->expectException('Joelwmale\Cart\Exceptions\InvalidItemException');
|
||||
$this->expectExceptionMessage('The name field is required.');
|
||||
$this->cart->add(523, '', 100.99, 2, []);
|
||||
});
|
||||
});
|
||||
|
||||
test('cart items attributes', function () {
|
||||
@@ -222,13 +406,6 @@
|
||||
expect($item['quantity'])->toEqual(5, 'Item quantity should be 5');
|
||||
});
|
||||
|
||||
test('item price should be normalized when added to cart', function () {
|
||||
// add a price in a string format should be converted to float
|
||||
$this->cart->add(455, 'Sample Item', '100.99', 2, []);
|
||||
|
||||
expect($this->cart->getContent()->first()['price'])->toBeFloat('Cart price should be a float');
|
||||
});
|
||||
|
||||
test('it removes an item on cart by item id', function () {
|
||||
$items = [
|
||||
[
|
||||
@@ -331,8 +508,6 @@
|
||||
});
|
||||
|
||||
test('sub total when item quantity is updated by reduced', function () {
|
||||
// $this->cart->setConfig(['format_numbers' => true, 'decimals' => 2, 'dec_point' => '.', 'thousands_sep' => ',']);
|
||||
|
||||
$items = [
|
||||
[
|
||||
'id' => 456,
|
||||
@@ -398,21 +573,6 @@
|
||||
expect($item['quantity'])->toEqual(3, 'Item quantity of with item ID of 456 should now be reduced to 2');
|
||||
});
|
||||
|
||||
test('should throw exception when provided invalid values scenario one', function () {
|
||||
$this->expectException('Wearepixel\Cart\Exceptions\InvalidItemException');
|
||||
$this->cart->add(455, 'Sample Item', 100.99, 0, []);
|
||||
});
|
||||
|
||||
test('should throw exception when provided invalid values scenario two', function () {
|
||||
$this->expectException('Wearepixel\Cart\Exceptions\InvalidItemException');
|
||||
$this->cart->add('', 'Sample Item', 100.99, 2, []);
|
||||
});
|
||||
|
||||
test('should throw exception when provided invalid values scenario three', function () {
|
||||
$this->expectException('Wearepixel\Cart\Exceptions\InvalidItemException');
|
||||
$this->cart->add(523, '', 100.99, 2, []);
|
||||
});
|
||||
|
||||
test('clearing cart', function () {
|
||||
$items = [
|
||||
[
|
||||
@@ -486,7 +646,7 @@
|
||||
expect($this->cart->getContent()->count())->toEqual(1, 'Cart should have 1 item on it');
|
||||
expect($this->cart->getContent()->first()['id'])->toEqual(456, 'The first content must have ID of 456');
|
||||
expect($this->cart->getContent()->first()['name'])->toEqual('Sample Item', 'The first content must have name of "Sample Item"');
|
||||
expect($addedItem->model)->toBeInstanceOf('Wearepixel\Cart\Tests\Helpers\MockProduct');
|
||||
expect($addedItem->model)->toBeInstanceOf('Joelwmale\Cart\Tests\Helpers\MockProduct');
|
||||
});
|
||||
|
||||
test('cart can add items with multidimensional array with associated model', function () {
|
||||
@@ -521,7 +681,7 @@
|
||||
|
||||
$content = $this->cart->getContent();
|
||||
foreach ($content as $item) {
|
||||
expect($item->model)->toBeInstanceOf('Wearepixel\Cart\Tests\Helpers\MockProduct');
|
||||
expect($item->model)->toBeInstanceOf('Joelwmale\Cart\Tests\Helpers\MockProduct');
|
||||
}
|
||||
|
||||
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Wearepixel\Cart\Cart;
|
||||
use Wearepixel\Cart\Tests\Helpers\SessionMock;
|
||||
use Joelwmale\Cart\Cart;
|
||||
use Joelwmale\Cart\Tests\Helpers\SessionMock;
|
||||
|
||||
beforeEach(function () {});
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
Mockery::close();
|
||||
});
|
||||
|
||||
test('event cart created', function () {
|
||||
test('event cart Created', function () {
|
||||
$events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
|
||||
$events->shouldReceive('dispatch')->once()->with('cart.created', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true);
|
||||
|
||||
$cart = new Cart(
|
||||
new SessionMock,
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
test('event cart adding', function () {
|
||||
$events = Mockery::mock('Illuminate\Events\Dispatcher');
|
||||
$events->shouldReceive('dispatch')->once()->with('cart.created', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('cart.adding', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('cart.added', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Adding', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Added', Mockery::type('array'), true);
|
||||
|
||||
$cart = new Cart(
|
||||
new SessionMock,
|
||||
@@ -45,9 +45,9 @@
|
||||
|
||||
test('event cart adding multiple times', function () {
|
||||
$events = Mockery::mock('Illuminate\Events\Dispatcher');
|
||||
$events->shouldReceive('dispatch')->once()->with('cart.created', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(2)->with('cart.adding', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(2)->with('cart.added', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(2)->with('LaravelCart.Adding', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(2)->with('LaravelCart.Added', Mockery::type('array'), true);
|
||||
|
||||
$cart = new Cart(
|
||||
new SessionMock,
|
||||
@@ -65,9 +65,9 @@
|
||||
|
||||
test('event cart adding multiple times scenario two', function () {
|
||||
$events = Mockery::mock('Illuminate\Events\Dispatcher');
|
||||
$events->shouldReceive('dispatch')->once()->with('cart.created', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(3)->with('cart.adding', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(3)->with('cart.added', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Adding', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Added', Mockery::type('array'), true);
|
||||
|
||||
$items = [
|
||||
[
|
||||
@@ -108,11 +108,11 @@
|
||||
|
||||
test('event cart remove item', function () {
|
||||
$events = Mockery::mock('Illuminate\Events\Dispatcher');
|
||||
$events->shouldReceive('dispatch')->once()->with('cart.created', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(3)->with('cart.adding', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(3)->with('cart.added', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(1)->with('cart.removing', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(1)->with('cart.removed', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Adding', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Added', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(1)->with('LaravelCart.Removing', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(1)->with('LaravelCart.Removed', Mockery::type('array'), true);
|
||||
|
||||
$items = [
|
||||
[
|
||||
@@ -155,11 +155,11 @@
|
||||
|
||||
test('event cart clear', function () {
|
||||
$events = Mockery::mock('Illuminate\Events\Dispatcher');
|
||||
$events->shouldReceive('dispatch')->once()->with('cart.created', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(3)->with('cart.adding', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(3)->with('cart.added', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('cart.clearing', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('cart.cleared', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Adding', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Added', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Clearing', Mockery::type('array'), true);
|
||||
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Cleared', Mockery::type('array'), true);
|
||||
|
||||
$items = [
|
||||
[
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Wearepixel\Cart\Cart;
|
||||
use Wearepixel\Cart\Tests\Helpers\SessionMock;
|
||||
use Joelwmale\Cart\Cart;
|
||||
use Joelwmale\Cart\Tests\Helpers\SessionMock;
|
||||
|
||||
beforeEach(function () {
|
||||
$events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
use Joelwmale\Cart\Cart;
|
||||
use Joelwmale\Cart\CartCondition;
|
||||
use Joelwmale\Cart\Tests\Helpers\MockCartModel;
|
||||
|
||||
beforeEach(function () {
|
||||
$events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
|
||||
$events->shouldReceive('dispatch');
|
||||
|
||||
$storage = new MockCartModel;
|
||||
|
||||
$this->cart = new Cart(
|
||||
$storage,
|
||||
$events,
|
||||
'cart',
|
||||
'SAMPLESESSIONKEY',
|
||||
require (__DIR__ . '/../Helpers/ConfigDatabaseMock.php')
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
Mockery::close();
|
||||
});
|
||||
|
||||
describe('database cart', function () {
|
||||
test('can add an item', function () {
|
||||
$this->cart->add(1, 'Sample Item', 100.99, 2, []);
|
||||
|
||||
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
|
||||
expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1');
|
||||
expect($this->cart->getContent()->first()['id'])->toEqual(1, 'Item added has ID of 1 so first content ID should be 1');
|
||||
expect($this->cart->getContent()->first()['price'])->toEqual(100.99, 'Item added has price of 100.99 so first content price should be 100.99');
|
||||
|
||||
expect(MockCartModel::all()->count())->toEqual(1, 'The carts database table should have 1 row');
|
||||
});
|
||||
|
||||
test('can add and remove an item', function () {
|
||||
$this->cart->add(1, 'Sample Item', 100.99, 2, []);
|
||||
|
||||
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
|
||||
expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1');
|
||||
expect($this->cart->getContent()->first()['id'])->toEqual(1, 'Item added has ID of 1 so first content ID should be 1');
|
||||
expect($this->cart->getContent()->first()['price'])->toEqual(100.99, 'Item added has price of 100.99 so first content price should be 100.99');
|
||||
|
||||
expect(MockCartModel::all()->count())->toEqual(1, 'The carts database table should have 1 row');
|
||||
|
||||
$this->cart->remove(1);
|
||||
|
||||
$cartModel = MockCartModel::first();
|
||||
|
||||
expect($this->cart->isEmpty())->toBeTrue('Cart should be empty');
|
||||
expect($this->cart->getContent()->count())->toEqual(0, 'Cart content should be 0');
|
||||
expect($cartModel->items)->toEqual([], 'The carts database table should have 0 row');
|
||||
});
|
||||
|
||||
test('can add an item with an item level condition', function () {
|
||||
$saleCondition = new CartCondition([
|
||||
'name' => '5% Discount',
|
||||
'type' => 'sale',
|
||||
'value' => '-5%',
|
||||
]);
|
||||
|
||||
$item = [
|
||||
'id' => 1,
|
||||
'name' => 'Chicken Curry',
|
||||
'price' => 18.95,
|
||||
'quantity' => 1,
|
||||
'attributes' => [],
|
||||
'conditions' => $saleCondition,
|
||||
];
|
||||
|
||||
$this->cart->add($item);
|
||||
|
||||
expect($this->cart->get(1)->getPriceSum())->toEqual(18.95);
|
||||
expect($this->cart->get(1)->getPriceSumWithConditions())->toEqual(18);
|
||||
expect($this->cart->getSubTotal())->toEqual(18, 'Cart should have subtotal of 18');
|
||||
expect($this->cart->getTotal())->toEqual(18, 'Cart should have total of 18');
|
||||
});
|
||||
|
||||
test('can add an item with multiple item level conditions', function () {
|
||||
$saleCondition = new CartCondition([
|
||||
'name' => '5% Discount',
|
||||
'type' => 'sale',
|
||||
'value' => '-5%',
|
||||
]);
|
||||
|
||||
$gstCondition = new CartCondition([
|
||||
'name' => 'GST',
|
||||
'type' => 'gst',
|
||||
'value' => '2.5%',
|
||||
]);
|
||||
|
||||
$item = [
|
||||
'id' => 1,
|
||||
'name' => 'Chicken Curry',
|
||||
'price' => 18.95,
|
||||
'quantity' => 1,
|
||||
'attributes' => [],
|
||||
'conditions' => [$saleCondition, $gstCondition],
|
||||
];
|
||||
|
||||
$this->cart->add($item);
|
||||
|
||||
expect($this->cart->get(1)->getPriceSum())->toEqual(18.95);
|
||||
expect($this->cart->get(1)->getPriceSumWithConditions())->toEqual(18.45);
|
||||
expect($this->cart->getSubTotal())->toEqual(18.45, 'Cart should have subtotal of 18.45');
|
||||
expect($this->cart->getTotal())->toEqual(18.45, 'Cart should have total of 18.45');
|
||||
});
|
||||
|
||||
test('can clear a simple cart', function () {
|
||||
$this->cart->add(1, 'Sample Item', 100.99, 2, []);
|
||||
|
||||
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
|
||||
expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1');
|
||||
expect($this->cart->getContent()->first()['id'])->toEqual(1, 'Item added has ID of 1 so first content ID should be 1');
|
||||
expect($this->cart->getContent()->first()['price'])->toEqual(100.99, 'Item added has price of 100.99 so first content price should be 100.99');
|
||||
expect(MockCartModel::all()->count())->toEqual(1, 'The carts database table should have 1 row');
|
||||
|
||||
$this->cart->clear();
|
||||
|
||||
expect($this->cart->isEmpty())->toBeTrue('Cart should be empty');
|
||||
expect($this->cart->getContent()->count())->toEqual(0, 'Cart content should be 0');
|
||||
expect(MockCartModel::all()->count())->toEqual(0, 'The carts database table should have 0 rows');
|
||||
});
|
||||
});
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
use Wearepixel\Cart\Cart;
|
||||
use Wearepixel\Cart\CartCondition;
|
||||
use Wearepixel\Cart\Tests\Helpers\MockProduct;
|
||||
use Wearepixel\Cart\Tests\Helpers\SessionMock;
|
||||
use Joelwmale\Cart\Cart;
|
||||
use Joelwmale\Cart\CartCondition;
|
||||
use Joelwmale\Cart\Tests\Helpers\MockProduct;
|
||||
use Joelwmale\Cart\Tests\Helpers\SessionMock;
|
||||
|
||||
beforeEach(function () {
|
||||
$events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
|
||||
@@ -47,7 +47,7 @@
|
||||
});
|
||||
|
||||
test('item get conditions with conditions', function () {
|
||||
$itemCondition1 = new \Wearepixel\Cart\CartCondition([
|
||||
$itemCondition1 = new \Joelwmale\Cart\CartCondition([
|
||||
'name' => 'SALE 5%',
|
||||
'type' => 'sale',
|
||||
'target' => 'item',
|
||||
@@ -77,7 +77,7 @@
|
||||
});
|
||||
|
||||
test('it will throw an exception when a non existing model is being associated', function () {
|
||||
$this->expectException(\Wearepixel\Cart\Exceptions\UnknownModelException::class);
|
||||
$this->expectException(\Joelwmale\Cart\Exceptions\UnknownModelException::class);
|
||||
$this->expectExceptionMessage('The supplied model SomeModel does not exist.');
|
||||
|
||||
$this->cart->add(1, 'Test item', 1, 10.00)->associate('SomeModel');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Wearepixel\Cart\Cart;
|
||||
use Wearepixel\Cart\Tests\Helpers\SessionMock;
|
||||
use Joelwmale\Cart\Cart;
|
||||
use Joelwmale\Cart\Tests\Helpers\SessionMock;
|
||||
|
||||
beforeEach(function () {
|
||||
$events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
|
||||
|
||||
Reference in New Issue
Block a user