Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Inventory Laravel Package

sylius/inventory

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require sylius/inventory
    

    Add the bundle to config/bundles.php (if using Symfony) or register the service provider in config/app.php (Laravel).

  2. Configuration:

    // config/inventory.php
    return [
        'driver' => env('INVENTORY_DRIVER', 'doctrine_orm'), // or 'doctrine_orm', 'array', 'custom'
        'stocks' => [
            'default' => [
                'tracking' => true, // Enable stock tracking
            ],
        ],
    ];
    
  3. First Use Case:

    • Check Stock:
      use Sylius\Component\Inventory\Repository\StockRepositoryInterface;
      
      $stockRepository = app(StockRepositoryInterface::class);
      $stock = $stockRepository->findOneBy(['productId' => 'product-123']);
      $quantity = $stock->getQuantity(); // Returns current stock quantity
      
    • Reserve Stock:
      use Sylius\Component\Inventory\Checker\StockCheckerInterface;
      use Sylius\Component\Inventory\ReservableInterface;
      
      $stockChecker = app(StockCheckerInterface::class);
      $stockChecker->check($productId, $quantity); // Throws exception if insufficient stock
      
      $reservable = app(ReservableInterface::class);
      $reservable->reserve($productId, $quantity); // Reserves stock for a transaction
      

Key Entry Points

  • Documentation: Sylius Inventory Docs
  • Entities: Product, Stock, StockEntry, InventoryUnit
  • Services: StockRepository, StockChecker, Reservable, InventoryUnitFactory

Implementation Patterns

Core Workflows

  1. Stock Management:

    • Initialization:
      $inventoryUnit = app(\Sylius\Component\Inventory\InventoryUnit::class);
      $inventoryUnit->setProductId('product-123')->setQuantity(10);
      $stockRepository->save($inventoryUnit);
      
    • Adjustments:
      $stockRepository->adjust('product-123', -2); // Decrease stock by 2
      $stockRepository->adjust('product-123', 5);  // Increase stock by 5
      
  2. Order Processing:

    • Reserve Stock for Order:
      $orderItems = collect([['product_id' => 'product-123', 'quantity' => 3]]);
      $reservable->reserveForOrder($orderItems, 'order-456');
      
    • Release Reserved Stock:
      $reservable->release('order-456'); // After order cancellation or fulfillment
      
  3. Inventory Tracking:

    • Track Stock Changes:
      $stockEntryRepository = app(\Sylius\Component\Inventory\Repository\StockEntryRepositoryInterface::class);
      $entries = $stockEntryRepository->findBy(['productId' => 'product-123'], ['createdAt' => 'DESC']);
      

Integration Tips

  • Laravel Eloquent: Use the doctrine_orm driver and map Sylius entities to Eloquent models:
    // app/Models/Product.php
    class Product extends Model implements \Sylius\Component\Inventory\Model\ProductInterface
    {
        use \Sylius\Component\Inventory\Model\ProductTrait;
    }
    
  • API Layer: Expose stock checks via API:
    Route::get('/api/stock/{productId}', function ($productId) {
        $stock = app(StockRepositoryInterface::class)->findOneBy(['productId' => $productId]);
        return response()->json(['quantity' => $stock->getQuantity()]);
    });
    
  • Event Listeners: Listen to stock changes:
    // app/Listeners/StockUpdatedListener.php
    class StockUpdatedListener
    {
        public function handle($event)
        {
            Log::info("Stock updated for product: {$event->getProductId()}");
        }
    }
    
    Register in EventServiceProvider:
    protected $listen = [
        \Sylius\Component\Inventory\Event\StockUpdated::class => [
            StockUpdatedListener::class,
        ],
    ];
    

Gotchas and Tips

Common Pitfalls

  1. Driver Mismatch:

    • Ensure the configured driver (inventory.driver) matches your setup (e.g., doctrine_orm requires Doctrine ORM).
    • Fix: Verify config/inventory.php and install required dependencies (e.g., doctrine/orm for ORM driver).
  2. Stock Tracking Disabled:

    • If tracking: false in config, stock changes won’t be logged in StockEntry.
    • Fix: Set tracking: true for audit trails.
  3. Race Conditions:

    • Concurrent stock adjustments can cause inconsistencies.
    • Fix: Use transactions or locks:
      DB::transaction(function () use ($stockRepository) {
          $stockRepository->adjust('product-123', -1);
      });
      
  4. Product ID Format:

    • Sylius expects productId as a string (e.g., 'product-123'), not an integer or UUID.
    • Fix: Normalize IDs before passing to Sylius methods.

Debugging Tips

  • Enable Logging:

    // config/inventory.php
    'logging' => [
        'enabled' => true,
        'channel' => 'inventory',
    ],
    

    Check logs for stock operations:

    tail -f storage/logs/inventory.log
    
  • Dump Stock Data:

    $stock = $stockRepository->findOneBy(['productId' => 'product-123']);
    dd($stock->getQuantity(), $stock->getReservations());
    
  • Validate Stock: Use the StockChecker to debug stock issues:

    try {
        $stockChecker->check('product-123', 5);
    } catch (\Sylius\Component\Inventory\Exception\OutOfStockException $e) {
        dd($e->getMessage()); // "Not enough stock for product-123"
    }
    

Extension Points

  1. Custom Drivers: Implement Sylius\Component\Inventory\Driver\DriverInterface for non-Doctrine storage (e.g., Redis, Elasticsearch):

    class RedisDriver implements DriverInterface
    {
        public function findStock($productId): ?StockInterface
        {
            $stock = Redis::get("stock:{$productId}");
            return $stock ? json_decode($stock, true) : null;
        }
        // ... other methods
    }
    
  2. Custom Stock Entries: Extend StockEntry to add custom fields:

    class CustomStockEntry extends \Sylius\Component\Inventory\Model\StockEntry
    {
        protected $adjustmentReason;
    
        public function setAdjustmentReason(string $reason): self
        {
            $this->adjustmentReason = $reason;
            return $this;
        }
    }
    
  3. Inventory Events: Subscribe to events for custom logic:

    // Example: Notify when stock is low
    event(new \Sylius\Component\Inventory\Event\StockUpdated($productId, $oldQuantity, $newQuantity));
    

    Listen in a service:

    public function __construct()
    {
        event(new \Sylius\Component\Inventory\Event\StockUpdated(...));
    }
    
  4. Laravel Service Provider: Override default services in AppServiceProvider:

    public function register()
    {
        $this->app->bind(
            \Sylius\Component\Inventory\Checker\StockCheckerInterface::class,
            \App\Services\CustomStockChecker::class
        );
    }
    

Performance Considerations

  • Batch Operations: Use bulk adjustments for large inventory updates:
    $stockRepository->bulkAdjust([
        'product-123' => -10,
        'product-456' => 5,
    ]);
    
  • Caching: Cache stock quantities for read-heavy applications:
    $quantity = Cache::remember("stock:product-123", now()->addHours(1), function () {
        return $stockRepository->findOneBy(['productId' => 'product-123'])->getQuantity();
    });
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky