Search by

omnisense / omnitravel

GlitchArt

Omnitravel: going from A to B under any PHP host, whoever keeps the data - a stop's or a station's next departures and arrivals in real time (delays, platforms, gates, cancellations), journeys across modes, where vehicles are, the network's stops and lines with their colours. One family for urban tr

1.x-dev 2026-11-09 23:31 UTC

This package is auto-updated.

Last update: 2026-11-10 00:35:31 UTC


README

Going from A to B under any PHP host, whoever keeps the data: one family for urban transit, trains and planes, in four contracts.

Contract What it answers
TimetablesInterface a stop's or a station's next departures and arrivals, in real time where the provider knows it: the expected time and the delay, the platform or the gate, cancellations
ItinerariesInterface journeys from A to B across modes: their legs on foot and on board, the lines, the changes
TrackingInterface where vehicles are: buses and trains from a real-time feed, aircraft from a tracking network
NetworkInterface a network's places and lines: a stop, the stops near a point, a search by name, the lines with their colours, a line's stops in order, the operators
Provider Contracts Key
omnitravel/gtfs timetables, network, tracking - any network that publishes GTFS, imported into a store (SQLite or MySQL), with GTFS-Realtime none
omnitravel/transitous itineraries, timetables, network (no lines list) - the community-run MOTIS 2 server over the world's open feeds none (a User-Agent)
omnitravel/navitia timetables, itineraries, network - a Navitia coverage, SNCF's through api.sncf.com a token

Planned, named in the family's plan: opensky (aircraft positions), aviationstack or flightaware (flights at an airport), deutsche-bahn, ourairports (the airports themselves).

use Omnitravel\Model\{Coordinates, DepartureQuery, JourneyQuery, Place};
use Omnitravel\Registry;

$travel = new Registry([new GtfsFactory($http), new TransitousFactory($http)], [
    'angers' => ['factory' => 'gtfs', 'options' => ['feed' => 'angers', 'dsn' => 'sqlite:/var/gtfs.sqlite']],
    'planner' => ['factory' => 'transitous', 'options' => ['user_agent' => 'MySite/1.0 (https://example.org; travel@example.org)']],
]);

$stop = $travel->network('angers')->nearby(new Coordinates(47.4712, -0.5518))[0];
$next = $travel->timetables('angers')->departures(new DepartureQuery($stop->id, limit: 5));
$ways = $travel->itineraries('planner')->journeys(new JourneyQuery(Place::at(47.4712, -0.5518), Place::at(47.4608, -0.5306)));

Usage policies

Each provider declares its usage policy as data (its policy.json: rate limits, rights, attribution, requirements, where and when it was read), and every call through timetables(), itineraries(), tracking() or network() is held to it: checked before, counted after, refused with UsageLimitReachedException once a limit is reached or while the provider asks to wait (a 429 and its Retry-After, a RateLimit field with nothing left). A site may tighten a policy in its configuration, never loosen it:

'planner' => [
    'factory' => 'transitous',
    'options' => ['user_agent' => 'MySite/1.0 (https://example.org; travel@example.org)'],
    'policy' => ['rateLimits' => [['max' => 600, 'window' => 'day', 'operations' => ['journeys']]]],
    'usage' => ['commercial' => false, 'open_source' => true],
],

$travel->policy('planner') gives the policy as the site runs it. Pass a shared RateLimiterInterface as the registry's third argument when the application runs in many processes. See docs/policies.md.

omnisense/omnitravel requires omnisense/contracts (the kernel every omnisense family builds on: provider, factory, registry, JSON client, usage policies, testing kit) and symfony/http-client-contracts, nothing else: no framework, no HTTP client of its own (each provider takes the application's). It runs the same in plain PHP, a worker, Laravel or Symfony.

The manual is in docs/: installation, Symfony, models, providers, usage policies, testing, the harness, errors, writing a provider.

MIT.