承接 shamarkellman/flex-cart 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

shamarkellman/flex-cart

Composer 安装命令:

composer require shamarkellman/flex-cart

包简介

A flexible shopping cart package for Laravel 12

README 文档

README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

FlexCart is a flexible shopping cart package for Laravel 12+ that provides comprehensive cart functionality including multiple storage backends, tax calculations, shipping management, coupon/discounts, and Money PHP integration.

Features

  • Multiple storage backends (session and database)
  • Flexible coupon/discount system with multiple discount types
  • Tax calculations with configurable rates
  • Shipping address and cost management
  • Comprehensive event system for cart lifecycle hooks
  • Money PHP integration for accurate financial calculations
  • Custom exception handling with detailed error messages

Installation

You can install the package via composer:

composer require shamarkellman/flex-cart

You can publish and run the migrations with:

php artisan vendor:publish --tag="flex-cart-migrations"
php artisan migrate

You can publish the config file with:

php artisan vendor:publish --tag="flex-cart-config"

Usage

Basic Cart Operations

use ShamarKellman\FlexCart\Facades\FlexCart;
use Money\Money;
use Money\Currency;

// Add product to cart
$product = Product::find(1);
$cartItem = FlexCart::addItem($product, 2);

// Add item with options (e.g., size, color)
$cartItemWithOptions = FlexCart::addItem($product, 1, [
    'size' => 'large',
    'color' => 'blue'
]);

// Update quantity
FlexCart::updateItem($cartItem->id, 3);

// Remove specific item
FlexCart::removeItem($cartItem->id);

// Clear entire cart
FlexCart::clear();

Cart Information

// Get all cart items
$items = FlexCart::items();

// Get specific item
$item = FlexCart::getItem($itemId);

// Count total items (sum of quantities)
$totalItems = FlexCart::count();

// Check if cart is empty
$isEmpty = FlexCart::isEmpty();

// Get cart totals
$subtotal = FlexCart::subtotal();      // Money object
$tax = FlexCart::tax();                // Money object
$shipping = FlexCart::shippingCost();  // Money object
$total = FlexCart::total();            // Money object

// Get raw amounts
echo $total->getAmount();              // '10000' (in cents)
echo $total->getCurrency()->getCode(); // 'USD'

Coupon System

FlexCart includes a comprehensive coupon/discount system supporting multiple discount types.

Adding Coupons

use ShamarKellman\FlexCart\Facades\FlexCart;
use ShamarKellman\FlexCart\Models\Coupon;

// Add a coupon to cart
$coupon = Coupon::where('code', 'SAVE20')->first();
$result = FlexCart::addCoupon($coupon);

// Check if coupon was added successfully
if ($result) {
    echo "Coupon applied!";
}

// Check if cart has a specific coupon
$hasCoupon = FlexCart::hasCoupon('SAVE20');

// Get coupon details
$coupon = FlexCart::getCoupon('SAVE20');

Removing Coupons

// Remove a specific coupon
FlexCart::removeCoupon('SAVE20');

// Clear all coupons
FlexCart::clearCoupons();

Getting Discounts

// Get general discount (products)
$generalDiscount = FlexCart::generalDiscount();

// Get shipping discount
$shippingDiscount = FlexCart::shippingDiscount();

// Get total discount
$totalDiscount = FlexCart::totalDiscount();

// Get subtotal after discounts
$subtotalWithCoupons = FlexCart::subtotalWithCoupons();

// Get final total (subtotal + shipping - discounts)
$total = FlexCart::total();

Coupon Model

Create coupons in your database using the CouponFactory:

use ShamarKellman\FlexCart\Models\Coupon;

// Fixed amount coupon ($20 off)
$coupon = Coupon::factory()->fixedAmount(20)->create([
    'code' => 'SAVE20',
    'is_stackable' => true,
]);

// Percentage coupon (10% off)
$coupon = Coupon::factory()->percentage(10)->create([
    'code' => 'PERCENT10',
    'is_stackable' => false,
]);

// Free shipping coupon
$coupon = Coupon::factory()->shipping(0)->create([
    'code' => 'FREESHIP',
]);

