alalm3i/laravel-cart

该包已废弃,不再维护。没有建议的替代包。

Laravel 购物车

v1.0.0 2023-09-21 22:06 UTC

This package is auto-updated.

Last update: 2024-03-26 18:44:09 UTC


README

此包是从 bumbummen99/LaravelShoppingcart 分支而来,增加了对 Laravel 10 的支持。

我刚刚升级了该包以支持 Laravel 10,以便在项目中使用。

Laravel 购物车

CI Code Checks codecov StyleCI Total Downloads Latest Stable Version Latest Unstable Version License

安装

通过 Composer 安装此包。

在终端运行 Composer require 命令

composer require alalm3i/laravel-cart

现在您已准备好在应用程序中使用 Laravel 购物车包了。

您绝对应该发布 config 文件并查看它。

php artisan vendor:publish --provider="Alalm3i\LaravelCart\CartServiceProvider" --tag="config"

这将为您提供一个 cart.php 配置文件,您可以在其中更改包的行为。

目录

查看以下主题之一以了解有关 LaravelShoppingcart 的更多信息

重要提示

由于所有包含计算含税和折扣价格的购物车都可能受到“总价四舍五入问题”的影响(*),这是由于价格和结果使用的小数精度引起的。为了避免(或至少最小化)此问题,在 Laravel 购物车包中,总价使用 “每行” 方法进行计算,并根据配置文件(cart.php)中设置的默认数字格式进行四舍五入。由于这个原因,我们 **不建议将高精度设置为默认值,并且使用更少的十进制数格式化输出结果**。这样做可能导致四舍五入问题。

基本价格(产品价格)不进行四舍五入。

用法

购物车提供了以下方法供您使用

Cart::add()

添加到购物车中的项目非常简单,您只需使用 add() 方法,该方法接受各种参数。

在其最基本的形式中,您可以指定要添加到购物车中的产品的 id、名称、数量、价格和重量。

Cart::add('293ad', 'Product 1', 1, 9.99, 550);

作为一个可选的第五个参数,您可以传递选项,这样您就可以添加具有相同 id 但(例如)不同尺寸的多个项目。

Cart::add('293ad', 'Product 1', 1, 9.99, 550, ['size' => 'large']);

add() 方法将返回您刚刚添加到购物车中的项目的 CartItem 实例。

也许您更喜欢使用数组添加项目?只要数组包含所需的键,您就可以将其传递给该方法。选项键是可选的。

Cart::add(['id' => '293ad', 'name' => 'Product 1', 'qty' => 1, 'price' => 9.99, 'weight' => 550, 'options' => ['size' => 'large']]);

在包的第二个版本中,新增了使用 Buyable 接口的可能性。这种方法是您有一个模型实现了 Buyable 接口,这将使您实现一些方法,以便包知道如何从您的模型中获取 id、名称和价格。这样,您只需将模型和数量传递给 add() 方法,它就会自动将其添加到购物车中。

作为一个额外的奖励,它将自动将模型与 CartItem 关联起来

Cart::add($product, 1, ['size' => 'large']);

作为一个可选的第三个参数,您可以添加选项。

Cart::add($product, 1, ['size' => 'large']);

最后,您还可以一次将多个商品添加到购物车中。您只需将一个数组或一个包含可购买商品的数组传递给add()方法,它们就会被添加到购物车中。

当添加多个商品到购物车时,add()方法将返回一个CartItems数组。

Cart::add([
  ['id' => '293ad', 'name' => 'Product 1', 'qty' => 1, 'price' => 10.00, 'weight' => 550],
  ['id' => '4832k', 'name' => 'Product 2', 'qty' => 1, 'price' => 10.00, 'weight' => 550, 'options' => ['size' => 'large']]
]);

Cart::add([$product1, $product2]);

Cart::update()

要更新购物车中的商品,您首先需要商品的rowId。然后,您可以使用update()方法来更新它。

如果您只想更新数量,只需将rowId和新的数量传递给更新方法即可。

$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';

Cart::update($rowId, 2); // Will update the quantity

如果您想更新购物车中商品的选项,

$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';

Cart::update($rowId, ['options'  => ['size' => 'small']]); // Will update the size option with new value

如果您想更新更多商品属性,您可以将一个数组或一个Buyable作为第二个参数传递给更新方法。这样,您就可以使用给定的rowId更新商品的所有信息。

