PHPackages                             timurturdyev/laravel-cart - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. timurturdyev/laravel-cart

ActiveLibrary

timurturdyev/laravel-cart
=========================

Shopping cart, wishlist and compare lists for Laravel

v1.0.0(today)00MITPHPPHP ^8.3CI passing

Since Jul 30Pushed todayCompare

[ Source](https://github.com/TimurTurdyev/laravel-cart)[ Packagist](https://packagist.org/packages/timurturdyev/laravel-cart)[ RSS](/packages/timurturdyev-laravel-cart/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (2)Versions (2)Used By (0)

 [![Laravel Cart](art/banner.svg)](art/banner.svg)

Laravel Cart
============

[](#laravel-cart)

Корзина, закладки и сравнение товаров для Laravel 12+ (PHP 8.3+).

Каждый список (корзина, закладки, сравнение, свои списки) - один и тот же примитив с политикой из конфига. Деньги считает только корзина, и делает это через конвейер классов-корректировок. Без магических строк, без float, без обязательных миграций.

Установка
---------

[](#установка)

```
composer require timurturdyev/laravel-cart
php artisan vendor:publish --tag=cart-config   # по желанию
```

Провайдер подхватывается автоматически через package discovery.

Быстрый старт
-------------

[](#быстрый-старт)

```
use TimurTurdyev\Cart\Facades\Cart;
use TimurTurdyev\Cart\Facades\Compare;
use TimurTurdyev\Cart\Facades\Wishlist;

$line = Cart::add($item, quantity: 2, options: ['size' => 'm']);

Cart::setQuantity($line->id, 5);
Cart::total();                // Price: ->minor(), ->decimal(), ->format()

Wishlist::toggle($item);      // первый вызов добавляет, второй убирает
Wishlist::has($item);         // для кнопки-сердечка
Wishlist::moveToCart($item);

Compare::add($item);          // лимит берется из конфига
```

`$item` - любая модель, реализующая `Purchasable`:

```
use TimurTurdyev\Cart\Contracts\Purchasable;
use TimurTurdyev\Cart\Support\Price;

class Chair extends Model implements Purchasable
{
    public function cartId(): string|int
    {
        return $this->id;
    }

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

    public function cartPrice(): Price
    {
        return Price::fromMinor($this->price);
    }
}
```

Без модели строка собирается вручную:

```
use TimurTurdyev\Cart\Line;

Cart::add(Line::of(11, 'Chair', Price::fromDecimal('19.99'), quantity: 2));
```

Идентичность строки
-------------------

[](#идентичность-строки)

Id строки = hash(id товара + нормализованные опции). Один товар с разными опциями сам раскладывается по разным строкам, составные id вручную склеивать не нужно:

```
Cart::add($item, options: ['size' => 'm']);
Cart::add($item, options: ['size' => 'l']);    // вторая строка

Cart::has($item, options: ['size' => 'm']);    // true
```

Данные вне идентичности (зафиксированная картинка, метка времени) живут в `meta`:

```
$line = Cart::add($item, meta: ['image' => $url]);

$line->meta('image');
$line->model();     // ленивый поиск модели по классу товара
```

Деньги
------

[](#деньги)

Суммы хранятся в целых минорных единицах внутри value-объекта `Price`. Конверсия в одной точке, округление half-up:

```
Price::fromMinor(1999);        // 19.99
Price::fromDecimal('19.99');   // строка парсится точно

Cart::total()->minor();        // 1999
Cart::total()->format();       // "19.99"
```

Скидки, сборы, доставка
-----------------------

[](#скидки-сборы-доставка)

```
use TimurTurdyev\Cart\Adjusters\PercentageDiscount;
use TimurTurdyev\Cart\Adjusters\Shipping;

Cart::adjust(
    new PercentageDiscount('summer', percent: 10),
    new Shipping(Price::fromMinor(1500)),
);

Cart::withoutAdjuster('summer');
Cart::totals()->breakdown();    // subtotal, каждая корректировка, total
```

В комплекте: `PercentageDiscount`, `FixedDiscount`, `PercentageFee`, `Shipping`. Корректировки применяются конвейером: каждая видит текущий total, поэтому последовательные скидки компаундятся и порядок важен. Своя корректировка - один класс:

```
use TimurTurdyev\Cart\Contracts\Adjuster;
use TimurTurdyev\Cart\Support\Totals;

final readonly class GiftWrap implements Adjuster
{
    public function name(): string
    {
        return 'gift-wrap';
    }

    public function adjust(Totals $totals): Totals
    {
        return $totals->addFee($this->name(), Price::fromMinor(300));
    }

    public function toArray(): array
    {
        return [];
    }

    public static function fromArray(array $data): static
    {
        return new self();
    }
}
```

Между запросами корректировки хранятся парами `{class, data}` и восстанавливаются с проверкой контракта. `unserialize` не используется.

Списки
------

[](#списки)

```
'lists' => [
    'cart' => ['policy' => 'append'],
    'wishlist' => ['policy' => 'toggle'],
    'compare' => ['policy' => 'toggle', 'limit' => 4],
    'viewed' => ['policy' => 'toggle', 'limit' => 20],
],
```

политикаповедение`append`повторное добавление суммирует количество`toggle`повторный `add` ничего не меняет, `toggle()` убирает`limit`новая строка сверх лимита кидает `ListLimitException`Новый тип списка - строка в конфиге, а не новый класс:

```
use TimurTurdyev\Cart\CartManager;

app(CartManager::class)->list('viewed')->toggle($item);

Cart::moveTo('wishlist', $line->id);   // отложить на потом
Wishlist::moveToCart($item);
```

Хранилище
---------

[](#хранилище)

По умолчанию session: работает сразу после установки, пустые списки не оставляют записей. Переключение на базу - одна строка конфига:

```
'storage' => 'database',
```

```
php artisan vendor:publish --tag=cart-migrations
php artisan migrate
```

При логине гостевая корзина сливается с корзиной пользователя. Стратегии: `sum` (количества складываются), `keep` (строки пользователя важнее), `replace` (гостевая заменяет).

Свой драйвер подключается снаружи, без правки пакета:

```
use TimurTurdyev\Cart\Storage\StorageManager;

app(StorageManager::class)->extend('redis', fn () => new RedisCartStorage());
```

События
-------

[](#события)

`LineAdded`, `LineUpdated`, `LineRemoved`, `ListCleared`. В каждом - имя списка и строка. Отключаются через `'events' => false`.

Переход с darryldecode/laravelshoppingcart
------------------------------------------

[](#переход-с-darryldecodelaravelshoppingcart)

Таблица соответствия API - в [UPGRADE.md](UPGRADE.md). Сохраненные корзины конвертируются командой:

```
php artisan cart:import-legacy legacy_carts --owner-column=identifier --data-column=cart_data
```

Тесты
-----

[](#тесты)

```
make check
```

Лицензия
--------

[](#лицензия)

MIT. См. [LICENSE.md](LICENSE.md).

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/42815774?v=4)[Timur](/maintainers/TimurTurdyev)[@TimurTurdyev](https://github.com/TimurTurdyev)

---

Top Contributors

[![TimurTurdyev](https://avatars.githubusercontent.com/u/42815774?v=4)](https://github.com/TimurTurdyev "TimurTurdyev (33 commits)")

---

Tags

laravelcomparecartshopping cartwishlist

### Embed Badge

![Health badge](/badges/timurturdyev-laravel-cart/health.svg)

```
[![Health](https://phpackages.com/badges/timurturdyev-laravel-cart/health.svg)](https://phpackages.com/packages/timurturdyev-laravel-cart)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M348](/packages/psalm-plugin-laravel)[wearepixel/laravel-cart

A cart implementation for Laravel

1374.8k](/packages/wearepixel-laravel-cart)[api-platform/laravel

API Platform support for Laravel

58174.6k17](/packages/api-platform-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
