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

Shipping Laravel Package

sylius/shipping

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require sylius/shipping
    

    Add the required database migrations:

    php artisan vendor:publish --provider="Sylius\Shipping\ShippingServiceProvider" --tag="migrations"
    php artisan migrate
    
  2. First Use Case: Basic Shipping Method Define a shipping method via configuration:

    # config/packages/sylius_shipping.yaml
    sylius_shipping:
        options:
            shipping_methods:
                standard:
                    name: 'Standard Shipping'
                    calculator: 'sylius.shipping.calculator.flat_rate'
                    calculator_configuration:
                        amount: 10.00
    
  3. Quick Test

    use Sylius\Component\Shipping\Model\ShipmentInterface;
    use Sylius\Component\Shipping\Repository\ShippingMethodRepositoryInterface;
    
    $shipment = new class implements ShipmentInterface { /* ... */ };
    $shippingMethodRepository = $this->container->get(ShippingMethodRepositoryInterface::class);
    $method = $shippingMethodRepository->findOneBy(['code' => 'standard']);
    
    $calculator = $this->container->get('sylius.shipping.calculator.flat_rate');
    $cost = $calculator->calculate($shipment, $method);
    

Key Entry Points

  • sylius_shipping.yaml: Central configuration for methods, rules, and calculators.
  • ShippingMethod: Core model for defining shipping options.
  • Shipment: Represents a delivery order with units (items).
  • ShippingMethodRepository: Fetch available methods dynamically.

Implementation Patterns

Core Workflows

1. Defining Shipping Methods

Dynamic Configuration:

sylius_shipping:
    options:
        shipping_methods:
            express:
                name: 'Express (2-3 days)'
                calculator: 'sylius.shipping.calculator.per_item'
                calculator_configuration:
                    price_per_item: 5.00
                enabled: true

Programmatic Creation:

$method = new ShippingMethod();
$method->setCode('custom');
$method->setName('Custom Shipping');
$method->setCalculator('sylius.shipping.calculator.fixed_total');
$method->setConfiguration(['amount' => 20.00]);
$em->persist($method);

2. Shipping Rules (Filtering Methods)

Use ShippingMethodEligibilityChecker to restrict methods:

sylius_shipping:
    options:
        shipping_methods:
            international:
                name: 'International'
                calculator: 'sylius.shipping.calculator.weight_based'
                rules: ['sylius.shipping.rule.country']
                configuration:
                    rules_configuration:
                        country: ['US', 'CA']

Custom Rule Example:

class MinimumOrderRule implements ShippingMethodRuleInterface {
    public function isEligible(ShipmentInterface $shipment, ShippingMethodInterface $method): bool {
        $total = $shipment->getTotal(); // Assume a getTotal() method exists
        return $total >= 50.00;
    }
}

Register the rule in services.yaml:

sylius.shipping.rule.minimum_order:
    class: App\Rule\MinimumOrderRule
    tags:
        - { name: sylius.shipping_method_rule }

3. Calculators (Dynamic Pricing)

Built-in Calculators:

  • flat_rate: Fixed cost (e.g., $10).
  • per_item: Cost per item (e.g., $5/item).
  • weight_based: Cost based on shipment weight.
  • fixed_total: Total cart-based cost.

Custom Calculator:

class DiscountedCalculator implements ShippingCalculatorInterface {
    public function calculate(ShipmentInterface $shipment, ShippingMethodInterface $method): Money {
        $baseCost = parent::calculate($shipment, $method); // Extend base calculator
        $discount = $shipment->getDiscount() ?? 0;
        return $baseCost->subtract($discount);
    }
}

Register in services.yaml:

sylius.shipping.calculator.discounted:
    class: App\Calculator\DiscountedCalculator
    arguments:
        - '@sylius.shipping.calculator.flat_rate' # Decorate existing calculator
    tags:
        - { name: sylius.shipping_calculator }

4. Shipment Processing

// Create a shipment
$shipment = new Shipment();
$shipment->setCustomer($customer);
$shipment->setShippingAddress($address);

// Add items (units)
foreach ($orderItems as $item) {
    $unit = new ShipmentUnit();
    $unit->setProductVariant($item->getVariant());
    $unit->setQuantity($item->getQuantity());
    $shipment->addUnit($unit);
}

// Calculate available methods
$eligibleMethods = $this->shippingMethodEligibilityChecker->getEligibleMethods($shipment);

// Select and calculate cost
$method = $eligibleMethods->first();
$cost = $this->shippingCalculator->calculate($shipment, $method);

5. API/Checkout Integration

Expose methods via API:

use Sylius\Component\Shipping\Resolver\ShippingMethodResolverInterface;

$resolver = $this->container->get(ShippingMethodResolverInterface::class);
$availableMethods = $resolver->getAvailableMethods($shipment);
return response()->json($availableMethods);

Integration Tips

With Sylius Ecosystem

  • Orders: Link Shipment to Order via OrderItemShipmentUnit.
  • Promotions: Apply shipping discounts via PromotionActions.
  • Payments: Use Shipment status (e.g., shipped, ready) to trigger payment workflows.

With Custom Logic

  • Dynamic Rules: Combine rules with OR/AND logic:
    rules: ['sylius.shipping.rule.country', 'sylius.shipping.rule.min_order']
    
  • Multi-Carrier: Use ShippingMethod categories to group methods (e.g., fedex, ups).

Testing

  • Unit Test Calculators:
    public function testFlatRateCalculator() {
        $shipment = $this->createMock(ShipmentInterface::class);
        $method = $this->createMock(ShippingMethodInterface::class);
        $method->method('getConfiguration')->willReturn(['amount' => 10.00]);
    
        $calculator = new FlatRateCalculator();
        $this->assertEquals('10.00', $calculator->calculate($shipment, $method)->getAmount());
    }
    
  • Integration Test Rules:
    public function testCountryRule() {
        $shipment = new Shipment();
        $shipment->setShippingAddress(new Address(['countryCode' => 'US']));
        $method = new ShippingMethod(['configuration' => ['rules_configuration' => ['country' => ['US']]]]);
    
        $rule = new CountryRule();
        $this->assertTrue($rule->isEligible($shipment, $method));
    }
    

Gotchas and Tips

Pitfalls

  1. Configuration Overrides

    • Issue: Custom services.yaml may override Sylius defaults.
    • Fix: Use sylius_shipping namespace explicitly:
      sylius.shipping.calculator.custom:
          # ...
      
  2. Calculator Dependencies

    • Issue: Calculators may require external services (e.g., WeightCalculator).
    • Fix: Inject dependencies via constructor:
      public function __construct(private WeightCalculatorInterface $weightCalculator) {}
      
  3. Rule Evaluation Order

    • Issue: Rules are evaluated in declaration order. Use priority in tags to control order:
      tags:
          - { name: sylius.shipping_method_rule, priority: 100 }
      
  4. Shipment Units vs. Order Items

    • Issue: Forgetting to map OrderItemShipmentUnit can break calculations.
    • Fix: Use a ShipmentCreator service to automate this:
      $shipment = $this->shipmentCreator->createFromOrder($order);
      
  5. Money Precision

    • Issue: Floating-point errors in calculators (e.g., 0.1 + 0.2 !== 0.3).
    • Fix: Use Sylius\Component\Currency\Money and avoid direct arithmetic.
  6. Circular Dependencies

    • Issue: Shipping methods referencing each other in rules.
    • Fix: Validate rules in a separate pass or use a RuleValidator.

Debugging Tips

  1. Log Eligible Methods
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.
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
spatie/mailcoach-vapor
spatie/laravel-javascript-views