canaltp/navitia-bundle
Symfony bundle that integrates the Navitia API into your application, providing services and configuration to query public transport journey planning, schedules, and network data from Navitia coverage.
Architecture fit — poor, and the framing is wrong. canaltp/navitia-bundle is a Symfony bundle, not a Laravel package. Its integration surface is Symfony's bundle/DI machinery: a Bundle subclass registered in config/bundles.php (or AppKernel), a DependencyInjection/*Extension that loads service definitions, and a Configuration tree that maps YAML config into constructor arguments for the Navitia API client. Laravel has no analogue for any of that — service providers, the config/ repository, and the container's autowiring are structurally different. Bundles are not portable to Laravel; only the code they wire together is.
What is potentially reusable is the underlying concern: an HTTP client for the Navitia journey-planning API (coverage-scoped endpoints for journeys, places, stop areas, departures, route schedules, isochrones). That logic is typically a thin Guzzle wrapper plus DTOs — which we would reimplement in a Laravel service provider in well under a day. The bundle adds configuration ergonomics, not capability.
Integration feasibility — not feasible as a dependency. Three blockers, in order of severity:
build(), boot(), or DI extension. Even if installed, it is inert dead weight.symfony/console, symfony/http-foundation, symfony/routing, symfony/process, etc. to the 6.x/7.x line. A bundle of this vintage will constrain symfony/framework-bundle and/or symfony/http-kernel to 2.8/3.x and PHP to ^5.6|^7.0. composer require will fail outright, and symfony/framework-bundle would drag an entire parallel framework into vendor/ regardless. Verify with composer why-not laravel/framework canaltp/navitia-bundle before spending further time.Technical risk — high if adopted, low if used as reference. Adopting it means an unpatchable transitive dependency (no maintainer, no CVE response path) sitting in a PHP application we are accountable for. Reading it as documentation is nearly free.
The domain risk is separate and survives reimplementation: Navitia is an external SaaS with per-token quotas and coverage-scoped data. Journey planning is a hard real-time dependency — p95 latency hundreds of milliseconds to a geographically distant endpoint, 404s for unknown/discontinued coverage IDs, and JSON shape drift across API versions.
Key questions
navitia.io, token + quota) or self-hosted Navitia? Self-hosting is a multi-service deployment with GTFS ingestion and PostgreSQL — an infrastructure programme, not a library choice.Verdict: do not install. Use the bundle's source as a specification for endpoint shapes and parameter names, and implement a first-party Laravel integration.
Stack fit — reimplement, don't bridge. Laravel's Http client (Guzzle underneath) covers everything the bundle's transport layer does. The idiomatic shape is:
config/navitia.php — base URL, token, default coverage, timeout, retry policy.NavitiaClient class taking those values via constructor injection.NavitiaServiceProvider registering it as a singleton and publishing the config.Navitia facade for ergonomics, plus a handful of typed DTOs (Journey, Section, Place, Departure) only for the fields we actually render.Exception hierarchy mapping HTTP status → domain error (CoverageNotFound, QuotaExceeded, UpstreamUnavailable).This is roughly a day of work and yields code we own, test with Http::fake(), and can patch.
Migration path. There is no live integration to migrate from — nothing depends on this bundle. If we are porting behaviour from an existing Symfony service, the sequence is: (1) inventory the bundle's configured parameters and the call sites that consume its services; (2) pin the Navitia API version the legacy app was calling; (3) reimplement calls against that version; (4) run both against a fixed set of recorded fixtures and diff the DTOs; (5) cut over behind a feature flag.
Compatibility. Requirements to validate before writing code: PHP version supported by the Navitia API's JSON contract (not a concern), TLS and outbound egress from the Laravel host to the Navitia endpoint, token issuance and rotation process, and whether the client must honour a specific Accept/version header. None of these are inherited from the bundle — they are ours to establish.
Sequencing
composer why-not sanity check to formally close out the bundle option (30 min, produces an artefact for the decision log).Http::fake() tests.Maintenance — favourable, because nothing is inherited. We own ~300 lines instead of depending on an unmaintained bundle. The maintenance burden shifts from "track a dead package's compatibility with future Laravel/Symfony releases" to "track the Navitia API's changelog," which we would have to do anyway. The bundle offered no protection against that and would have actively obstructed it by pinning stale Symfony components. Budget a recurring line item for API version review, and a fixture-refresh job so contract drift surfaces in CI rather than production.
Support — no upstream. Zero dependents and no maintainer means no issue tracker to escalate to, no security advisories, no fix for a PHP 8.x incompatibility. If we had adopted it, the only exit would be a fork — which is a reimplementation with extra steps and a worse starting point. On the Navitia side, support depends on the chosen topology: navitia.io SaaS has a commercial relationship and a quota policy to negotiate; self-hosted Navitia means we are the operator, with no vendor to call.
Scaling. The integration is a thin HTTP client, so scaling is dominated by the upstream. Two levers: (1) caching — places, stop areas, route schedules, and coverage metadata are near-static and should be cached aggressively with a long TTL; journeys and departures are real-time and should not be cached beyond a few seconds, if at all. (2) Graceful degradation — a circuit breaker around the client so a slow Navitia endpoint doesn't consume the PHP-FPM worker pool. Watch the SaaS quota: journey planning is the expensive call, and a retry storm can exhaust a monthly quota in minutes. Cap retries, jitter backoff, and instrument quota consumption as a first-class metric with an alert at 70% of plan.
Failure modes
null fields and blank UI rather than an exception. Guard with schema-validated DTO hydration and a fixture-based contract test.Ramp-up. Low for the recommended path: a mid-level Laravel engineer unfamiliar with transit data can ship the client, config, tests, and caching in one to two days, and Navitia's REST/JSON surface is self-documenting via its OpenAPI spec. The bundle's source is useful here purely as a worked example of parameter names and endpoint construction — an afternoon of reading, not a dependency. Ramp-up on the domain is the real cost: understanding coverage scoping, journey section types, and the difference between scheduled and real-time data takes considerably longer than the code.
If self-hosted Navitia is chosen, discard the above estimate entirely — that is a data-platform project spanning infrastructure, ingestion, and ongoing operations, and it should be scoped and staffed as such rather than as an integration task.
How can I help you explore Laravel packages today?