// Coupon with restrictions
$coupon = Coupon::factory()
    ->withMinimumAmount(50)      // $50 minimum
    ->withUsageLimit(100)        // 100 uses max
    ->expiresInDays(30)          // Expires in 30 days
    ->create([
        'code' => 'SPECIAL',
    ]);

Coupon Types

Type Description Value Format
TYPE_FIXED_AMOUNT Fixed discount on order total Amount in cents
TYPE_PERCENTAGE Percentage off order total Percentage (0-100)
TYPE_SHIPPING Free or discounted shipping Amount in cents

Coupon Features

  • Stackable coupons: Allow multiple coupons to be applied
  • Usage limits: Limit total number of uses
  • Minimum amount: Require minimum order total
  • Product-specific: Apply to specific products only
  • Exclusions: Exclude specific products from discount
  • Expiration: Set expiration dates
  • Activation dates: Set when coupon becomes active

Coupon Events

use ShamarKellman\FlexCart\Events\CouponApplied;
use ShamarKellman\FlexCart\Events\CouponRemoved;
use ShamarKellman\FlexCart\Events\CouponExpired;

Event::listen(CouponApplied::class, function ($event) {
    $coupon = $event->getCoupon();
    logger()->info('Coupon applied', ['code' => $coupon->getCode()]);
});

Event::listen(CouponRemoved::class, function ($event) {
    $coupon = $event->getCoupon();
    logger()->info('Coupon removed', ['code' => $coupon->getCode()]);
});

Event::listen(CouponExpired::class, function ($event) {
    $coupon = $event->getCoupon();
    logger()->info('Coupon expired', ['code' => $coupon->getCode()]);
});

Shipping Management

// Set shipping address
FlexCart::setShippingAddress([
    'first_name' => 'John',
    'last_name' => 'Doe',
    'company' => 'Acme Corp', // optional
    'address_line_1' => '123 Main St',
    'address_line_2' => 'Apt 4B', // optional
    'city' => 'New York',
    'state' => 'NY',
    'postal_code' => '10001',
    'country' => 'US',
    'phone' => '+1-555-0123', // optional
    'email' => 'john@example.com', // optional
]);

// Set shipping cost
FlexCart::setShippingCost(new Money(1000, new Currency('USD'))); // $10.00

// Get shipping details
$shippingDetail = FlexCart::getShippingDetail();
echo $shippingDetail->first_name; // 'John'
echo $shippingDetail->country; // 'US'

Cart Item Operations

$cartItem = FlexCart::addItem($product, 2);

// Get item details
$quantity = $cartItem->getQuantity();
$unitPrice = $cartItem->getUnitPrice();
$totalPrice = $cartItem->getTotal();
$taxAmount = $cartItem->getTaxAmount();
$options = $cartItem->getOptions();
$buyableProduct = $cartItem->getBuyable();

// Modify item directly
$cartItem->setQuantity(5);
$cartItem->setOptions(['size' => 'XL', 'gift_wrap' => true]);

Working with Different Currencies

// Set default currency in config/flex-cart.php
'default_currency' => 'EUR',

// Or change currency dynamically
FlexCart::setShippingCost(new Money(1000, new Currency('EUR')));

Advanced Usage Examples

// Check if item exists before adding
if (!FlexCart::getItem($productId)) {
    FlexCart::addItem($product, 1);
}

// Add multiple items at once
$products = [
    ['product' => $product1, 'quantity' => 2, 'options' => ['size' => 'M']],
    ['product' => $product2, 'quantity' => 1, 'options' => ['color' => 'red']],
];

foreach ($products as $item) {
    FlexCart::addItem($item['product'], $item['quantity'], $item['options'] ?? []);
}

// Calculate totals with tax (if tax rate is configured)
$subtotal = FlexCart::subtotal();
$taxRate = config('flex-cart.tax_rate', 0);
$totalWithTax = FlexCart::total();

// Format money for display
$formatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY);
echo $formatter->formatCurrency($total->getAmount() / 100, $total->getCurrency()->getCode());
// Output: $100.00

Configuration

Environment Variables

