renatoandradeweb/modern-cart

Modern PHP 8+ shopping cart library with multiple storage backends and type safety

v1.0.0 2025-06-19 18:03 UTC

This package is auto-updated.

Last update: 2025-06-19 18:29:31 UTC


README

Latest Stable Version Total Downloads License PHP Version Require Tests Coverage

A modern, type-safe shopping cart library for PHP 8+ with multiple storage backends and a fluent API.

โœจ Features

  • ๐Ÿ”ง PHP 8+ Features: Full type declarations, property promotion, match expressions
  • ๐Ÿ›ก๏ธ Type Safety: Strict typing throughout with PHPStan level 9 compliance
  • ๐Ÿ’พ Multiple Storage Backends: Session, Cookie, File, Memory storage
  • ๐Ÿ”— Fluent API: Chainable methods for better developer experience
  • ๐Ÿ“ฆ Zero Dependencies: No external dependencies required
  • ๐Ÿงช Fully Tested: 100% code coverage with PHPUnit
  • ๐Ÿ“š Well Documented: Comprehensive documentation with examples

๐Ÿ“‹ Requirements

  • PHP 8.0 or higher
  • Session support (for SessionStore)
  • File system access (for FileStore)

๐Ÿš€ Installation

Install via Composer:

composer require renatoandradeweb/modern-cart

๐ŸŽฏ Quick Start

<?php

use ModernCart\Cart;
use ModernCart\CartItem;
use ModernCart\Storage\SessionStore;

// Create a cart with session storage
$cart = new Cart('user_123', new SessionStore());

// Add items
$item = new CartItem([
    'name' => 'Awesome Product',
    'price' => 29.99,
    'tax' => 3.00,
    'quantity' => 2
]);

$cart->add($item)->save();

// Get totals
echo "Items: " . $cart->totalItems(); // 2
echo "Subtotal: $" . $cart->subtotal(); // $59.98
echo "Tax: $" . $cart->tax(); // $6.00
echo "Total: $" . $cart->total(); // $65.98

๐Ÿ“– Usage

Creating a Cart

use ModernCart\Cart;
use ModernCart\Storage\{SessionStore, CookieStore, FileStore, MemoryStore};

// Session storage (recommended for web applications)
$cart = new Cart('cart_id', new SessionStore());

// Cookie storage (for persistent carts)
$cart = new Cart('cart_id', new CookieStore(
    prefix: 'cart_',
    expiry: 2592000, // 30 days
    path: '/',
    secure: true,
    httpOnly: true
));

// File storage (for server-side persistence)
$cart = new Cart('cart_id', new FileStore('/path/to/storage'));

// Memory storage (for testing)
$cart = new Cart('cart_id', new MemoryStore());

Working with Cart Items

use ModernCart\CartItem;

// Create items
$item = new CartItem([
    'name' => 'Product Name',
    'price' => 19.99,
    'tax' => 2.00,
    'quantity' => 1,
    'sku' => 'PROD-001', // Custom attributes
    'category' => 'Electronics'
]);

// Fluent setters
$item->setName('New Name')
     ->setPrice(24.99)
     ->setQuantity(3);

// Getters
echo $item->getName(); // 'New Name'
echo $item->getPrice(); // 24.99
echo $item->getTotalPrice(); // 80.97 (includes tax)

Cart Operations

// Add items
$cart->add($item);

// Update quantity
$cart->updateQuantity($item->getId(), 5);

// Update any property
$cart->update($item->getId(), 'price', 29.99);

// Remove items
$cart->remove($item->getId());

// Check if item exists
if ($cart->has($item->getId())) {
    // Item exists
}

// Get specific item
$foundItem = $cart->get($item->getId());

// Clear cart
$cart->clear();

Cart Information

// Counts
$cart->totalItems(); // Total quantity of all items
$cart->totalUniqueItems(); // Number of different items
$cart->isEmpty(); // Check if cart is empty
$cart->isNotEmpty(); // Check if cart has items

// Prices
$cart->subtotal(); // Total excluding tax
$cart->tax(); // Total tax
$cart->total(); // Total including tax

// Get all items
$items = $cart->all(); // Returns CartItem[]

// Filter items
$expensiveItems = $cart->filter(fn($item) => $item->getPrice() > 50);

