foodcheri/routific-bundle
Symfony bundle that integrates the Routific route optimization API, providing service and configuration to submit delivery jobs and retrieve optimized routes. Simplifies wiring Routific into Symfony applications.
Reality check first: this is a Symfony bundle (foodcheri/routific-bundle), not a Laravel package, last touched in 2017, zero stars and zero dependents. It is a convenience wrapper around Routific's route-optimisation REST API. Treat it as a reference implementation of the payload shape, not as a dependency you install blindly.
Minimal steps:
composer require foodcheri/routific-bundle — expect dependency friction; the bundle will likely pull Symfony 2/3-era components that conflict with a modern Laravel (Symfony 6/7 components). If it resolves, it's because Composer negotiated old versions alongside Laravel's, which is fragile. If it does not resolve, read the source instead.DependencyInjection/ config — that's where the Routific API token parameter and the service definition live. That file tells you the entire contract: what the token config key is called and what service ID you resolve.routific/php-sdk (or a hand-rolled Guzzle call). It will almost certainly expose one meaningful method: submit a set of visits + a fleet + options, get back optimised routes. Everything else is payload marshalling.ServiceProvider that binds the wrapper with config('services.routific.token'), or (b) — my recommendation — skip the bundle and make two Http:: calls yourself, using the bundle's source as documentation for the request body.First use case worth wiring up: one depot, N delivery orders, M drivers, tomorrow's shift. Build visits from your orders table, build fleet from your drivers table, POST it, persist the returned stop sequence back onto the orders as route_position + driver_id. That is 90% of what anyone uses Routific for.
Payload construction is the real work. The bundle gives you a client; you still own the mapping. Isolate it in a dedicated class (App\Routing\RoutificPayloadBuilder or similar) rather than sprinkling arrays through controllers:
visits[]: id (your order ID, string), location with name, lat, lng, plus optional start/end (time windows), demand, priority, service_time.fleet[]: vehicle_id, start_location / end_location, capacity, shift_start / shift_end.options: traffic model, min_visits_per_vehicle, balancing, etc.Wrap the call in a queued job. Route optimisation is a multi-second HTTP round-trip against a third party. Never do it inside a request/response cycle that a user is waiting on. Pattern: order cut-off triggers OptimiseRoutesJob, job writes results to routes/route_stops tables, UI polls or is notified.
Normalise the response into your own domain. Routific returns a status plus a solution keyed by vehicle ID containing an ordered visits array. Do not let that array shape leak past your persistence layer — map it into route_stops(order_id, driver_id, sequence, eta) so downstream code (driver app, dispatch board) never knows Routific exists. This also makes swapping providers survivable.
Multi-tenant tokens. If you have multiple depots/accounts, don't rely on the bundle's single container parameter. Resolve the client per tenant from config('services.routific.*') or a DB column, and construct the wrapper with the token injected — the bundle's static/config-bound design fights you here.
Integration tip — async/polling. The SDK is synchronous and blocking. Set an explicit Guzzle timeout (30s+) and a retry with backoff on 5xx. If volumes grow, check whether you've been provisioned for Routific's async/webhook flow and bypass the SDK's blocking call.
Testing. Record one real fixture per scenario (single vehicle, multi-vehicle, infeasible) and mock your wrapper interface, not the SDK. Assert on your domain output (stops assigned, sequence monotonic), not on Routific's raw JSON.
app/Support/Routific if you must use it, and assume no security patches. Budget for replacing it with a 40-line Http::withToken(...)->post('https://api.routific.com/v1/vrp', $payload) at the first sign of trouble — the API is plain JSON and the bundle adds little beyond config plumbing.--ignore-platform-reqs or -W is how you end up debugging autoload collisions two weeks later.shift_start/shift_end and visit start/end must be consistently formatted and timezone-aware; mismatches silently produce "infeasible" responses rather than errors."51,5" instead of "51.5" will fail or misroute). Watch for number_format creeping in from your formatting layer.status in the response body, not just HTTP 200. Infeasible problems return status: "error" with a message — log the full payload alongside it or you'll be unable to reproduce.How can I help you explore Laravel packages today?