# .env file
CART_DEFAULT_CURRENCY=USD
CART_TAX_RATE=8.25
CART_STORAGE_DRIVER=session

Configuration File

After publishing the config file (config/flex-cart.php):

<?php

return [
    // Default currency for all cart operations
    'default_currency' => env('CART_DEFAULT_CURRENCY', 'USD'),

    // Tax rate as percentage (e.g., 8.25 for 8.25%)
    'tax_rate' => env('CART_TAX_RATE', 0),

    // Storage configuration
    'storage' => [
        // Driver: 'session' or 'database'
        'driver' => env('CART_STORAGE_DRIVER', 'session'),

        // Session key for session storage
        'session_key' => 'shopping_cart',

        // Available storage drivers
        'drivers' => [
            'session' => \ShamarKellman\FlexCart\Storage\SessionStorage::class,
            'database' => \ShamarKellman\FlexCart\Storage\DatabaseStorage::class,
        ],
    ],

    // Custom model classes (if you want to extend them)
    'models' => [
        'cart' => \ShamarKellman\FlexCart\Models\Cart::class,
        'cart_item' => \ShamarKellman\FlexCart\Models\CartItem::class,
        'shipping_detail' => \ShamarKellman\FlexCart\Models\ShippingDetail::class,
    ],
];

Making Models Buyable

To use your models with FlexCart, implement the BuyableInterface:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use ShamarKellman\FlexCart\Contracts\BuyableInterface;
use Money\Money;
use Money\Currency;

class Product extends Model implements BuyableInterface
{
    // ... existing model code

    public function getCartItemIdentifier(): int|string
    {
        return $this->id;
    }

    public function getCartItemName(): string
    {
        return $this->name;
    }

    public function getPrice(): Money
    {
        // Assuming price is stored in cents in database
        return new Money($this->price_cents, new Currency('USD'));
        
        // Or if stored as decimal:
        // return new Money((int) ($this->price * 100), new Currency('USD'));
    }

    public function getCartItemOptions(): array
    {
        return [
            'size' => $this->size,
            'color' => $this->color,
            // Add any other relevant options
        ];
    }
}

API Reference

FlexCart Facade Methods

Cart Management

  • addItem(Model $buyable, int $quantity = 1, array $options = []): CartItemInterface
  • updateItem(int|string $itemId, int $quantity): bool
  • removeItem(int|string $itemId): bool
  • clear(): void

Cart Information

  • items(): Collection<CartItemInterface>
  • getItem(int|string $itemId): ?CartItemInterface
  • count(): int
  • isEmpty(): bool

Totals and Calculations

  • subtotal(): Money
  • subtotalNet(): Money
  • tax(): Money
  • shippingCost(): Money
  • total(): Money

Coupon Methods

  • addCoupon(CouponInterface $coupon): bool
  • removeCoupon(string $code): bool
  • hasCoupon(string $code): bool
  • getCoupon(string $code): ?CouponInterface
  • getCoupons(): Collection
  • clearCoupons(): void
  • generalDiscount(): Money
  • shippingDiscount(): Money
  • totalDiscount(): Money
  • subtotalWithCoupons(): Money
  • couponDiscount(): Money

Shipping

  • setShippingAddress(array $address): void
  • setShippingCost(Money $cost): void
  • getShippingDetail(): ?ShippingDetail

CartItemInterface Methods

  • getQuantity(): int
  • getUnitPrice(): Money
  • getTotal(): Money
  • getTaxAmount(): Money
  • getOptions(): array
  • setQuantity(int $quantity): void
  • setOptions(array $options): void
  • getBuyable(): Model

BuyableInterface Methods

  • getCartItemIdentifier(): int|string
  • getCartItemName(): string
  • getPrice(): Money
  • getCartItemOptions(): array

Events

FlexCart dispatches events for various cart operations, allowing you to hook into cart lifecycle events:

Cart Events

ShamarKellman\FlexCart\Events\ItemAddedToCart

Fired when an item is added to the cart for the first time.

Event::listen(ItemAddedToCart::class, function ($event) {
    $cartItem = $event->getCartItem();
    $quantity = $event->getAddedQuantity();
    $buyable = $event->getBuyable();
    $options = $event->getOptions();
});