Cart::update($rowId, ['name' => 'Product 1']); // Will update the name

Cart::update($rowId, $product); // Will update the id, name and price

Cart::remove()

要移除购物车中的商品,您同样需要rowId。您只需将此rowId传递给remove()方法,它就会从购物车中移除该商品。

$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';

Cart::remove($rowId);

Cart::get()

如果您想通过rowId从购物车中获取商品,您只需在购物车上调用get()方法并传递rowId即可。

$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';

Cart::get($rowId);

Cart::content()

当然,您还想获取购物车的内容。这里您将使用content方法。此方法将返回一个包含CartItems的集合,您可以遍历它并向您的客户展示内容。

Cart::content();

此方法将返回当前购物实例的内容,如果您想获取其他实例的内容,只需简单地链式调用。

Cart::instance('wishlist')->content();

Cart::destroy()

如果您想完全移除购物车的内容,您可以在购物车上调用destroy方法。这将移除当前购物实例的所有CartItems

Cart::destroy();

Cart::weight()

可以使用weight()方法获取购物车中所有商品的重量总和,给定它们的重量和数量。

Cart::weight();

该方法将自动格式化结果,您可以使用三个可选参数进行微调。

Cart::weight($decimals, $decimalSeperator, $thousandSeperator);

您可以在配置文件中设置默认的数字格式。

如果您不是使用外观(Facade),而是在您的(例如)控制器中使用依赖注入,您也可以简单地获取总属性$cart->weight

Cart::total()

可以使用total()方法获取购物车中所有商品的计算总价,给定它们的价格和数量。

Cart::total();

该方法将自动格式化结果,您可以使用三个可选参数进行微调。

Cart::total($decimals, $decimalSeparator, $thousandSeparator);

您可以在配置文件中设置默认的数字格式。

如果您不是使用外观(Facade),而是在您的(例如)控制器中使用依赖注入,您也可以简单地获取总属性$cart->total

Cart::tax()

可以使用tax()方法获取购物车中所有商品的计算税额,给定它们的价格和数量。

Cart::tax();

该方法将自动格式化结果,您可以使用三个可选参数进行微调。

Cart::tax($decimals, $decimalSeparator, $thousandSeparator);

您可以在配置文件中设置默认的数字格式。

如果您不是使用外观(Facade),而是在您的(例如)控制器中使用依赖注入,您也可以简单地获取税属性$cart->tax

Cart::subtotal()

可以使用subtotal()方法获取购物车中所有商品的总价,减去税额。

Cart::subtotal();

该方法将自动格式化结果,您可以使用三个可选参数进行微调。

Cart::subtotal($decimals, $decimalSeparator, $thousandSeparator);

您可以在配置文件中设置默认的数字格式。

如果您不是使用外观(Facade),而是在您的(例如)控制器中使用依赖注入,您也可以简单地获取小计属性$cart->subtotal

Cart::discount()

可以使用discount()方法获取购物车中所有商品的总折扣。

Cart::discount();

该方法将自动格式化结果,您可以使用三个可选参数进行微调。

Cart::discount($decimals, $decimalSeparator, $thousandSeparator);

您可以在配置文件中设置默认的数字格式。

如果您不是使用外观(Facade),而是在您的(例如)控制器中使用依赖注入,您也可以简单地获取小计属性$cart->discount

Cart::initial()

可以使用initial()方法获取购物车中所有商品在应用折扣和税之前的总价。

未来可能会被弃用。 当四舍五入可能受到四舍五入问题的影响时,请谨慎使用或使用 Cart::priceTotal()

Cart::initial();

该方法将自动格式化结果,您可以使用三个可选参数进行修改。

Cart::initial($decimals, $decimalSeparator, $thousandSeparator);

您可以在配置文件中设置默认的数字格式。

Cart::priceTotal()

使用 priceTotal() 方法可以获取购物车中所有商品在应用折扣和税费之前的总价。

Cart::priceTotal();

该方法将根据默认数字格式进行四舍五入,但您可以使用三个可选参数进行修改

Cart::priceTotal($decimals, $decimalSeparator, $thousandSeparator);

您可以在配置文件中设置默认的数字格式。

如果您没有使用外观(Facade),而是使用(例如)控制器中的依赖注入,您也可以简单地获取小计属性 $cart->initial

Cart::count()

如果您想了解购物车中有多少件商品,可以使用 count() 方法。此方法将返回购物车中的商品总数。所以如果您添加了2本书和1件衬衫,它将返回3件商品。

