elcodi/shipping-bundle
Symfony shipping bundle from the Elcodi e-commerce suite, providing shipping rule and method management for handling order shipments. MIT licensed and read-only; contributions and issues go through the main elcodi/elcodi repository.
Read the compatibility reality first. elcodi/shipping-bundle is a read-only split of the Elcodi monorepo, last tagged in Feb 2016, archived, with zero dependents. It targets Symfony 2.x and PHP 5.x/7.0-era APIs. You will only get value from it if you are maintaining or migrating an existing Elcodi shop — do not start a new project on it.
dev-master for the "last commit", but on a dead repo that is the worst option. Use the last stable tag (^1.0 range) and commit composer.lock.app/AppKernel.php after its dependencies (Core, Cart, Currency, Geo/Zone, Media if you use method images, Rule for expressions):
new Elcodi\Bundle\ShippingBundle\ElcodiShippingBundle(),
src/Elcodi/Bundle/ShippingBundle/ — DI extension, Resources/config/*.yml (service ids), Resources/config/doctrine/*.orm.yml (schema), form types, Twig views.src/Elcodi/Component/Shipping/ — entities (ShippingMethod, Carrier, Warehouse, ranges, ShippingRule), factories, repositories.Tests/Functional/ — the best documentation for how services are actually wired.elcodi.<entity>_factory / elcodi.<entity>_manager / elcodi.repository.<entity>; confirm the exact ids in Resources/config/services.yml before copying snippets:
$carrier = $this->get('elcodi.carrier_factory')->create();
$carrier->setName('MRW')->setEnabled(true);
$this->get('elcodi.carrier_manager')->save($carrier);
$method = $this->get('elcodi.shipping_method_factory')->create();
$method->setName('Standard 24h')->setCarrier($carrier)->setEnabled(true);
// ranges: from/to define the band the cart total or weight falls into
$method->addRange($rangeFactory->create()->setFrom(0)->setTo(5));
$this->get('elcodi.shipping_method_manager')->save($method);
$cart->setShippingMethod($method); // cart recalculates totals from here
Always build entities through factories. Elcodi entities have defaults (enabled flags, empty collections, generated ids) applied by the factory create(). Constructing entities with new skips those and produces rows that fail silently in listings or rule evaluation.
Manager for writes, repository for reads. elcodi.<entity>_manager wraps the Doctrine EntityManager and dispatches Elcodi's pre/post save/delete events. Repositories (elcodi.repository.shipping_method, elcodi.repository.carrier, …) expose the read side and custom finders. Keep that split: bypassing the manager means listeners (image handling, event-driven cache busting) never fire.
Model shipping cost as ranges, not code. A shipping method owns a collection of range entities; the applicable price is the range whose from/to covers the cart's weight or amount. Add ranges via addRange() and persist through the method manager, not by saving ranges independently — the owning side is the method.
Eligibility belongs in ShippingRule, not controllers. Rules carry an expression string evaluated by the rule/expression-language service. Use this for "free over €50", "only for zone X", "max 20 kg" instead of branching in your checkout controller. If you need new vocabulary, register custom functions on the expression language through the rule bundle rather than editing the shipping bundle.
Integrate at the cart boundary. The shipping bundle is a dumb data provider: you set the method on the cart/order, and the cart's cost calculator reads ranges back. If you need per-order overrides (manual discount, negotiated rate), decorate the shipping cost calculator service in your app's services.yml instead of forking the bundle.
Reuse the shipped form types (Form/Type/) for admin CRUD. They already wire the carrier/warehouse/ranges relationships; hand-rolled forms usually miss the collection by_reference setting and end up orphaning range rows.
Override entities via container parameters, not by editing vendor. Elcodi bundles resolve entity classes from parameters (elcodi.entity.*.class-style keys in the bundle's configuration). Subclass the base entity, point the parameter at your class, and extend the Doctrine mapping in your own bundle so your extra columns survive schema updates.
getRequest()-era APIs. If you must keep it, fork it internally and add replace in composer so transitive constraints resolve.resolve_target_entities is mandatory. Because the component ships interfaces, Doctrine needs concrete Carrier, Warehouse, and ShippingMethod mappings in your app config. Miss this and you get "target entity … does not exist" at schema time or Class not found on hydration.0 — it will not throw. Boundary semantics (from/to inclusivity, null for open-ended) are the usual culprit. Add an explicit test for the exact weight/amount at each boundary.EntityManager saves skip events. If images or slugs are missing after a bulk import, that is why. Use the manager's save(), or dispatch the equivalent events yourself.fetch="EAGER"/join fetch in a custom repository finder if you have many methods.app/console debug:container elcodi.shipping (or plain container:debug on older versions), doctrine:schema:validate, and doctrine:mapping:info will resolve 90% of "service not found" and mapping errors faster than reading the source.Resources/views → subclassing entities. Patching the vendor copy is a last resort and will be lost on the next composer install.How can I help you explore Laravel packages today?