// Find first item matching condition
$firstElectronic = $cart->first(fn($item) => $item->get('category') === 'Electronics');

Persistence

// Manual save
$cart->save();

// Auto-save (saves automatically when cart is destroyed)
// No action needed - cart saves on __destruct if dirty

// Restore from storage
$cart->restore();

// Refresh (discard unsaved changes)
$cart->refresh();

// Check if cart has unsaved changes
if ($cart->isDirty()) {
    $cart->save();
}

Advanced Features

// Copy cart
$newCart = $cart->copy('new_cart_id');

// Merge carts
$cart1->merge($cart2);

// Export as array
$cartData = $cart->toArray();

// Export as JSON
$cartJson = $cart->toJson(JSON_PRETTY_PRINT);

// Get summary
$summary = $cart->summary();
/*
Array:
[
    'id' => 'cart_123',
    'total_items' => 5,
    'unique_items' => 3,
    'subtotal' => 99.95,
    'tax' => 8.00,
    'total' => 107.95,
    'is_empty' => false
]
*/

๐ŸŽจ Custom Storage Backend

Implement the Store interface to create custom storage:

use ModernCart\Contracts\Store;

class DatabaseStore implements Store
{
    public function __construct(
        private PDO $pdo
    ) {}

    public function get(string $cartId): string
    {
        $stmt = $this->pdo->prepare('SELECT data FROM carts WHERE id = ?');
        $stmt->execute([$cartId]);
        
        return $stmt->fetchColumn() ?: serialize([]);
    }

    public function put(string $cartId, string $data): void
    {
        $stmt = $this->pdo->prepare(
            'INSERT INTO carts (id, data) VALUES (?, ?) 
             ON DUPLICATE KEY UPDATE data = VALUES(data)'
        );
        $stmt->execute([$cartId, $data]);
    }

    public function flush(string $cartId): void
    {
        $stmt = $this->pdo->prepare('DELETE FROM carts WHERE id = ?');
        $stmt->execute([$cartId]);
    }

    public function exists(string $cartId): bool
    {
        $stmt = $this->pdo->prepare('SELECT 1 FROM carts WHERE id = ?');
        $stmt->execute([$cartId]);
        
        return $stmt->fetchColumn() !== false;
    }
}

๐Ÿงช Testing

# Run tests
composer test

# Run tests with coverage
composer test-coverage

# Run static analysis
composer analyse

# Run code style check
composer cs-check

# Fix code style
composer cs-fix

# Run all quality checks
composer quality

๐Ÿ“Š Error Handling

The library uses specific exceptions for different error conditions:

use ModernCart\Exceptions\{
    CartException,
    CartRestoreException,
    InvalidCartItemException
};

try {
    $cart->add($item);
    $cart->save();
} catch (InvalidCartItemException $e) {
    // Handle invalid item data
} catch (CartRestoreException $e) {
    // Handle restoration errors
} catch (CartException $e) {
    // Handle general cart errors
}

๐Ÿ”ง Configuration

Session Store Options

$sessionStore = new SessionStore(
    prefix: 'my_cart_' // Default: 'cart_'
);

Cookie Store Options

$cookieStore = new CookieStore(
    prefix: 'cart_',
    expiry: 2592000, // 30 days
    path: '/',
    domain: '',
    secure: false,
    httpOnly: true,
    sameSite: 'Lax'
);

File Store Options

$fileStore = new FileStore(
    storagePath: '/var/cart-storage',
    prefix: 'cart_',
    extension: '.dat'
);

// Clean up old files (older than 30 days)
$cleaned = $fileStore->cleanup(2592000);

๐ŸŽญ Migration from Legacy Cart

If migrating from the original library:

// Old way
$cart->add($cartItem);
$existingItem = $cart->find($itemId);
$existingItem->quantity += $cartItem->quantity;

// New way
$cart->add($cartItem); // Automatically handles quantity merging

// Old way
$item->price = 29.99;

// New way
$item->setPrice(29.99);
// or
$cart->update($itemId, 'price', 29.99);

๐Ÿค Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run quality checks (composer quality)
  5. Commit your changes (git commit -am 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Create a Pull Request

๐Ÿ“œ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐ŸŽ‰ Credits

  • Original cart library inspiration
  • PHP 8+ modern practices
  • Community feedback and contributions

๐Ÿ“ž Support