Search by

omnisense / omnistay

GlitchArt

Omnistay: where to stay and what to book for a trip, under any PHP host, whoever sells it - hotels and homes rented by their owners searched through one interface, a property's availability, nightly rates, fees, taxes and cancellation policy, offers re-priced, bookings made and cancelled, a property

1.x-dev 2026-11-10 12:00 UTC

This package is auto-updated.

Last update: 2026-11-10 12:34:07 UTC


README

Where to stay and what to book for a trip, under any PHP host, whoever sells it. Hotels from a distribution system and homes rented by their owners answer the same contracts, so a site searches both through one interface, prices a stay line by line, books it and cancels it.

use Omnistay\Amadeus\AmadeusFactory;
use Omnistay\Local\LocalFactory;
use Omnistay\Model\{Guests, Stay, StayQuery};
use Omnistay\Registry;

$registry = new Registry([new AmadeusFactory($http), new LocalFactory($store)], [
    'hotels' => ['factory' => 'amadeus', 'options' => ['client_id' => getenv('AMADEUS_CLIENT_ID'), 'client_secret' => getenv('AMADEUS_CLIENT_SECRET')]],
    'homes' => ['factory' => 'local', 'options' => ['service_fee' => 12]],
]);

$results = $registry->searchAll(new StayQuery(Stay::of('2026-12-18', '2026-12-21'), new Guests(2), latitude: 45.899, longitude: 6.129, radius: 10));
foreach ($results->items as $result) {
    echo $result->property->name, ' ', $result->nightly(), "\n";   // hotels and homes, the cheapest night first
}
$offer = $registry->availabilityOf($results->items[0]->property->ref, $stay, $guests)->cheapest();
$booking = $registry->bookOffer(new BookingRequest($offer, [new Traveller('Alice', 'Example', 'alice@example.org')], paymentReference: $paid));

The shape

  • Models (Omnistay\Model): Property (a hotel or a home: kind, Location, Amenitys, Photos, RoomTypes, stars, guests' rating), Stay and Guests, StayQuery, SearchResult, Offer with its Rate (the nights one by one, Charges: cleaning, service, taxes, discounts), CancellationPolicy and PaymentTiming, Availability, CalendarDay, BookingRequest, Booking and BookingStatus, Money; CarHire and Package, shared models for the providers that sell them.
  • Contracts by capability, each provider saying which it has (Capabilities): SearchInterface, AvailabilityInterface (a property's offers, an offer re-priced), CalendarInterface, BookInterface, CancelInterface, ContentInterface.
  • Registry (providers by name; searchAll() merges several providers' answers; a PropertyRef names the provider it came from, so every question about it goes back there), Config, ProviderFactory, as in the other Omnisense families.
  • Testing: FixedProvider (every contract, in memory), RecordedHttpClient, BareTestCase.
  • Providers are packages: omnistay/amadeus (hotels), omnistay/local (a site's own listings).

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 search(), availability(), calendar(), book(), cancel() or content() - and through searchAll(), availabilityOf(), propertyOf(), bookOffer() - 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). In searchAll(), a provider over its limit is one of the failures; the others' answers stand. A site may tighten a policy in its configuration, never loosen it:

'homes' => [
    'factory' => 'local',
    'policy' => ['rateLimits' => [['max' => 60, 'window' => 'minute', 'operations' => ['book']]]],
    'usage' => ['commercial' => true],
],

$registry->policy('homes') 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.

The core needs no framework: it 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.

Manual: docs/index.md. License: MIT.