ShamarKellman\FlexCart\Events\QuantityUpdated

Fired when an item's quantity is modified.

Event::listen(QuantityUpdated::class, function ($event) {
    $cartItem = $event->getCartItem();
    $oldQuantity = $event->getOldQuantity();
    $newQuantity = $event->getNewQuantity();
    $isIncrease = $event->isIncrease();
    $isDecrease = $event->isDecrease();
});

ShamarKellman\FlexCart\Events\ItemRemovedFromCart

Fired when an item is removed from the cart.

Event::listen(ItemRemovedFromCart::class, function ($event) {
    $cartItem = $event->getCartItem();
    $removedQuantity = $event->getRemovedQuantity();
    $unitPrice = $event->getUnitPrice();
});

ShamarKellman\FlexCart\Events\CartCleared

Fired when the entire cart is cleared.

Event::listen(CartCleared::class, function ($event) {
    $clearedItems = $event->getClearedItems();
    $itemCount = $event->getClearedItemCount();
    $totalQuantity = $event->getClearedTotalQuantity();
    $subtotal = $event->getClearedSubtotal();
});

ShamarKellman\FlexCart\Events\ShippingCostSet

Fired when shipping cost is set or changed.

Event::listen(ShippingCostSet::class, function ($event) {
    $oldCost = $event->getOldCost();
    $newCost = $event->getNewCost();
    $difference = $event->getDifference();
    $hasIncreased = $event->hasIncreased();
    $hasDecreased = $event->hasDecreased();
});

ShamarKellman\FlexCart\Events\ShippingAddressSet

Fired when shipping address is set or changed.

Event::listen(ShippingAddressSet::class, function ($event) {
    $oldAddress = $event->getOldAddress();
    $newAddress = $event->getNewAddress();
    $isFirstAddress = $event->isFirstAddress();
    $hasChanged = $event->hasChanged();
    $country = $event->getCountry();
    $postalCode = $event->getPostalCode();
});

Coupon Events

ShamarKellman\FlexCart\Events\CouponApplied

Fired when a coupon is applied to the cart.

ShamarKellman\FlexCart\Events\CouponRemoved

Fired when a coupon is removed from the cart.

ShamarKellman\FlexCart\Events\CouponExpired

Fired when a coupon expires.

Storage Backends

Session Storage (Default)

  • Stores cart data in Laravel sessions
  • Perfect for guest carts
  • Automatically cleaned when session expires
  • No database overhead

Database Storage

  • Persists carts across sessions
  • Supports user authentication integration
  • Enables cart analytics and recovery
  • Requires published migrations

To use database storage:

// In config/flex-cart.php
'storage' => [
    'driver' => 'database',
    // ...
],

Don't forget to publish and run the migrations:

php artisan vendor:publish --tag="flex-cart-migrations"
php artisan migrate

Testing

composer test

Troubleshooting

Common Issues

"Buyable model must implement BuyableInterface"

Make sure your model implements the BuyableInterface and all required methods.

Cart items not persisting

Check your storage driver configuration. For database storage, ensure migrations are published and run.

Tax calculations seem incorrect

Verify your tax rate configuration. The rate should be a percentage (e.g., 8.25 for 8.25%).

Money currency mismatch

Ensure all Money objects use the same currency, or configure the default currency properly.

Debug Mode

To debug cart operations, you can temporarily access the cart instance:

$cart = app(\ShamarKellman\FlexCart\FlexCart::class);
dd($cart->items(), $cart->total());

Performance Considerations

  • Use session storage for guest carts to reduce database load
  • Implement cart cleanup jobs for abandoned carts
  • Consider Redis for session storage in production
  • Add indexes to the database tables (included in migrations)

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.

shamarkellman/flex-cart 适用场景与选型建议

shamarkellman/flex-cart 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 21 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 03 月 13 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「laravel」 「shamarkellman」 「flex-cart」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 shamarkellman/flex-cart 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 shamarkellman/flex-cart 我们能提供哪些服务?
定制开发 / 二次开发

基于 shamarkellman/flex-cart 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 21
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 24
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-03-13