Installation
composer require sylius/shipping
Add the required database migrations:
php artisan vendor:publish --provider="Sylius\Shipping\ShippingServiceProvider" --tag="migrations"
php artisan migrate
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
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);
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.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);
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 }
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 }
// 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);
Expose methods via API:
use Sylius\Component\Shipping\Resolver\ShippingMethodResolverInterface;
$resolver = $this->container->get(ShippingMethodResolverInterface::class);
$availableMethods = $resolver->getAvailableMethods($shipment);
return response()->json($availableMethods);
Shipment to Order via OrderItem → ShipmentUnit.PromotionActions.Shipment status (e.g., shipped, ready) to trigger payment workflows.OR/AND logic:
rules: ['sylius.shipping.rule.country', 'sylius.shipping.rule.min_order']
ShippingMethod categories to group methods (e.g., fedex, ups).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());
}
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));
}
Configuration Overrides
services.yaml may override Sylius defaults.sylius_shipping namespace explicitly:
sylius.shipping.calculator.custom:
# ...
Calculator Dependencies
WeightCalculator).public function __construct(private WeightCalculatorInterface $weightCalculator) {}
Rule Evaluation Order
priority in tags to control order:
tags:
- { name: sylius.shipping_method_rule, priority: 100 }
Shipment Units vs. Order Items
OrderItem → ShipmentUnit can break calculations.ShipmentCreator service to automate this:
$shipment = $this->shipmentCreator->createFromOrder($order);
Money Precision
0.1 + 0.2 !== 0.3).Sylius\Component\Currency\Money and avoid direct arithmetic.Circular Dependencies
RuleValidator.How can I help you explore Laravel packages today?