elcodi/cart-shipping
Cart Shipping Component is part of the Elcodi e-commerce suite for Symfony, providing shipping calculation and cart shipping logic as a reusable PHP component under the MIT license. Read-only repository; use the main elcodi/elcodi package for issues and pull requests.
This is an archived, read-only, end-of-life component (last release Feb 2016). Before writing any integration code, confirm two things:
elcodi/elcodi, not this repo.Install
composer require elcodi/cart-shipping
If Composer struggles with abandoned metadata or version conflicts, add it as a VCS repository from your own fork, or copy the component source into src/ and register the namespace in composer.json (autoload.psr-4).
Where to look first
src/Elcodi/Component/CartShipping/ in the main elcodi/elcodi monorepo — the read-only split repo is a mirror.Services/ first (the actual behavior), then Entity/ (the Cart ↔ ShippingMethod/Range link), then Factory/ and Resources/config/ (Doctrine mapping and service definitions).src/Elcodi/Bundle/ in the monorepo to see how the component is wired into CartBundle/ShippingBundle. There may be no standalone CartShippingBundle, so treat the component as glue rather than a self-contained bundle.elcodi.io/docs may be dead; the most reliable usage examples are in the monorepo's test suites. Search the whole repo for CartShipping.First use case
Attach a chosen shipping method/range to a cart and record its cost so it can be added to cart totals. Typical flow: customer selects a shipping option → you create a CartShipping from the factory → persist it → roll the amount into the cart's shipping total. Class names vary, but expect something close to:
$cartShipping = $cartShippingFactory->create();
$cartShipping
->setCart($cart)
->setShippingMethod($method)
->setShippingRange($range)
->setAmount($range->getPrice());
$cartShippingManager->save($cartShipping);
$cart->setShippingAmount($cartShipping->getAmount());
$cartManager->save($cart);
1. Treat it as a link, not a calculator. Cost logic (weight bands, zones, free-shipping rules) belongs to the Shipping component and its ranges/rules. CartShipping persists which option the cart chose and what it costs. Don't put pricing logic here.
2. Recalculate on cart change. Hook into the Cart component's events (load/pre-load/change events, e.g. CartEvents::*) to re-resolve shipping whenever quantities, coupons, or addresses change:
class CartShippingRecalculator
{
public function onCartChange(CartEvent $event)
{
$cart = $event->getCart();
$cartShipping = $this->cartShippingRepository->findOneByCart($cart);
if (!$cartShipping) {
return;
}
// Re-resolve the range for the current cart state
$amount = $this->shippingResolver->resolveAmount($cart, $cartShipping->getShippingMethod());
$cartShipping->setAmount($amount);
$this->cartShippingManager->save($cartShipping);
$cart->setShippingAmount($amount);
}
}
3. Decorate, don't fork. Old Elcodi services are named and public; you can override behavior without touching vendor code:
services:
app.cart_shipping_manager:
decorates: elcodi.cart_shipping_manager
arguments: ['@app.cart_shipping_manager.inner']
Useful for adding free-shipping thresholds, logging, or forcing recalculation.
4. Custom shipping rules via the Shipping component. Implement the Shipping rule interface and register it; CartShipping will store the resulting range. Keep the custom rule and the cart persistence concerns separate.
5. Fixtures and tests with factories. The factory classes make it easy to build CartShipping objects in isolation. For integration tests, use KernelTestCase and the real manager/repository rather than mocking Doctrine.
6. Checkout orchestration. In your checkout flow, decide the order: resolve method → create/update CartShipping → recalculate cart totals → persist cart. Persisting in a different order is the most common source of stale totals.
doctrine.orm.mappings manually and verify the table name doesn't collide with your own shipping tables.cart_id. Enforce "one CartShipping per cart" in your manager — update the existing row instead of creating a new one on every selection.cart.shippingAmount correct. Log recalculations in dev to catch missed hooks.CartShipping entity alongside $cart->getShippingAmount() after each step; check Doctrine's unit of work if a changed amount isn't flushed. Old code often relies on explicit save() calls rather than cascade.bin/console debug:container to confirm wiring.How can I help you explore Laravel packages today?