zangra/geodis-bundle
A PHP/Laravel bundle for integrating Geodis shipping services into your application, providing structured configuration and service wiring to support Geodis-related transport and logistics workflows.
Install and register the bundle
composer require zangra/geodis-bundle
Register it in config/bundles.php:
Zangra\GeodisBundle\ZangraGeodisBundle::class => ['all' => true],
If the bundle ships routes (e.g. webhook endpoint, admin UI), import them in config/routes.yaml:
zangra_geodis:
resource: "@ZangraGeodisBundle/Resources/config/routing.yaml"
Look at these files first, in order
src/DependencyInjection/Configuration.php — the authoritative list of config keys (credentials, endpoints, sandbox flag, defaults). This is where you learn what is actually configurable.src/DependencyInjection/ZangraGeodisExtension.php — which services get wired, aliases, and tagged services.src/Api/ (or src/Client/) — the HTTP client wrapper around the Geodis REST/JSON endpoints. Confirm which calls are covered (rate, create shipment, label, tracking) versus missing.src/Sylius/Shipping/Calculator/ — whether a CalculatorInterface implementation is provided for Sylius shipping method rate calculation.README.md and any Tests/ fixtures — often the only working example of config shape.Configure credentials
# config/packages/zangra_geodis.yaml
zangra_geodis:
environment: test # or prod / sandbox — check config tree for the exact key
credentials:
customer_id: '%env(GEODIS_CUSTOMER_ID)%'
api_key: '%env(GEODIS_API_KEY)%'
# agency / contract numbers if required by your Geodis account
First use case: rate calculation on a Sylius shipping method
Create a shipping method in the Sylius admin, choose the Geodis calculator (if provided), and attach a matching shipping method rule (zone + weight/amount). Verify the calculator is tagged with sylius.shipping_calculator by dumping the container: bin/console debug:container --tag=sylius.shipping_calculator.
Wrap the bundle's client behind your own interface. Because the package has single-digit contribution history, treat its API client as a vendor detail. Inject Zangra\GeodisBundle\...\Client into your own GeodisGateway interface and mock your interface in tests. This lets you swap to a raw HttpClient call if the bundle goes stale.
Label generation on shipment transitions. The idiomatic Sylius hook is the state machine, not a controller:
// services.yaml
App\EventListener\GeodisLabelListener:
tags:
- { name: kernel.event_listener, event: sylius.shipment.post_transition, method: onShipmentTransition }
Trigger label creation when the shipment transitions ready → shipped. Store the returned label URL/tracking number on the shipment (via a custom field on Shipment or the shipment.metadata map) — do not block the transition on a Geodis HTTP failure; queue it instead.
Queue outbound calls with Symfony Messenger. Rate calls during checkout are latency-sensitive; label creation is not. Route CreateGeodisLabelMessage through your async transport so a Geodis 5xx doesn't fail checkout. Sylius already has Messenger wired in recent versions — reuse it rather than adding a separate queue.
Webhook / tracking sync pattern. Geodis typically pushes tracking updates via callback or you poll the tracking endpoint. If the bundle exposes a route, secure it (shared secret in header or IP allowlist — Geodis won't sign by default). Otherwise schedule app:geodis:sync-tracking as a messenger:consume job and update the shipment state machine from the result.
Rate caching by address signature. Geodis rate responses are stable for ~minutes. Cache on a hash of postcode|country|weight|service with a short TTL (5–15 min) using Symfony Cache. This is the single biggest win in checkout performance.
Test against recorded fixtures. Geodis REST responses have a fairly idiosyncratic envelope. Capture a handful of real sandbox responses (rate, label, tracking, error) into tests/fixtures/ and drive both your gateway and the bundle client with Symfony's MockHttpClient returning those bodies. This is the only way to get the error-shape handling right.
Multi-channel / multi-agency. If your Geodis contract has multiple agencies (per warehouse or per store), key the client config by channel. The bundle likely assumes one credential set; you'll instantiate multiple clients or decorate the factory.
The package is effectively pre-1.0. Zero stars, zero dependents, one release as of late 2025. Read composer.json for the exact Symfony/Sylius version constraints before adding it to an existing app — a bundle written against Sylius 1.x CalculatorInterface may not work on 2.x without a fork. Pin the version in composer.json and commit composer.lock.
Sandbox vs production is usually a host swap, not a flag. Check Configuration.php for how environment is consumed. A common failure mode is sandbox credentials hitting the production host (or vice versa) and getting a 401 that looks like a credential error. Log the resolved base URI on boot.
Error envelopes are inconsistent. Geodis typically returns JSON errors with a non-standard shape alongside a non-2xx status. Don't trust $response->getStatusCode() alone — inspect the body and log the raw payload on any non-success. Add a Retry-After-aware retry decorator on top of the client for 429/5xx.
Idempotency on label creation. Retrying a label request after a timeout can duplicate a parcel and a charge. Persist a client-generated reference (order number + shipment id) before the call, and on retry first query for an existing label by that reference before re-creating. If the bundle doesn't expose a "find by reference" call, you'll need to add it.
Address fields are stricter than Sylius. Geodis expects postcode/city/country with particular casing and country codes. French/EU addresses with missing state or street2 commonly fail validation. Add a small normalizer service translating Sylius\Component\Addressing\Model\Address → Geodis payload; do this in your own class rather than editing vendor code so upgrades are safe.
Extension points to prefer over editing the bundle:
App\Geodis\DecoratingClient implementing the same interface, decorates: zangra_geodis.client.Debugging checklist when a rate returns 0 or 500:
bin/console debug:config zangra_geodis — confirm credentials actually resolve from env (empty env vars are a classic).bin/console debug:container --tag=sylius.shipping_calculator — confirm the calculator is registered.framework.http_client.default_options.trace or a profiler listener to see the actual outbound request body; Geodis errors frequently reference a field your normalizer dropped.Vendor risk mitigation. Because the repository is unmaintained-by-popularity, plan for one of:
private-vendor/ path repository (recommended) and apply patches directly,Either way, add a smoke test that hits the sandbox once in CI weekly — the API contract drift is the thing that will bite you, not the PHP code.
How can I help you explore Laravel packages today?