Cart::count();
$cart->count();

Cart::search()

要查找购物车中的商品,可以使用 search() 方法。

该方法在版本2中进行了更改

在幕后,该方法简单地使用了 Laravel Collection 类的 filter 方法。这意味着您必须传递一个闭包,在其中指定您要搜索的术语。

如果您想找到所有 id 为 1 的商品

$cart->search(function ($cartItem, $rowId) {
	return $cartItem->id === 1;
});

如您所见,闭包将接收两个参数。第一个是要进行检查的 CartItem。第二个参数是这个 CartItem 的 rowId。

该方法将返回一个包含所有找到的 CartItems 的 Collection

这种搜索方式让您完全控制搜索过程,并让您能够创建非常精确和具体的搜索。

Cart::setTax($rowId, $taxRate)

您可以使用 setTax() 方法更改应用于 CartItem 的税率。这将覆盖配置文件中设置的值。

Cart::setTax($rowId, 21);
$cart->setTax($rowId, 21);

Cart::setGlobalTax($taxRate)

您可以使用 setGlobalTax() 方法更改购物车中所有商品的税率。新商品也将接收 setGlobalTax。

Cart::setGlobalTax(21);
$cart->setGlobalTax(21);

Cart::setGlobalDiscount($discountRate)

您可以使用 setGlobalDiscount() 方法更改购物车中所有商品的折扣率。新商品也将接收折扣。

Cart::setGlobalDiscount(50);
$cart->setGlobalDiscount(50);

Cart::setDiscount($rowId, $taxRate)

您可以使用 setDiscount() 方法更改应用于 CartItem 的折扣率。请注意,如果您之后为购物车设置了全局折扣,此值将发生变化。

Cart::setDiscount($rowId, 21);
$cart->setDiscount($rowId, 21);

Buyable

为了方便快速将商品添加到购物车并自动关联,您的模型必须实现 Buyable 接口。您可以使用 CanBeBought 特性来实现所需的方法,但请注意,这些将使用模型上预定义的字段来获取所需值。

<?php
namespace App\Models;

use Alalm3i\LaravelCart\Contracts\Buyable;
use Illuminate\Database\Eloquent\Model;

class Product extends Model implements Buyable {
    use Alalm3i\LaravelCart\CanBeBought;
}

如果特性对模型不起作用或您想手动映射字段,模型必须实现 Buyable 接口的方法。为此,它必须实现以下函数

    public function getBuyableIdentifier(){
        return $this->id;
    }
    public function getBuyableDescription(){
        return $this->name;
    }
    public function getBuyablePrice(){
        return $this->price;
    }
    public function getBuyableWeight(){
        return $this->weight;
    }

示例

<?php
namespace App\Models;

use Alalm3i\LaravelCart\Contracts\Buyable;
use Illuminate\Database\Eloquent\Model;

class Product extends Model implements Buyable {
    public function getBuyableIdentifier($options = null) {
        return $this->id;
    }
    public function getBuyableDescription($options = null) {
        return $this->name;
    }
    public function getBuyablePrice($options = null) {
        return $this->price;
    }
    public function getBuyableWeight($options = null) {
        return $this->weight;
    }
}

集合

在多个实例中,购物车将返回一个 Collection。这只是一个简单的 Laravel Collection,因此您可以在结果上调用 Laravel Collection 上的所有方法。

例如,您可以快速获取购物车中独特产品的数量

Cart::content()->count();

或者您可以根据产品的 id 对内容进行分组

Cart::content()->groupBy('id');

实例

该包支持多个购物车实例。这种方式是这样的

您可以通过调用 Cart::instance('newInstance') 来设置当前购物车实例。从这一刻起,活动的购物车实例将是 newInstance,因此当您添加、删除或获取购物车内容时,您将处理购物车的 newInstance 实例。如果您想切换实例,只需再次调用 Cart::instance('otherInstance'),您将再次与 otherInstance 一起工作。

下面是一个简单的例子

Cart::instance('shopping')->add('192ao12', 'Product 1', 1, 9.99, 550);

// Get the content of the 'shopping' cart
Cart::content();

Cart::instance('wishlist')->add('sdjk922', 'Product 2', 1, 19.95, 550, ['size' => 'medium']);

// Get the content of the 'wishlist' cart
Cart::content();

