Lue dans les fichiers PHP du paquet au commit fd38b58a7f7e : ses espaces de noms, classes, interfaces et énumérations, leurs constantes, propriétés et méthodes publiques avec leur PHPDoc, et les options que prennent ses fabriques. Rien n’en est exécuté.
CapabilitiesclassWhat a provider is, said before it is asked anything: what it can do, and who it makes the visitor's browser or the server talk to.
3 methods · 7 properties
ConfigclassA provider's configuration while its factory builds it: the options given, the factory's defaults under them, and the keys that must be filled.
7 methods
GeocoderInterfaceinterfacePlaces from an address, addresses from a point. omnimap does not geocode itself: Geocoding\GeocoderPhp asks a geocoder-php provider (willdurand/geocoder), with a cache and the pace the provider's terms set.
2 methods
MapHtmlclassThe map's element, as any host prints it (Twig, Blade, a React server render, plain PHP): either the picture kept in the cache, cut in tiles that assets/snapshot.js lays out, or a live map that assets/omnimap.js draws from the renderer's description.
4 methods
MapPrinterclassWhat a page shows of a view, whatever the host: the picture kept in the cache when there is one (made now by the server when it can), else the live map - for whoever may change the map only, when $cacheOnly (the visitor never loads the provider: an empty frame until a picture is captured), for everyone otherwise. It is glitchr/ux-google's rule (cache_only, cache_control), the provider aside.
6 methods
MapRendererInterfaceinterfaceThe map in the browser: the provider turns a view into a description the page's script draws (assets/omnimap.js and the provider's driver) - plain data, no code, the same for a Twig page, a Laravel view or a React component:
3 methods
ProviderFactoryclassA provider's factory fills a Config - its name ("omnimap.factory_name"), its title ("omnimap.factory_title"), the options it needs ("omnimap.required_options") and the defaults of the others - then builds the provider from it.
3 methods
ProviderFactoryInterfaceinterfaceBuilds a provider from its options (a key, a secret, a tile URL...).
2 methods
ProviderInterfaceinterfaceOne map provider, configured: Google, OpenStreetMap... Its Capabilities say what it can be asked - draw a map in the browser (MapRendererInterface), make an image of one on the server (StaticMapInterface), find places (GeocoderInterface), give tiles (TileSourceInterface) - and what it costs the visitor's privacy.
3 methods
RegistryclassThe application's map providers by name, each built once from its factory and options:
10 methods
SignerclassHMAC-SHA1 with a secret given in URL-safe base64, the signature in URL-safe base64: Google's rule for signing a Maps URL, and the rule glitchr/ux-google named its captured maps by - kept, so the pictures captured before omnimap keep their names. An empty secret signs with an empty key, as ux-google did.
6 methods
StaticMapInterfaceinterfaceA map as an image, made on the server: the provider's static map service, or tiles put together. The image carries what the provider asks to be shown on it (an attribution) when the provider does not draw it itself.
1 method
TileSourceInterfaceinterfaceSquare tiles of the Web Mercator grid, one URL each: what Leaflet draws and what Static\TileStitcher puts together.
6 methods
InvalidArgumentExceptionclassA value no map can hold: a latitude past a pole, a size of zero, a zoom below 0.
InvalidConfigExceptionclassA provider asked for with options it cannot work with, or not configured at all.
NotSupportedExceptionclassA provider asked for a capability it does not have: a static image of a provider that only draws in the browser.
1 method
OmnimapExceptioninterfaceEvery exception omnimap throws itself. A storage's own failures (Flysystem's, omnidrive's) and an HTTP client's pass through as they are.
ProviderExceptionclassThe provider answered, and not with what was asked: an error status, an image that is not one.
1 method
UnreachableExceptionclassThe provider could not be reached: a network error, a timeout.
GeocoderPhpclassomnimap's geocoding is geocoder-php's (willdurand/geocoder): a provider of theirs asked, its Locations turned into Places. Around it, what the providers' terms ask of whoever calls them: answers kept (a PSR-16 cache, $ttl seconds; Nominatim: "results must be cached on your side") and a pace (at least $interval seconds between two calls of this process; Nominatim: "an absolute maximum of 1 request per second" - across processes, a shared cache is what keeps the count down).
4 methods
RedactionclassWhat a failed call may carry of its credentials, taken out before the failure leaves the package: an HTTP client's exception quotes the URL called (a key in its query, a password in its user part), and every exception's trace keeps the arguments of the calls under it (the request options, headers and query with the key) unless PHP runs with zend.exception_ignore_args.
5 methods · 1 constant
AddressclassWhat a geocoder says of a place's address; any part may be unknown.
3 methods · 8 properties
BoundsclassA box on the map: its south-west and north-east corners. A box across the antimeridian has a western longitude greater than its eastern one.
4 methods · 2 properties
ImageclassAn image a provider made: its bytes, its media type and its size.
1 method · 3 properties
LatLngclassA point on Earth in degrees (WGS 84): a latitude from -90 to 90, a longitude of any value (180.5 and -179.5 are the same meridian; wrapped() brings it back between -180 and 180). A map's description carries it wrapped (MapView::toArray()).
7 methods · 2 properties
MapViewclassWhat a map shows, whoever draws it: its centre and zoom (the Web Mercator zoom every provider shares: 0 is the whole world in one 256-pixel tile), its markers, whether the provider's own controls are shown, and the options only one provider understands, under that provider's name (['google' => ['styles' => [...]]]): another provider ignores them.
7 methods · 6 properties
MarkerclassA pin on the map: where, its title (shown on hover by the renderers that can), its colour (a CSS hex colour).
3 methods · 3 properties
PlaceclassA place a geocoder found: where it is, what it is called, its address when known, the box it covers, and who said so (the provider's name) - a provider's terms often ask that its answers be shown with its name, and some forbid showing them on another provider's map.
3 methods · 6 properties
PointclassA position in pixels: on the whole world at a zoom (Projection\WebMercator), or on an image.
1 method · 2 properties
SizeclassA width and a height in pixels.
5 methods · 2 properties
WebMercatorclassThe projection of Google's, OpenStreetMap's and nearly every web map's tiles (EPSG:3857): at zoom z the world is a square of 256 x 2^z pixels, x growing eastward from the antimeridian, y southward from latitude 85.0511 (the square's edge).
4 methods · 2 constants
DirectoryStorageclassThe cache in a directory of the server's disk.
5 methods
DriveStorageclassThe cache on an omnidrive Drive (omnisense/omnidrive, suggested): the storage an application names ("uploads"), wherever it is - a directory, an S3 bucket, an SFTP server - Flysystem behind it.
5 methods
FlysystemStorageclassThe cache in a Flysystem storage (league/flysystem 3, suggested): local, S3, SFTP... - the operator a host already has (Symfony's flysystem-bundle storages, a Laravel disk's driver).
5 methods
SnapshotclassA picture of a map, kept: its name (the signature of what it shows), its size, and the grid of square tiles it is cut into (the last row and column padded to a whole tile). metadata() is the file kept beside the tiles, written as glitchr/ux-google wrote it - the same keys and the same types, PHP-serialized - so the captures made before omnimap are read as they are.
5 methods · 6 properties
SnapshotStoreclassThe map pictures in a Storage, laid out as glitchr/ux-google laid them out: under $directory ("google"), one folder per signature, the tiles named by $pattern ("{signature}/image-{id}") with the format's extension, the metadata beside them:
8 methods
SnapshotsclassThe map cache, whatever the provider: a view is named by the signature of what its picture depends on (the renderer's fingerprint, signed), and its picture is kept in a SnapshotStore. The picture comes from the browser (an administrator's capture of the live map, save()) or from the server (make(), when a StaticMapInterface is given: the provider's static map service, or its tiles put together) - the cache does not care which.
10 methods
StorageinterfaceWhere the map pictures are kept: the four things the cache asks of a storage. FlysystemStorage puts any Flysystem storage behind it (local, S3...), DirectoryStorage a plain directory; an application's own storage contract fits in a few lines.
4 methods
TileStitcherclassA map image made on the server from a tile source: the tiles the view covers, fetched (all at once: the HTTP client runs them side by side) with the source's headers, kept in a PSR-16 cache as long as the server's Cache-Control allows (max-age plus stale-while-revalidate; 7 days when it says nothing - OpenStreetMap's tile policy), put together with GD, the markers drawn as dots, the attribution written in the bottom-right corner.
3 methods
ArrayCacheclassA PSR-16 cache in this process's memory, with what was set kept readable (ttls()).
8 methods · 1 property
FixedGeocoderclassA geocoder-php provider that knows a few places by heart (and counts the questions it was asked): GeocoderPhp checked with no network.
4 methods · 1 property
PlainTilesclassTiles drawn here, for a test or the harness's bare script: a tile of one colour per zoom, x and y, its coordinates written on it - the image a RecordedHttpClient answers with.
2 methods
ProviderContractTeststraitWhat every omnimap provider does, as PHPUnit tests: a provider's test case uses this trait and gives its factory, built over the HTTP client the suite hands it (the provider wraps it in a PSR-18 client for geocoder-php when it geocodes). No test reaches the network: every answer is recorded.
8 methods
RecordedHttpClientclassAn HTTP client that answers from what it was given - a callable of the method, the URL and the options, returning [status, body, headers] - and keeps every request made ($requests): a provider's calls checked with no network.
4 methods · 1 property
RecordedResponseclassRecordedHttpClient's answer.
7 methods
TestTilesclassA provider for tests and the bare script: tiles from https://tiles.example/{z}/{x}/{y}.png (answer them with PlainTiles), a view described as plain data, its image made by TileStitcher.
13 methods
Omnimap
Capabilities class
final readonly class Capabilities Capabilities.php:9
What a provider is, said before it is asked anything: what it can do, and who it makes the visitor's browser or the server talk to.
public bool $rendererit draws a map in the browser (MapRendererInterface)
public bool $staticMapit makes an image of a map on the server (StaticMapInterface)
public bool $geocoderit finds places from an address and addresses from a point (GeocoderInterface)
public bool $tilesit gives tiles, one URL per tile (TileSourceInterface)
public array $browserHoststhe hosts a visitor's browser reaches when the map is drawn live: what a consent asks about
whether its browser script sets or reads cookies
public array $termsthe terms whoever runs it must follow (URLs)
Capabilities::__construct()
public function __construct(public bool $renderer = false, public bool $staticMap = false, public bool $geocoder = false, public bool $tiles = false, public array $browserHosts = [], public bool $cookies = false, public array $terms = [])$rendererit draws a map in the browser (MapRendererInterface)
$staticMapit makes an image of a map on the server (StaticMapInterface)
$geocoderit finds places from an address and addresses from a point (GeocoderInterface)
$tilesit gives tiles, one URL per tile (TileSourceInterface)
$browserHoststhe hosts a visitor's browser reaches when the map is drawn live: what a consent asks about
$cookieswhether its browser script sets or reads cookies
$termsthe terms whoever runs it must follow (URLs)
Capabilities::contracts()
public function contracts(): array- Returns
what it can be asked, by contract: renderer, staticMap, geocoder, tiles
Capabilities::toArray()
public function toArray(): arrayConfig class
final class Config extends ArrayObject Config.php:14
A provider's configuration while its factory builds it: the options given, the factory's defaults under them, and the keys that must be filled.
Config::defaults()
public function defaults(array $defaults): selfSets each key not set yet.
Config::validateNotEmpty()
public function validateNotEmpty(array $keys): voidConfig::get()
public function get(string $key, mixed $default = null): mixedConfig::string()
public function string(string $key): ?stringA string option; null when it is empty.
Config::int()
public function int(string $key, int $default = 0): intConfig::float()
public function float(string $key, float $default = 0.0): floatConfig::bool()
public function bool(string $key): boolA boolean option, as an environment variable gives it too: "1", "true", "yes", "on".
GeocoderInterface interface
interface GeocoderInterface extends ProviderInterface GeocoderInterface.php:14
Places from an address, addresses from a point. omnimap does not geocode itself: Geocoding\GeocoderPhp asks a geocoder-php provider (willdurand/geocoder), with a cache and the pace the provider's terms set.
GeocoderInterface::geocode()
public function geocode(string $address, ?string $locale = null, int $limit = 5): array- Returns
the best first; none found, an empty list
GeocoderInterface::reverse()
public function reverse(LatLng $position, ?string $locale = null, int $limit = 5): arrayMapHtml class
final class MapHtml MapHtml.php:20
The map's element, as any host prints it (Twig, Blade, a React server render, plain PHP): either the picture kept in the cache, cut in tiles that assets/snapshot.js lays out, or a live map that assets/omnimap.js draws from the renderer's description.
The picture's markup takes the host's own names where it has older ones to keep (lesringostars: class "google-tilemap", id "myMap_html2canvas", src "/google/{signature}/{id}.webp"). Options: class, suffix (of the frame's id), src (the tiles' address), missing (the address of a picture snapshot.js shows over a frame with no picture kept and in place of a tile that does not load; '' for none).
MapHtml::__construct()
public function __construct(array $options = [])MapHtml::snapshot()
public function snapshot(string $id, string $signature, ?Snapshot $snapshot, string $attribution = ''): stringThe picture of a map: the element $id, the tiles' frame in it, and the attribution the provider asks for. No snapshot yet: the frame with no tile (nothing is shown, nothing is fetched).
MapHtml::live()
public function live(string $id, array $description): stringA live map: the element $id carrying the renderer's description, which assets/omnimap.js draws (mountAll()) once the provider's script may be loaded.
MapHtml::button()
public function button(string $action, string $id, string $url, string $token, string $contents, array $attributes = []): stringMapPrinter class
final class MapPrinter MapPrinter.php:21
What a page shows of a view, whatever the host: the picture kept in the cache when there is one (made now by the server when it can), else the live map - for whoever may change the map only, when $cacheOnly (the visitor never loads the provider: an empty frame until a picture is captured), for everyone otherwise. It is glitchr/ux-google's rule (cache_only, cache_control), the provider aside.
The host gives what it alone knows: whether the visitor may change the map, and the export and suppress URLs and token (omnibridge's Twig extension asks its Access, Urls and Tokens).
MapPrinter::__construct()
public function __construct(readonly Snapshots $snapshots, readonly MapHtml $html = new MapHtml(), readonly bool $cacheOnly = true, ?\Closure $onError = null)$onErrorwhat to do with a picture the server could not make (log it): the page shows no picture
MapPrinter::map()
public function map(MapView $view, bool $mayChange = false): stringMapPrinter::exportButton()
public function exportButton(MapView $view, bool $mayChange, string $url, string $token, string $contents, array $attributes = []): stringThe button that sends the live map's picture to the cache: for whoever may change the map, whether a picture is kept or not - a kept one is replaced by the next capture (glitchr/ux-google's "update the map"; lesringostars shows it beside the delete button over a kept picture).
MapPrinter::suppressButton()
public function suppressButton(MapView $view, bool $mayChange, string $url, string $token, string $contents, array $attributes = []): stringThe button that deletes the picture kept: for whoever may change the map, when there is a picture.
MapPrinter::signature()
public function signature(MapView $view): stringMapPrinter::snapshots()
public function snapshots(): SnapshotsMapRendererInterface interface
interface MapRendererInterface extends ProviderInterface MapRendererInterface.php:19
The map in the browser: the provider turns a view into a description the page's script draws (assets/omnimap.js and the provider's driver) - plain data, no code, the same for a Twig page, a Laravel view or a React component:
{"provider": "google", "view": {...MapView::toArray()}, "library": {...what the driver loads}, "options": {...}}
A renderer also says what a picture of the view depends on (fingerprint()): a captured image of the map (Snapshot) is named by it, signed, so a change of centre, zoom or provider makes a new one.
MapRendererInterface::describe()
public function describe(MapView $view): array- Returns
JSON-ready
MapRendererInterface::fingerprint()
public function fingerprint(MapView $view): stringThe text a picture of this view is named after, once signed (Signer).
MapRendererInterface::attribution()
public function attribution(): stringThe attribution the map must show, as HTML (the provider's terms ask for it).
ProviderFactory class
abstract class ProviderFactory implements ProviderFactoryInterface ProviderFactory.php:15
A provider's factory fills a Config - its name ("omnimap.factory_name"), its title ("omnimap.factory_title"), the options it needs ("omnimap.required_options") and the defaults of the others - then builds the provider from it.
Nothing here calls anything: a factory whose provider is reached over HTTP takes its client in its own constructor - the application's, a MockHttpClient in a test.
ProviderFactory::getName()
public function getName(): stringProviderFactory::create()
public function create(array $options = []): ProviderInterfaceProviderFactory::createConfig()
public function createConfig(array $options = []): ConfigProviderFactoryInterface interface
interface ProviderFactoryInterface ProviderFactoryInterface.php:6
Builds a provider from its options (a key, a secret, a tile URL...).
ProviderFactoryInterface::getName()
public function getName(): stringThe name providers are configured with: "google", "openstreetmap".
..
ProviderFactoryInterface::create()
public function create(array $options = []): ProviderInterfaceProviderInterface interface
interface ProviderInterface ProviderInterface.php:12
One map provider, configured: Google, OpenStreetMap... Its Capabilities say what it can be asked - draw a map in the browser (MapRendererInterface), make an image of one on the server (StaticMapInterface), find places (GeocoderInterface), give tiles (TileSourceInterface) - and what it costs the visitor's privacy.
ProviderInterface::getName()
public function getName(): stringThe factory's name: "google", "openstreetmap".
..
ProviderInterface::getTitle()
public function getTitle(): stringProviderInterface::capabilities()
public function capabilities(): CapabilitiesRegistry class
final class Registry Registry.php:20
The application's map providers by name, each built once from its factory and options:
$registry = new Registry([new GoogleFactory($http), new OpenStreetMapFactory($http)], [ 'maps' => ['factory' => 'openstreetmap', 'options' => ['user_agent' => 'MySite/1.0 (+https://example.org)']], 'places' => ['factory' => 'google', 'options' => ['api_key' => '...']], ]);
$registry->renderer('maps')->describe($view); $registry->geocoder('places')->geocode('Kyoto');
Registry::__construct()
public function __construct(iterable $factories, readonly array $config)Registry::get()
public function get(string $name): ProviderInterfaceRegistry::has()
public function has(string $name): boolRegistry::renderer()
public function renderer(string $name): MapRendererInterfaceThe provider, as a map drawn in the browser.
Registry::staticMap()
public function staticMap(string $name): StaticMapInterfaceThe provider, as a map image made on the server.
Registry::geocoder()
public function geocoder(string $name): GeocoderInterfaceThe provider, as a geocoder.
Registry::tiles()
public function tiles(string $name): TileSourceInterfaceThe provider, as tiles.
Registry::options()
public function options(string $name): array- Returns
the options a provider is configured with
Registry::names()
public function names(): array- Returns
the configured providers' names
Registry::factories()
public function factories(): array- Returns
the factories installed: what
factory:may name
Signer class
final class Signer Signer.php:12
HMAC-SHA1 with a secret given in URL-safe base64, the signature in URL-safe base64: Google's rule for signing a Maps URL, and the rule glitchr/ux-google named its captured maps by - kept, so the pictures captured before omnimap keep their names. An empty secret signs with an empty key, as ux-google did.
Signer::__construct()
public function __construct(readonly ?string $secret)Signer::sign()
public function sign(string $payload): stringThe signature, without base64's "=" padding (ux-google's names).
Signer::signPadded()
public function signPadded(string $payload): stringThe signature with its padding: what Google expects in a URL's signature=.
Signer::verify()
public function verify(string $payload, string $signature): boolSigner::encode()
public static function encode(string $bytes): stringSigner::decode()
public static function decode(string $text): stringStaticMapInterface interface
interface StaticMapInterface extends ProviderInterface StaticMapInterface.php:14
A map as an image, made on the server: the provider's static map service, or tiles put together. The image carries what the provider asks to be shown on it (an attribution) when the provider does not draw it itself.
StaticMapInterface::image()
public function image(MapView $view, Size $size, int $scale = 1): Image$scale1, or 2 for a screen of twice the density: the image is $size x $scale pixels
TileSourceInterface interface
interface TileSourceInterface extends ProviderInterface TileSourceInterface.php:9
Square tiles of the Web Mercator grid, one URL each: what Leaflet draws and what Static\TileStitcher puts together.
TileSourceInterface::template()
public function template(): stringThe URL template, {z}/{x}/{y} in it: the browser's library fills it.
TileSourceInterface::url()
public function url(int $zoom, int $x, int $y): stringTileSourceInterface::tileSize()
public function tileSize(): intIn pixels: 256 nearly always.
TileSourceInterface::maxZoom()
public function maxZoom(): intTileSourceInterface::attribution()
public function attribution(): stringAs HTML.
TileSourceInterface::headers()
public function headers(): arrayThe headers a request for a tile must carry (a User-Agent naming the application, say).
Omnimap\Exception
InvalidArgumentException class
final class InvalidArgumentException extends InvalidArgumentException implements OmnimapException InvalidArgumentException.php:6
A value no map can hold: a latitude past a pole, a size of zero, a zoom below 0.
InvalidConfigException class
final class InvalidConfigException extends InvalidArgumentException implements OmnimapException InvalidConfigException.php:6
A provider asked for with options it cannot work with, or not configured at all.
NotSupportedException class
final class NotSupportedException extends LogicException implements OmnimapException NotSupportedException.php:6
A provider asked for a capability it does not have: a static image of a provider that only draws in the browser.
NotSupportedException::capability()
public static function capability(object $provider, string $name, string $capability): selfOmnimapException interface
interface OmnimapException extends Throwable OmnimapException.php:9
Every exception omnimap throws itself. A storage's own failures (Flysystem's, omnidrive's) and an HTTP client's pass through as they are.
ProviderException class
final class ProviderException extends RuntimeException implements OmnimapException ProviderException.php:6
The provider answered, and not with what was asked: an error status, an image that is not one.
ProviderException::answered()
public static function answered(string $provider, string $what, int|string $status): selfUnreachableException class
final class UnreachableException extends RuntimeException implements OmnimapException UnreachableException.php:6
The provider could not be reached: a network error, a timeout.
Omnimap\Geocoding
GeocoderPhp class
final class GeocoderPhp GeocoderPhp.php:28
omnimap's geocoding is geocoder-php's (willdurand/geocoder): a provider of theirs asked, its Locations turned into Places. Around it, what the providers' terms ask of whoever calls them: answers kept (a PSR-16 cache, $ttl seconds; Nominatim: "results must be cached on your side") and a pace (at least $interval seconds between two calls of this process; Nominatim: "an absolute maximum of 1 request per second" - across processes, a shared cache is what keeps the count down).
GeocoderPhp::__construct()
public function __construct(readonly Provider $provider, readonly ?CacheInterface $cache = null, readonly int $ttl = 2592000, readonly float $interval = 0.0)GeocoderPhp::geocode()
public function geocode(string $address, ?string $locale = null, int $limit = 5): arrayGeocoderPhp::reverse()
public function reverse(LatLng $position, ?string $locale = null, int $limit = 5): arrayGeocoderPhp::place()
public static function place(Location $location): ?PlaceOmnimap\Http
Redaction class
final class Redaction Redaction.php:22
What a failed call may carry of its credentials, taken out before the failure leaves the package: an HTTP client's exception quotes the URL called (a key in its query, a password in its user part), and every exception's trace keeps the arguments of the calls under it (the request options, headers and query with the key) unless PHP runs with zend.exception_ignore_args.
copy() gives the previous exception to wrap instead of the client's own: the same class and code, its message with the key's parameters, the user part and every secret value replaced by ***, its trace without arguments, its own previous copied the same way. Properties of the client's class beyond those of \Exception are not copied (a Symfony HttpException's response, a PSR-18 exception's request: their URL holds the key). withoutArguments() takes the arguments out of the trace of the exception thrown in its place.
const MASK = '***'
Redaction::secrets()
public static function secrets(string $url, array $options = []): arrayThe secrets a request carries: the values of its query parameters, headers and body fields named as credentials (key, token, secret, password, signature, auth...), a bearer token, a basic password, the URL's user part.
$optionsthe HTTP client's options
Redaction::sensitive()
public static function sensitive(string $name): boolWhether a parameter, header or field of this name holds a credential.
Redaction::text()
public static function text(string $text, array $secrets = []): stringA text without credentials: in every address, the user part and the parameters named as credentials masked (api_key=***); then every secret given, raw or URL-encoded, masked wherever it stands.
Redaction::copy()
public static function copy(\Throwable $failure, array $secrets = []): \ThrowableA copy of a failure to wrap in its place: its class, code, file and line, its message through text(), its trace without arguments, its previous copied the same way.
Redaction::withoutArguments()
public static function withoutArguments(\Throwable $failure): \ThrowableThe failure given, the arguments out of its trace (and out of its previous ones'), as zend.exception_ignore_args would have left it.
Omnimap\Model
Address class
final readonly class Address implements JsonSerializable Address.php:6
What a geocoder says of a place's address; any part may be unknown.
public ?string $streetNumberpublic ?string $streetNamepublic ?string $postalCodepublic ?string $localitypublic ?string $subLocalitypublic ?string $regionpublic ?string $countrypublic ?string $countryCode
Address::__construct()
public function __construct(public ?string $streetNumber = null, public ?string $streetName = null, public ?string $postalCode = null, public ?string $locality = null, public ?string $subLocality = null, public ?string $region = null, public ?string $country = null, public ?string $countryCode = null)Address::toArray()
public function toArray(): arrayAddress::jsonSerialize()
public function jsonSerialize(): arrayBounds class
final readonly class Bounds implements JsonSerializable Bounds.php:9
A box on the map: its south-west and north-east corners. A box across the antimeridian has a western longitude greater than its eastern one.
public LatLng $southWestpublic LatLng $northEast
Bounds::__construct()
public function __construct(public LatLng $southWest, public LatLng $northEast)Bounds::contains()
public function contains(LatLng $point): boolBounds::toArray()
public function toArray(): arrayBounds::jsonSerialize()
public function jsonSerialize(): arrayImage class
final readonly class Image Image.php:6
An image a provider made: its bytes, its media type and its size.
public string $bytespublic string $mimeTypepublic Size $size
Image::__construct()
public function __construct(public string $bytes, public string $mimeType, public Size $size)LatLng class
final readonly class LatLng implements JsonSerializable, Stringable LatLng.php:13
A point on Earth in degrees (WGS 84): a latitude from -90 to 90, a longitude of any value (180.5 and -179.5 are the same meridian; wrapped() brings it back between -180 and 180). A map's description carries it wrapped (MapView::toArray()).
public float $latpublic float $lng
LatLng::__construct()
public function __construct(public float $lat, public float $lng)LatLng::fromArray()
public static function fromArray(array $array): selfLatLng::wrapped()
public function wrapped(): selfThe same point, its longitude between -180 (included) and 180 (excluded).
LatLng::equals()
public function equals(self $other, float $tolerance = 1.0E-9): boolLatLng::toArray()
public function toArray(): arrayLatLng::jsonSerialize()
public function jsonSerialize(): arrayLatLng::__toString()
public function __toString(): string"lat,lng", as URLs and geocoders write a point.
MapView class
final readonly class MapView implements JsonSerializable MapView.php:16
What a map shows, whoever draws it: its centre and zoom (the Web Mercator zoom every provider shares: 0 is the whole world in one 256-pixel tile), its markers, whether the provider's own controls are shown, and the options only one provider understands, under that provider's name (['google' => ['styles' => [...]]]): another provider ignores them.
The id is the page element's the map is drawn into.
public LatLng $centerpublic int $zoompublic array $markerspublic bool $controlspublic array $optionspublic string $id
MapView::__construct()
public function __construct(public LatLng $center, public int $zoom, public array $markers = [], public bool $controls = true, public array $options = [], public string $id = 'map')MapView::withMarker()
public function withMarker(Marker $marker): selfMapView::withMarkers()
public function withMarkers(array $markers): selfMapView::withOptions()
public function withOptions(string $provider, array $options): self$optionsmerged over the provider's options already set
MapView::options()
public function options(string $provider): array- Returns
the options of one provider
MapView::toArray()
public function toArray(): array- Returns
the view as a description carries it: every longitude wrapped between -180 and 180
MapView::jsonSerialize()
public function jsonSerialize(): arrayMarker class
final readonly class Marker implements JsonSerializable Marker.php:6
A pin on the map: where, its title (shown on hover by the renderers that can), its colour (a CSS hex colour).
public LatLng $positionpublic ?string $titlepublic ?string $color
Marker::__construct()
public function __construct(public LatLng $position, public ?string $title = null, public ?string $color = null)Marker::toArray()
public function toArray(): arrayMarker::jsonSerialize()
public function jsonSerialize(): arrayPlace class
final readonly class Place implements JsonSerializable Place.php:11
A place a geocoder found: where it is, what it is called, its address when known, the box it covers, and who said so (the provider's name) - a provider's terms often ask that its answers be shown with its name, and some forbid showing them on another provider's map.
public LatLng $positionpublic string $labelpublic string $providedBypublic ?Address $addresspublic ?Bounds $boundspublic ?string $id
Place::__construct()
public function __construct(public LatLng $position, public string $label, public string $providedBy, public ?Address $address = null, public ?Bounds $bounds = null, public ?string $id = null)Place::toArray()
public function toArray(): arrayPlace::jsonSerialize()
public function jsonSerialize(): arrayPoint class
final readonly class Point Point.php:6
A position in pixels: on the whole world at a zoom (Projection\WebMercator), or on an image.
public float $xpublic float $y
Point::__construct()
public function __construct(public float $x, public float $y)Size class
final readonly class Size implements JsonSerializable, Stringable Size.php:8
A width and a height in pixels.
public int $widthpublic int $height
Size::__construct()
public function __construct(public int $width, public int $height)Size::fromString()
public static function fromString(string $size): self"640x480"
Size::scaled()
public function scaled(int $scale): selfSize::jsonSerialize()
public function jsonSerialize(): arraySize::__toString()
public function __toString(): stringOmnimap\Projection
WebMercator class
final class WebMercator WebMercator.php:16
The projection of Google's, OpenStreetMap's and nearly every web map's tiles (EPSG:3857): at zoom z the world is a square of 256 x 2^z pixels, x growing eastward from the antimeridian, y southward from latitude 85.0511 (the square's edge).
const TILE = 256const MAX_LATITUDE = 85.0511287798066
WebMercator::worldSize()
public static function worldSize(float $zoom): floatThe world's width at a zoom, in pixels.
WebMercator::point()
public static function point(LatLng $latLng, float $zoom): PointWhere a point lies on the world at a zoom, in pixels.
WebMercator::latLng()
public static function latLng(Point $point, float $zoom): LatLngThe point at a position on the world at a zoom (its longitude not wrapped).
WebMercator::bounds()
public static function bounds(LatLng $center, int $zoom, Size $size): BoundsThe box an image of this size shows around this centre at this zoom.
Omnimap\Snapshot
DirectoryStorage class
final class DirectoryStorage implements Storage DirectoryStorage.php:8
The cache in a directory of the server's disk.
DirectoryStorage::__construct()
public function __construct(string $root)DirectoryStorage::read()
public function read(string $path): ?stringDirectoryStorage::write()
public function write(string $path, string $contents): voidDirectoryStorage::exists()
public function exists(string $path): boolDirectoryStorage::deleteDirectory()
public function deleteDirectory(string $path): voidDriveStorage class
final class DriveStorage implements Storage DriveStorage.php:15
The cache on an omnidrive Drive (omnisense/omnidrive, suggested): the storage an application names ("uploads"), wherever it is - a directory, an S3 bucket, an SFTP server - Flysystem behind it.
DriveStorage::__construct()
public function __construct(readonly Drive $drive)DriveStorage::read()
public function read(string $path): ?stringDriveStorage::write()
public function write(string $path, string $contents): voidDriveStorage::exists()
public function exists(string $path): boolDriveStorage::deleteDirectory()
public function deleteDirectory(string $path): voidFlysystemStorage class
final class FlysystemStorage implements Storage FlysystemStorage.php:16
The cache in a Flysystem storage (league/flysystem 3, suggested): local, S3, SFTP... - the operator a host already has (Symfony's flysystem-bundle storages, a Laravel disk's driver).
FlysystemStorage::__construct()
public function __construct(readonly FilesystemOperator $filesystem)FlysystemStorage::read()
public function read(string $path): ?stringFlysystemStorage::write()
public function write(string $path, string $contents): void- Throws
FilesystemException
FlysystemStorage::exists()
public function exists(string $path): boolFlysystemStorage::deleteDirectory()
public function deleteDirectory(string $path): void- Throws
FilesystemException
Snapshot class
final readonly class Snapshot implements JsonSerializable Snapshot.php:13
A picture of a map, kept: its name (the signature of what it shows), its size, and the grid of square tiles it is cut into (the last row and column padded to a whole tile). metadata() is the file kept beside the tiles, written as glitchr/ux-google wrote it - the same keys and the same types, PHP-serialized - so the captures made before omnimap are read as they are.
public string $signaturepublic int $widthpublic int $heightpublic ?int $tilesizepublic int $xtilespublic int $ytiles
Snapshot::__construct()
public function __construct(public string $signature, public int $width, public int $height, public ?int $tilesize, public int $xtiles, public int $ytiles)Snapshot::fromMetadata()
public static function fromMetadata(string $signature, array $metadata): ?selfSnapshot::metadata()
public function metadata(): arraySnapshot::tiles()
public function tiles(): intSnapshot::jsonSerialize()
public function jsonSerialize(): arraySnapshotStore class
final class SnapshotStore SnapshotStore.php:21
The map pictures in a Storage, laid out as glitchr/ux-google laid them out: under $directory ("google"), one folder per signature, the tiles named by $pattern ("{signature}/image-{id}") with the format's extension, the metadata beside them:
google/tcIj2DZnhR2xGsZ8K8t2ID4PKVg/image-0.png ... image-23.png google/tcIj2DZnhR2xGsZ8K8t2ID4PKVg/metadata.txt
save() cuts an image into tiles (GD) - a picture the browser captured, or one the server made (Snapshots::make()). What has been asked during this object's life is remembered (one storage round trip per question: on S3 each is an HTTP request); save() and delete() forget it.
SnapshotStore::__construct()
public function __construct(readonly Storage $storage, readonly string $directory = 'omnimap', readonly string $pattern = '{signature}/image-{id}', readonly string $format = 'png')SnapshotStore::find()
public function find(string $signature): ?SnapshotSnapshotStore::tile()
public function tile(string $signature, int $id): ?stringA tile's bytes, in the store's format; null when there is none.
SnapshotStore::save()
public function save(string $signature, string $image, ?int $tilesize = 512): SnapshotKeeps an image as the picture of $signature: cut into squares of $tilesize (the last row and column padded with transparency), or whole when $tilesize is null. Replaces what was kept under that name.
SnapshotStore::delete()
public function delete(string $signature): voidForgets the picture of $signature, tiles and metadata.
SnapshotStore::format()
public function format(): stringSnapshotStore::tilePath()
public function tilePath(string $signature, int $id): stringSnapshotStore::metadataPath()
public function metadataPath(string $signature): stringSnapshots class
final class Snapshots Snapshots.php:23
The map cache, whatever the provider: a view is named by the signature of what its picture depends on (the renderer's fingerprint, signed), and its picture is kept in a SnapshotStore. The picture comes from the browser (an administrator's capture of the live map, save()) or from the server (make(), when a StaticMapInterface is given: the provider's static map service, or its tiles put together) - the cache does not care which.
$snapshots = new Snapshots($renderer, new Signer($secret), new SnapshotStore(new DirectoryStorage('/var/maps')), $staticMap); $snapshot = $snapshots->findOrMake($view); // made once, then read
Snapshots::__construct()
public function __construct(readonly MapRendererInterface $renderer, readonly Signer $signer, readonly SnapshotStore $store, readonly ?StaticMapInterface $staticMap = null, readonly Size $size = new Size(1512, 938), readonly int $scale = 1, readonly ?int $tilesize = 512)Snapshots::signature()
public function signature(MapView $view): stringSnapshots::find()
public function find(MapView $view): ?SnapshotSnapshots::canMake()
public function canMake(): boolWhether the server can make a picture itself (a static map is configured).
Snapshots::make()
public function make(MapView $view): SnapshotThe picture of the view, made now by the server and kept (replacing any).
Snapshots::findOrMake()
public function findOrMake(MapView $view): ?SnapshotThe picture kept; made now when there is none and the server can make one.
Snapshots::save()
public function save(string $signature, string $image, ?int $tilesize = null): SnapshotA picture the browser captured (an image's bytes, or a data: URL), kept under its signature.
Snapshots::delete()
public function delete(string $signature): voidSnapshots::store()
public function store(): SnapshotStoreSnapshots::renderer()
public function renderer(): MapRendererInterfaceStorage interface
interface Storage Storage.php:13
Where the map pictures are kept: the four things the cache asks of a storage. FlysystemStorage puts any Flysystem storage behind it (local, S3...), DirectoryStorage a plain directory; an application's own storage contract fits in a few lines.
Paths are relative, "/"-separated: "google/<signature>/image-0.png".
Storage::read()
public function read(string $path): ?stringThe file's contents; null when there is no such file.
Storage::write()
public function write(string $path, string $contents): voidStorage::exists()
public function exists(string $path): boolStorage::deleteDirectory()
public function deleteDirectory(string $path): voidThe directory and everything in it; nothing when it is not there.
Omnimap\Static
TileStitcher class
final class TileStitcher TileStitcher.php:35
A map image made on the server from a tile source: the tiles the view covers, fetched (all at once: the HTTP client runs them side by side) with the source's headers, kept in a PSR-16 cache as long as the server's Cache-Control allows (max-age plus stale-while-revalidate; 7 days when it says nothing - OpenStreetMap's tile policy), put together with GD, the markers drawn as dots, the attribution written in the bottom-right corner.
The world repeats east and west; above and below it, $background.
A scale of 2 takes the tiles of the next zoom: the same view at twice the density.
The view's zoom is the one every provider shares (0: the world in 256 pixels). A source of 512-pixel tiles numbers them as such servers do, 2^z a side at z (Leaflet's zoomOffset -1): the view's zoom z is read at the source's zoom z - 1, and at zoom 0 the source's one tile is drawn at half its size.
TileStitcher::__construct()
public function __construct(readonly TileSourceInterface $tiles, readonly HttpClientInterface $http, readonly ?CacheInterface $cache = null, readonly string $background = '#aad3df', readonly string $markerColor = '#d33b3b')TileStitcher::image()
public function image(MapView $view, Size $size, int $scale = 1): ImageTileStitcher::lifetime()
public static function lifetime(string $cacheControl): intmax-age plus stale-while-revalidate, in seconds; 7 days when the server says neither.
Omnimap\Testing
ArrayCache class
final class ArrayCache implements CacheInterface ArrayCache.php:8
A PSR-16 cache in this process's memory, with what was set kept readable (ttls()).
public array $ttls = []
ArrayCache::get()
public function get(string $key, mixed $default = null): mixedArrayCache::set()
public function set(string $key, mixed $value, \DateInterval|int|null $ttl = null): boolArrayCache::delete()
public function delete(string $key): boolArrayCache::clear()
public function clear(): boolArrayCache::getMultiple()
public function getMultiple(iterable $keys, mixed $default = null): iterable$keys@return iterable<string, mixed>
ArrayCache::setMultiple()
public function setMultiple(iterable $values, \DateInterval|int|null $ttl = null): boolArrayCache::deleteMultiple()
public function deleteMultiple(iterable $keys): boolArrayCache::has()
public function has(string $key): boolFixedGeocoder class
final class FixedGeocoder implements Provider FixedGeocoder.php:16
A geocoder-php provider that knows a few places by heart (and counts the questions it was asked): GeocoderPhp checked with no network.
public int $calls = 0
FixedGeocoder::__construct()
public function __construct(readonly array $places)FixedGeocoder::geocodeQuery()
public function geocodeQuery(GeocodeQuery $query): CollectionFixedGeocoder::reverseQuery()
public function reverseQuery(ReverseQuery $query): CollectionFixedGeocoder::getName()
public function getName(): stringPlainTiles class
final class PlainTiles PlainTiles.php:10
Tiles drawn here, for a test or the harness's bare script: a tile of one colour per zoom, x and y, its coordinates written on it - the image a RecordedHttpClient answers with.
PlainTiles::png()
public static function png(int $zoom, int $x, int $y, int $size = 256): stringPlainTiles::answer()
public static function answer(int $size = 256): \ClosureThe answer RecordedHttpClient gives for ".../{z}/{x}/{y}.png": tiles of $size pixels.
ProviderContractTests trait
trait ProviderContractTests ProviderContractTests.php:62
What every omnimap provider does, as PHPUnit tests: a provider's test case uses this trait and gives its factory, built over the HTTP client the suite hands it (the provider wraps it in a PSR-18 client for geocoder-php when it geocodes). No test reaches the network: every answer is recorded.
final class OpenStreetMapContractTest extends TestCase { use ProviderContractTests;
protected function contractFactory(?HttpClientInterface $http): ProviderFactoryInterface
{
return new OpenStreetMapFactory($http, $http ? new Psr18Client($http) : null, new ArrayCache());
} protected function contractOptions(): array { return ['user_agent' => 'tests/1.0', 'nominatim_interval' => 0]; }
}What it checks: - the factory's name is the provider's, the Registry builds it from {factory, options} once; a missing required option is refused with InvalidConfigException naming it; - capabilities() says exactly what the provider answers: a declared contract is implemented, an implemented one declared off (no client given) throws NotSupportedException, never a TypeError; browser hosts are host names, terms are https addresses; - a renderer's description is plain data (JSON and back) naming the provider, the view and the consent; every address in it is on a declared browser host; its fingerprint is stable and follows the centre, the zoom and the markers; - a static map is an image: bytes that are the media type it says, no larger than asked; - a tile source's addresses are complete https URLs, its sizes and zooms sane; - a geocoder's places are places of this provider, within the limit, on the globe; - errors are the family's: an answer other than 200 or a body that is not what was asked is a ProviderException, a transport failure an UnreachableException.
Requires phpunit/phpunit and symfony/http-client (the provider's require-dev).
ProviderContractTests::testTheFactoryNamesWhatItBuildsAndTheRegistryBuildsItOnce()
public function testTheFactoryNamesWhatItBuildsAndTheRegistryBuildsItOnce(): voidProviderContractTests::testAMissingRequiredOptionIsRefusedByName()
public function testAMissingRequiredOptionIsRefusedByName(): voidProviderContractTests::testCapabilitiesAreWhatTheProviderAnswers()
public function testCapabilitiesAreWhatTheProviderAnswers(): voidProviderContractTests::testARendererDescribesTheViewAsPlainData()
public function testARendererDescribesTheViewAsPlainData(): voidProviderContractTests::testAStaticMapIsAnImageOfTheSizeAsked()
public function testAStaticMapIsAnImageOfTheSizeAsked(): voidProviderContractTests::testTileAddressesAreComplete()
public function testTileAddressesAreComplete(): voidProviderContractTests::testAGeocoderAnswersPlacesOfItsOwn()
public function testAGeocoderAnswersPlacesOfItsOwn(): voidProviderContractTests::testErrorsAreTheFamilysExceptions()
public function testErrorsAreTheFamilysExceptions(): voidRecordedHttpClient class
final class RecordedHttpClient implements HttpClientInterface RecordedHttpClient.php:15
An HTTP client that answers from what it was given - a callable of the method, the URL and the options, returning [status, body, headers] - and keeps every request made ($requests): a provider's calls checked with no network.
public array $requests = []
RecordedHttpClient::__construct()
public function __construct(readonly \Closure $answer)RecordedHttpClient::request()
public function request(string $method, string $url, array $options = []): ResponseInterfaceRecordedHttpClient::stream()
public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterfaceRecordedHttpClient::withOptions()
public function withOptions(array $options): staticRecordedResponse class
final class RecordedResponse implements ResponseInterface RecordedResponse.php:8
RecordedHttpClient's answer.
RecordedResponse::__construct()
public function __construct(readonly int $status, readonly string $body, readonly array $headers, readonly string $url)RecordedResponse::getStatusCode()
public function getStatusCode(): intRecordedResponse::getHeaders()
public function getHeaders(bool $throw = true): arrayRecordedResponse::getContent()
public function getContent(bool $throw = true): stringRecordedResponse::toArray()
public function toArray(bool $throw = true): arrayRecordedResponse::cancel()
public function cancel(): voidRecordedResponse::getInfo()
public function getInfo(?string $type = null): mixedTestTiles class
final class TestTiles implements MapRendererInterface, StaticMapInterface, TileSourceInterface TestTiles.php:21
A provider for tests and the bare script: tiles from https://tiles.example/{z}/{x}/{y}.png (answer them with PlainTiles), a view described as plain data, its image made by TileStitcher.
TestTiles::__construct()
public function __construct(readonly HttpClientInterface $http, readonly ?CacheInterface $cache = null, readonly int $tileSize = 256)$tileSize256, or 512 for a source of 512-pixel tiles (2^z a side at z)
TestTiles::getName()
public function getName(): stringTestTiles::getTitle()
public function getTitle(): stringTestTiles::capabilities()
public function capabilities(): CapabilitiesTestTiles::describe()
public function describe(MapView $view): arrayTestTiles::fingerprint()
public function fingerprint(MapView $view): stringTestTiles::attribution()
public function attribution(): stringTestTiles::image()
public function image(MapView $view, Size $size, int $scale = 1): ImageTestTiles::template()
public function template(): stringTestTiles::url()
public function url(int $zoom, int $x, int $y): stringTestTiles::tileSize()
public function tileSize(): intTestTiles::maxZoom()
public function maxZoom(): intTestTiles::headers()
public function headers(): array