laravelshoppingcart

repository·master·Indexed 23 days ago

https://github.com/darryldecode/laravelshoppingcart

A shopping cart implementation for the Laravel framework supporting session-based storage, item attributes, and user-specific cart binding. It provides functionality to manage items via Cart::add(), update quantities, apply cart-wide or item-specific conditions (such as taxes and discounts), and associate cart items with Eloquent models. The library supports multiple cart instances and allows for custom database-backed storage implementations.

Tokens
7.7K
Snippets
15
Records
32
Agent score
79%

What's inside darryldecode/laravelshoppingcart

  1. How to bind the cart to a specific user session

    master

    By default, the cart uses a single session key. To manage different carts for different users (e.g., in a multi-user environment), you must bind the cart to a unique identifier (like a User ID) using \Cart::session($sessionKey) before calling any other cart methods. This ensures the cart knows which user's data to manipulate.

    Example: \Cart::session($userId);

  2. How CartCondition works

    master

    A CartCondition is an object used to modify the cart's value via taxes, shipping, discounts, or other logic.

    When used as a Cart-based condition, it requires a target (subtotal or total) and an optional order to define calculation sequence.

    When used as an Item-based condition, it is passed within the product array during Cart::add() or via Cart::addItemCondition(). It modifies the price of that specific item before the cart's subtotal is calculated.

  3. Implement custom database storage for the cart

    master

    You can replace the default session storage with a database-backed storage by creating a custom storage class. The storage class injected into the Cart instance must implement has($key), get($key), and put($key, $value) methods.

    To implement database storage:

    1. Create a migration for a storage table (e.g., cart_storage) with an id (primary key) and cart_data (longText).
    2. Create an Eloquent Model to manage the data, using accessors/mutators to serialize and unserialize the cart_data attribute.
    3. Create a storage class (e.g., DBStorage) that uses the Model to fulfill the required interface.
    class DBStorage {
        public function has($key)
        {
            return DatabaseStorageModel::find($key);
        }
    
        public function get($key)
        {
            if($this->has($key))
            {
                return new CartCollection(DatabaseStorageModel::find($key)->cart_data);
            }
            else
            {
                return [];
            }
        }
    
        public function put($key, $value)
        {
            if($row = DatabaseStorageModel::find($key)) {
                $row->cart_data = $value;
                $row->save();
            }
            else {
                DatabaseStorageModel::create([
                    'id' => $key,
                    'cart_data' => $value
                ]);
            }
        }
    }
  4. Configure the Shopping Cart Service Provider and Alias

    master

    To use the package, you must register the Service Provider and the Facade in your config/app.php file.

    1. Add the Service Provider to the providers array:

    Darryldecode\Cart\CartServiceProvider::class

    1. Add the Alias to the aliases array:

    'Cart' => Darryldecode\Cart\Facades\CartFacade::class

    1. (Optional) To publish the configuration file for full control, run:

    php artisan vendor:publish --provider="Darryldecode\Cart\CartServiceProvider" --tag="config"

    php artisan vendor:publish --provider="Darryldecode\Cart\CartServiceProvider" --tag="config"
  5. Configure the default cart storage

    master

    To set a custom storage class as the default for the entire application, first publish the configuration file:

    php artisan vendor:publish --provider="Darryldecode\Cart\CartServiceProvider" --tag="config"

    Then, open config/shopping_cart.php and update the 'storage' key with the fully qualified class name of your custom storage class.

  6. Create multiple cart instances

    master

    To prevent conflicts when using multiple carts on the same page (e.g., a main cart and a separate wishlist), you can register custom cart instances via a Service Provider. Each instance requires a unique instanceName and a unique session_key to store its items separately in the session.

    For Laravel 5.4 or newer, use the singleton method in your Service Provider's register() method.

    use Darryldecode\Cart\Cart;
    use Illuminate\Support\ServiceProvider;
    
    class WishListProvider extends ServiceProvider
    {
        public function register()
        {
            $this->app->singleton('wishlist', function($app)
            {
                $storage = $app['session'];
                $events = $app['events'];
                $instanceName = 'cart_2';
                $session_key = '88uuiioo99888';
                
                return new Cart(
                    $storage,
                    $events,
                    $instanceName,
                    $session_key,
                    config('shopping_cart')
                );
            });
        }
    }
  7. Associate a model with a cart item

    master

    You can link a cart item to an Eloquent model (e.g., a Product model) using the associate() method or by providing the associatedModel key in the item array. Once associated, you can access the model instance directly via the $item->model property when iterating through the cart content.

    This association must be defined at the moment the item is added to the cart.

    // Option 1: Using the associate() method
    $cartItem = Cart::add(455, 'Sample Item', 100.99, 2, array())->associate('Product');
    
    // Option 2: Using the array format
    Cart::add(array(
        'id' => 456,
        'name' => 'Sample Item',
        'price' => 67.99,
        'quantity' => 4,
        'attributes' => array(),
        'associatedModel' => 'Product'
    ));
    
    // Accessing the model during iteration
    foreach(Cart::getContent() as $row) {
        echo 'Product name: ' . $row->model->name;
    }
  8. Apply conditions to the whole cart

    master

    You can apply conditions (like tax, shipping, or discounts) to the entire cart. These conditions can target either the subtotal or the total.

    • Target subtotal: The condition is applied when getSubTotal() is called. Note that getTotal() will also be affected because it depends on the subtotal.
    • Target total: The condition is applied only when getTotal() is called.

    Use the order parameter to control the sequence of calculation for cart-based conditions (higher numbers are applied later). If no order is defined, it defaults to 0.

    // Add a condition targeting the subtotal
    $condition = new \Darryldecode\Cart\CartCondition(array(
        'name' => 'VAT 12.5%',
        'type' => 'tax',
        'target' => 'subtotal',
        'value' => '12.5%',
        'attributes' => array(
        	'description' => 'Value added tax',
        	'more_data' => 'more data here'
        )
    ));
    
    Cart::condition($condition);
    
    // Or add multiple conditions at once
    Cart::condition([$condition1, $condition2]);
  9. Create multiple cart instances (e.g., Wishlist) with custom storage

    master

    If you need multiple independent cart instances (like a separate 'Wishlist'), you can register them as singletons in a Laravel Service Provider. This allows you to inject a specific storage class and unique identifiers for each instance.

    use Darryldecode\Cart\Cart;
    use Illuminate
    Support\ServiceProvider;
    
    class WishListProvider extends ServiceProvider
    {
        public function register()
        {
            $this->app->singleton('wishlist', function($app)
            {
                $storage = new DBStorage(); // Your custom storage
                $events = $app['events'];
                $instanceName = 'cart_2';
                $session_key = '88uuiioo99888';
                return new Cart(
                    $storage,
                    $events,
                    $instanceName,
                    $session_key,
                    config('shopping_cart')
                );
            });
        }
    }
  10. Apply conditions to specific items

    master

    You can apply conditions (like item-specific sales or promos) to individual products. Unlike cart-based conditions, per-item conditions do not require a target parameter.

    To apply conditions to an item, include them in the conditions array within the product data when calling Cart::add().

    Important: All per-item conditions must be added before calling Cart::getSubTotal() to ensure they are included in the calculation.

    $saleCondition = new \Darryldecode\Cart\CartCondition(array(
        'name' => 'SALE 5%',
        'type' => 'tax',
        'value' => '-5%',
    ));
    
    $item = array(
        'id' => 456,
        'name' => 'Sample Item 1',
        'price' => 100,
        'quantity' => 1,
        'attributes' => array(),
        'conditions' => [$saleCondition]
    );
    
    Cart::add($item);
  11. Install the Laravel Shopping Cart

    master

    Install the package via Composer depending on your Laravel version.

    For Laravel 5.1~: composer require "darryldecode/cart:~2.0"

    For Laravel 5.5, 5.6, 5.7, or 9: composer require "darryldecode/cart:~4.0" or composer require "darryldecode/cart"

    composer require "darryldecode/cart:~4.0"
  12. Implement cache-based storage with cookie persistence

    master

    You can leverage Laravel's Cache (Redis, Memcached, etc.) for storage. To ensure the cart persists beyond the session lifetime (e.g., for 30 days), you can combine Cache storage with a Cookie to store a unique cart_id on the client side.

    namespace App\Cart;
    
    use Carbon\Carbon;
    use Cookie;
    use Darryldecode\Cart\CartCollection;
    
    class CacheStorage
    {
        private $data = [];
        private $cart_id;
    
        public function __construct()
        {
            $this->cart_id = \Cookie::get('cart');
            if ($this->cart_id) {
                $this->data = \Cache::get('cart_' . $this->cart_id, []);
            } else {
                $this->cart_id = uniqid();
            }
        }
    
        public function has($key)
        {
            return isset($this->data[$key]);
        }
    
        public function get($key)
        {
            return new CartCollection($this->data[$key] ?? []);
        }
    
        public function put($key, $value)
        {
            $this->data[$key] = $value;
            \Cache::put('cart_' . $this->cart_id, $this->data, Carbon::now()->addDays(30));
    
            if (!Cookie::hasQueued('cart')) {
                Cookie::queue(
                    Cookie::make('cart', $this->cart_id, 60 * 24 * 30)
                );
            }
        }
    }