// If you want to get the content of the 'shopping' cart again
Cart::instance('shopping')->content();

// And the count of the 'wishlist' cart again
Cart::instance('wishlist')->count();

您还可以使用 InstanceIdentifier 合约来扩展所需的模型,并为它分配/创建一个购物车实例。这也允许您直接设置全局折扣。

<?php

namespace App;
...
use Illuminate\Foundation\Auth\User as Authenticatable;
use Alalm3i\LaravelCart\Contracts\InstanceIdentifier;

class User extends Authenticatable implements InstanceIdentifier
{
	...

	/**
     * Get the unique identifier to load the Cart from
     *
     * @return int|string
     */
    public function getInstanceIdentifier($options = null)
    {
        return $this->email;
    }

    /**
     * Get the unique identifier to load the Cart from
     *
     * @return int|string
     */
    public function getInstanceGlobalDiscount($options = null)
    {
        return $this->discountRate ?: 0;
    }
}

// Inside Controller
$user = \Auth::user();
$cart = Cart::instance($user);



注意:在脚本执行期间,如果没有设置不同的实例,购物车将保持在上次设置的实例中。

注意2:默认的购物车实例名为 default,因此当您不使用实例时,Cart::content();Cart::instance('default')->content() 相同。

模型

由于直接从购物车项访问模型可能非常方便,因此可以将模型与购物车中的项目相关联。假设您在应用程序中有一个 Product 模型。使用 associate() 方法,您可以告诉购物车购物车中的某个项目与 Product 模型相关联。

这样,您就可以从 CartItem 直接访问模型了!

您可以通过购物车项上的 model 属性访问模型。

如果您的模型实现了 Buyable 接口并且您使用该模型将项目添加到购物车中,它将自动关联。

下面是一个示例

// First we'll add the item to the cart.
$cartItem = Cart::add('293ad', 'Product 1', 1, 9.99, 550, ['size' => 'large']);

// Next we associate a model with the item.
Cart::associate($cartItem->rowId, 'Product');

// Or even easier, call the associate method on the CartItem!
$cartItem->associate('Product');

// You can even make it a one-liner
Cart::add('293ad', 'Product 1', 1, 9.99, 550, ['size' => 'large'])->associate('Product');

// Now, when iterating over the content of the cart, you can access the model.
foreach(Cart::content() as $row) {
	echo 'You have ' . $row->qty . ' items of ' . $row->model->name . ' with description: "' . $row->model->description . '" in your cart.';
}

数据库

配置

要将购物车保存到数据库以便稍后检索,该包需要知道使用哪个数据库连接以及表的名称。默认情况下,该包将使用默认数据库连接并使用名为 shoppingcart 的表。您可以在配置中更改这些设置。

为了使您的操作更简单,该包还包括一个可用的 migration,您可以通过运行以下命令发布它:

php artisan vendor:publish --provider="Alalm3i\LaravelCart\ShoppingcartServiceProvider" --tag="migrations"

这将把 shoppingcart 表的迁移文件放入 database/migrations 目录。现在您只需运行 php artisan migrate 来迁移您的数据库。

存储购物车

要将购物车实例存储到数据库中,您必须调用 store($identifier) 方法。其中 $identifier 是一个随机密钥,例如用户的 id 或用户名。

Cart::store('username');

// To store a cart instance named 'wishlist'
Cart::instance('wishlist')->store('username');

恢复购物车

如果您想从数据库中检索购物车并将其恢复,您只需调用 restore($identifier),其中 $identifier 是您为 store 方法指定的密钥。

Cart::restore('username');

// To restore a cart instance named 'wishlist'
Cart::instance('wishlist')->restore('username');

合并购物车

如果您想将购物车与数据库中的另一个购物车合并,您只需调用 merge($identifier),其中 $identifier 是您为 store 方法指定的密钥。您还可以定义是否想保留项目的折扣和税率,以及是否想分发 "cart.added" 事件。

// Merge the contents of 'savedcart' into 'username'.
Cart::instance('username')->merge('savedcart', $keepDiscount, $keepTaxrate, $dispatchAdd, 'savedcartinstance');

删除购物车

如果您想从数据库中删除购物车,您只需调用 erase($identifier),其中 $identifier 是您为 store 方法指定的密钥。

Cart::erase('username');

// To erase a cart switching to an instance named 'wishlist'
Cart::instance('wishlist')->erase('username');

计算器

该包的计算逻辑在 Calculator 类中实现并定义。这些类实现了 Alalm3i\LaravelCart\Contracts\Calculator 合约,并确定如何计算和四舍五入价格。计算器可以在配置文件中进行配置。这是默认的计算器

<?php

namespace Alalm3i\LaravelCart\Calculation;

use Alalm3i\LaravelCart\CartItem;
use Alalm3i\LaravelCart\Contracts\Calculator;

class DefaultCalculator implements Calculator
{
    public static function getAttribute(string $attribute, CartItem $cartItem)
    {
        $decimals = config('cart.format.decimals', 2);

        switch ($attribute) {
            case 'discount':
                return $cartItem->price * ($cartItem->getDiscountRate() / 100);
            case 'tax':
                return round($cartItem->priceTarget * ($cartItem->taxRate / 100), $decimals);
            case 'priceTax':
                return round($cartItem->priceTarget + $cartItem->tax, $decimals);
            case 'discountTotal':
                return round($cartItem->discount * $cartItem->qty, $decimals);
            case 'priceTotal':
                return round($cartItem->price * $cartItem->qty, $decimals);
            case 'subtotal':
                return max(round($cartItem->priceTotal - $cartItem->discountTotal, $decimals), 0);
            case 'priceTarget':
                return round(($cartItem->priceTotal - $cartItem->discountTotal) / $cartItem->qty, $decimals);
            case 'taxTotal':
                return round($cartItem->subtotal * ($cartItem->taxRate / 100), $decimals);
            case 'total':
                return round($cartItem->subtotal + $cartItem->taxTotal, $decimals);
            default:
                return;
        }
    }
}

异常

如果出现问题,购物车包将抛出异常。这样,您就可以更容易地使用购物车包调试代码或根据异常类型处理错误。购物车包可以抛出以下异常

异常 原因
CartAlreadyStoredException 当尝试使用指定的标识符存储已存储的购物车时
InvalidRowIDException 当传递的行ID当前购物车实例中不存在时
UnknownModelException 当您尝试将一个不存在的模型关联到购物车项时。

事件

购物车还内置了事件。有五个事件可供您监听。

事件 触发 参数
cart.adding 当向购物车添加项目时。 正在添加的CartItem
cart.updating 当更新购物车中的项目时。 正在更新的CartItem
cart.removing 当从购物车中移除项目时。 正在移除的CartItem
cart.added 当项目被添加到购物车时。 被添加的CartItem
cart.updated 当项目被更新到购物车时。 被更新的CartItem
cart.removed 当项目从购物车中被移除时。 被移除的CartItem
cart.merged 当购物车内容合并时。 -
cart.stored 当购物车内容被存储时。 -
cart.restored 当购物车内容被恢复时。 -
cart.erased 当购物车内容被删除时。 -

示例

以下是如何在表格中列出购物车内容的简单示例

// Add some items in your Controller.
Cart::add('192ao12', 'Product 1', 1, 9.99);
Cart::add('1239ad0', 'Product 2', 2, 5.95, ['size' => 'large']);

// Display the content in a View.
<table>
   	<thead>
       	<tr>
           	<th>Product</th>
           	<th>Qty</th>
           	<th>Price</th>
           	<th>Subtotal</th>
       	</tr>
   	</thead>

   	<tbody>

   		<?php foreach(Cart::content() as $row) :?>

       		<tr>
           		<td>
               		<p><strong><?php echo $row->name; ?></strong></p>
               		<p><?php echo ($row->options->has('size') ? $row->options->size : ''); ?></p>
           		</td>
           		<td><input type="text" value="<?php echo $row->qty; ?>"></td>
           		<td>$<?php echo $row->price; ?></td>
           		<td>$<?php echo $row->total; ?></td>
       		</tr>

	   	<?php endforeach;?>

   	</tbody>
   	
   	<tfoot>
   		<tr>
   			<td colspan="2">&nbsp;</td>
   			<td>Subtotal</td>
   			<td><?php echo Cart::subtotal(); ?></td>
   		</tr>
   		<tr>
   			<td colspan="2">&nbsp;</td>
   			<td>Tax</td>
   			<td><?php echo Cart::tax(); ?></td>
   		</tr>
   		<tr>
   			<td colspan="2">&nbsp;</td>
   			<td>Total</td>
   			<td><?php echo Cart::total(); ?></td>
   		</tr>
   	</tfoot>
</table>