Skip to content

omnisense/omnibus API reference

Floor
Family
Version
2.x
Conformance suite
runs, no CI read
Verified for real
Verified in part
Licence
MIT
composer require omnisense/omnibus:2.x-dev

Read from the package's own PHP files at the commit 1dd873f591e4: its namespaces, classes, interfaces and enums, their public constants, properties and methods with their PHPDoc, and the options its factories take. Nothing of it is run.

Omnibus

  • Config class

    A gateway's configuration while its factory builds it: the options given, the factory's defaults under them, and the keys that must be filled.

    3 methods

  • Gateway class

    A carrier's actions behind one door: the first action supporting a request answers it.

    11 methods

  • GatewayFactory class

    The Payum way: a carrier's factory fills a Config - its name, title, the options it needs, its API client ("omnibus.api", a closure of the Config) and its actions ("omnibus.action.<name>") - and the gateway is those actions, the API handed to the ones that ask for it.

    4 methods

  • GatewayFactoryInterface interface

    Builds a carrier's gateway from its options (credentials, sandbox, rates...).

    2 methods

  • GatewayInterface interface

    One carrier, configured: the same questions for all of them. Each typed method is a shortcut for execute() with its request.

    10 methods

  • Registry class

    The shop's carriers by name, each built once from its factory and options:

    7 methods

Omnibus\Action

  • ActionInterface interface

    One thing a carrier does: answers the requests it supports.

    2 methods

  • ApiAwareInterface interface

    An action that talks to the carrier through the gateway's API client.

    1 method

  • ApiAwareTrait trait

    1 method

  • ConfiguredRatingAction class

    Prices from the gateway's configuration, for carriers that publish no rating API (the price is the shop's contract, not a public tariff).

    3 methods

Omnibus\Bridge\Symfony

  • OmnibusBundle class

    Omnibus in a Symfony application: the carrier packages installed (omnibus/offline, omnibus/mondial-relay, omnibus/colissimo, omnibus/ups... every omnibus/* package) registered, the shop's gateways built from configuration, Omnibus\Registry autowired, and each gateway injectable by its name:

    2 methods

Omnibus\Exception

Omnibus\Http

  • Redaction class

    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.

    5 methods · 1 constant

Omnibus\Model

  • Address class

    A postal address: the sender's, the recipient's, a pickup point's.

    2 methods · 8 properties

  • Label class

    The shipping label (or slip) a carrier issued: its tracking number and the printable document.

    1 method · 7 properties · 2 constants

  • Parcel class

    One box: its weight (grams), its size (centimetres), what it is worth (minor units).

    2 methods · 7 properties

  • PickupPoint class

    A relay, locker or post office a parcel can be sent to and collected from.

    1 method · 8 properties

  • Rate class

    What a service costs for a shipment (minor units) and how long it takes.

    1 method · 7 properties

  • Shipment class

    What goes where: from the sender to the recipient - at home, or at a pickup point - in one or more parcels, under a carrier's service.

    3 methods · 8 properties

  • Tracking class

    Where a parcel is: its latest status and every step so far, oldest first.

    2 methods · 4 properties

  • TrackingEvent class

    1 method · 5 properties

  • TrackingStatus enum

    Every carrier's statuses, folded onto one scale.

    1 method · 8 cases

Omnibus\Request

  • Cancel class

    Cancel a shipment not handed over yet. Result: true when the carrier voided it.

    1 method · 1 property

  • GetSlip class

    The label of a shipment booked earlier, again (a reprint). Result: the Label.

    2 methods · 2 properties

  • Paperless class

    Customs documents sent electronically (paperless trade) for a shipment leaving the customs union. Result: true once the carrier accepted them.

    1 method · 2 properties

  • Pickup class

    The pickup points near an address (that can take this parcel). Result: PickupPoint[]

    2 methods · 3 properties

  • Rating class

    The services that can carry a shipment, and their price. Result: Rate[]

    2 methods · 1 property

  • Request class

    A question put to a gateway. The action that supports it answers by setting the result; the gateway hands the request back.

    3 methods

  • Shipping class

    Book the shipment with the carrier. Result: the Label.

    2 methods · 1 property

  • Tracking class

    Where is this parcel? Result: Model\Tracking

    2 methods · 2 properties

Omnibus\Testing

  • Fixtures class

    Addresses and shipments for a carrier's tests: a shop in Paris sending to a customer (in France unless told otherwise). Shipped with the core so a carrier's tests run where the carrier is installed alone.

    3 methods

  • GatewayContractTests trait

    What every Omnibus gateway does, as PHPUnit tests a carrier runs against its own factory, offline: the carrier's API is replaced by its recorded answers (RecordedHttpClient), so no test reaches the network.

    12 methods

  • RecordedHttpClient class

    A carrier's recorded answers in place of its API: no request leaves the process. Each route is "METHOD fragment" or "fragment" (any method), matched when the request's URL contains the fragment - or, for "body:fragment", when its body does (a SOAP operation, say); the first route declared that matches answers.

    9 methods

Omnibus

Config class

final class Config extends ArrayObject Config.php:13

A gateway'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): self

Sets each key not set yet.

Config::validateNotEmpty()

public function validateNotEmpty(array $keys): void

Config::get()

public function get(string $key, mixed $default = null): mixed

Gateway class

final class Gateway implements GatewayInterface Gateway.php:16

A carrier's actions behind one door: the first action supporting a request answers it.

Gateway::__construct()

public function __construct(readonly string $name, readonly string $title, readonly array $actions)

Gateway::getName()

public function getName(): string

Gateway::getTitle()

public function getTitle(): string

Gateway::supports()

public function supports(string $request): bool

Gateway::execute()

public function execute(Request\Request $request): Request\Request

Gateway::rate()

public function rate(Shipment $shipment): array

Gateway::ship()

public function ship(Shipment $shipment): Label

Gateway::track()

public function track(string $trackingNumber, string $locale = 'fr'): TrackingModel

Gateway::pickupPoints()

public function pickupPoints(Address $near, int $limit = 10, ?Parcel $parcel = null): array

Gateway::slip()

public function slip(string $trackingNumber, string $format = Label::PDF): Label

Gateway::cancel()

public function cancel(string $trackingNumber): bool

GatewayFactory class

abstract class GatewayFactory implements GatewayFactoryInterface GatewayFactory.php:20

The Payum way: a carrier's factory fills a Config - its name, title, the options it needs, its API client ("omnibus.api", a closure of the Config) and its actions ("omnibus.action.<name>") - and the gateway is those actions, the API handed to the ones that ask for it.

A "rates" option always gives a rating action from configuration (Action\ConfiguredRatingAction), unless the carrier rates by API.

GatewayFactory::__construct()

public function __construct(protected readonly ?HttpClientInterface $http = null)

GatewayFactory::getName()

public function getName(): string

GatewayFactory::create()

public function create(array $options = []): GatewayInterface

GatewayFactory::createConfig()

public function createConfig(array $options = []): Config

GatewayFactoryInterface interface

interface GatewayFactoryInterface GatewayFactoryInterface.php:6

Builds a carrier's gateway from its options (credentials, sandbox, rates...).

GatewayFactoryInterface::getName()

public function getName(): string

The name gateways are configured with: "mondial_relay", "colissimo".

..

GatewayFactoryInterface::create()

public function create(array $options = []): GatewayInterface

GatewayInterface interface

interface GatewayInterface GatewayInterface.php:18

One carrier, configured: the same questions for all of them. Each typed method is a shortcut for execute() with its request.

GatewayInterface::getName()

public function getName(): string

GatewayInterface::getTitle()

public function getTitle(): string

GatewayInterface::supports()

public function supports(string $request): bool

GatewayInterface::execute()

public function execute(Request $request): Request
Returns

answered

Throws

Exception\RequestNotSupportedException

Throws

Exception\CarrierException

GatewayInterface::rate()

public function rate(Shipment $shipment): array
Returns

cheapest first

GatewayInterface::ship()

public function ship(Shipment $shipment): Label

GatewayInterface::track()

public function track(string $trackingNumber, string $locale = 'fr'): Tracking
$trackingNumber

the label's tracking number, or its carrierReference when it has one

GatewayInterface::pickupPoints()

public function pickupPoints(Address $near, int $limit = 10, ?Parcel $parcel = null): array
Returns

nearest first

GatewayInterface::slip()

public function slip(string $trackingNumber, string $format = Label::PDF): Label
$trackingNumber

the label's tracking number, or its carrierReference when it has one

GatewayInterface::cancel()

public function cancel(string $trackingNumber): bool
$trackingNumber

the label's tracking number, or its carrierReference when it has one

Registry class

final class Registry Registry.php:15

The shop's carriers by name, each built once from its factory and options:

new Registry([new MondialRelayGatewayFactory($http)], [ 'relais' => ['factory' => 'mondial_relay', 'options' => [...]], ]);

Registry::__construct()

public function __construct(iterable $factories, readonly array $config)

Registry::get()

public function get(string $name): GatewayInterface

Registry::has()

public function has(string $name): bool

Registry::options()

public function options(string $name): array
Returns

the options a gateway is configured with

Registry::create()

public function create(string $name, array $overrides = []): GatewayInterface

A gateway built afresh, its configured options with $overrides over them - keys typed in a back office, say. Not kept: get() still gives the configured one.

Registry::names()

public function names(): array
Returns

the configured gateways' names

Registry::all()

public function all(): array

Omnibus\Action

ActionInterface interface

interface ActionInterface ActionInterface.php:8

One thing a carrier does: answers the requests it supports.

ActionInterface::supports()

public function supports(Request $request): bool

ActionInterface::execute()

public function execute(Request $request): void

Sets the request's result, or throws Omnibus\Exception\CarrierException.

ApiAwareInterface interface

interface ApiAwareInterface ApiAwareInterface.php:6

An action that talks to the carrier through the gateway's API client.

ApiAwareInterface::setApi()

public function setApi(object $api): void

ApiAwareTrait trait

trait ApiAwareTrait ApiAwareTrait.php:10

ApiAwareTrait::setApi()

public function setApi(object $api): void

ConfiguredRatingAction class

final class ConfiguredRatingAction implements ActionInterface ConfiguredRatingAction.php:22

Prices from the gateway's configuration, for carriers that publish no rating API (the price is the shop's contract, not a public tariff).

rates: - { service: relay, label: 'Point relais', to_pickup_point: true, days: 4, currency: EUR, countries: [FR, BE], bands: { 500: 490, 1000: 590, 5000: 890 } } # up to grams => minor units

A band applies up to its weight, each parcel priced on its own; a parcel heavier than the last band, or a country not listed, gets no rate for that service.

ConfiguredRatingAction::__construct()

public function __construct(readonly string $carrier, readonly array $rates)

ConfiguredRatingAction::supports()

public function supports(Request $request): bool

ConfiguredRatingAction::execute()

public function execute(Request $request): void

Omnibus\Bridge\Symfony

OmnibusBundle class

final class OmnibusBundle extends AbstractBundle OmnibusBundle.php:56

Omnibus in a Symfony application: the carrier packages installed (omnibus/offline, omnibus/mondial-relay, omnibus/colissimo, omnibus/ups... every omnibus/* package) registered, the shop's gateways built from configuration, Omnibus\Registry autowired, and each gateway injectable by its name:

omnibus: gateways: relais: { factory: mondial_relay, options: { enseigne: '%env(MONDIAL_RELAY_ENSEIGNE)%', private_key: '%env(MONDIAL_RELAY_PRIVATE_KEY)%' } } retrait: { factory: offline }

public function __construct(GatewayInterface $relais) }

An application's own factories (a GatewayFactoryInterface) are registered too, autoconfigured.

OmnibusBundle::configure()

public function configure(DefinitionConfigurator $definition): void

OmnibusBundle::loadExtension()

public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void

Omnibus\Exception

CarrierException class

class CarrierException extends RuntimeException implements OmnibusException CarrierException.php:6

The carrier refused, or could not be reached.

public readonly string $carrier
public readonly ?string $carrierCode

The carrier's own error code, when it gave one

CarrierException::__construct()

public function __construct(public readonly string $carrier, string $message, public readonly ?string $carrierCode = null, ?\Throwable $previous = null)

InvalidConfigException class

final class InvalidConfigException extends LogicException implements OmnibusException InvalidConfigException.php:6

A gateway misconfigured: a credential missing, an unknown factory.

OmnibusException interface

interface OmnibusException extends Throwable OmnibusException.php:6

Every exception Omnibus throws.

RequestNotSupportedException class

final class RequestNotSupportedException extends LogicException implements OmnibusException RequestNotSupportedException.php:8

The carrier does not do that (no pickup points, no cancellation...).

RequestNotSupportedException::for()

public static function for(Request $request, string $gateway): self

Omnibus\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 = []): array

The 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.

$options

the HTTP client's options

Redaction::sensitive()

public static function sensitive(string $name): bool

Whether a parameter, header or field of this name holds a credential.

Redaction::text()

public static function text(string $text, array $secrets = []): string

A 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 = []): \Throwable

A 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): \Throwable

The failure given, the arguments out of its trace (and out of its previous ones'), as zend.exception_ignore_args would have left it.

Omnibus\Model

Address class

final readonly class Address Address.php:6

A postal address: the sender's, the recipient's, a pickup point's.

public string $name
public array $street

one line each, most carriers take up to three

public string $postcode
public string $city
public string $country

ISO 3166-1 alpha-2

public ?string $company
public ?string $email
public ?string $phone

Address::__construct()

public function __construct(public string $name, public array $street, public string $postcode, public string $city, public string $country, public ?string $company = null, public ?string $email = null, public ?string $phone = null)
$street

one line each, most carriers take up to three

Address::line()

public function line(int $index): string

Label class

final readonly class Label Label.php:6

The shipping label (or slip) a carrier issued: its tracking number and the printable document.

const PDF = 'application/pdf'
const ZPL = 'application/zpl'
public string $carrier
public string $trackingNumber
public ?string $content

The document itself, when the carrier sends it inline

public string $format
public ?string $url

Or where to download it, when the carrier hands out a link

public ?string $trackingUrl
public ?string $carrierReference

The carrier's own handle on the booking, for the carriers whose later requests need more than the tracking number (Amazon: the shipment and carrier ids; SF Express: the order id). Opaque: keep it with the order and pass it to track(), slip() and cancel() in place of the tracking number. Null when the tracking number is enough.

Label::__construct()

public function __construct(public string $carrier, public string $trackingNumber, public ?string $content = null, public string $format = self::PDF, public ?string $url = null, public ?string $trackingUrl = null, public ?string $carrierReference = null)

Parcel class

final readonly class Parcel Parcel.php:6

One box: its weight (grams), its size (centimetres), what it is worth (minor units).

public int $weight
public ?int $length
public ?int $width
public ?int $height
public ?int $value
public string $currency
public ?string $reference

Parcel::__construct()

public function __construct(public int $weight, public ?int $length = null, public ?int $width = null, public ?int $height = null, public ?int $value = null, public string $currency = 'EUR', public ?string $reference = null)

Parcel::girth()

public function girth(): ?int

Longest side plus girth, in centimetres - what size bands are built on.

PickupPoint class

final readonly class PickupPoint PickupPoint.php:6

A relay, locker or post office a parcel can be sent to and collected from.

public string $carrier
public string $id
public string $name
public Address $address
public ?float $latitude
public ?float $longitude
public array $openingHours

ISO weekday (1 = Monday) => [[open, close], ...], "HH:MM"

public ?int $distance

Metres from the searched address, when the carrier says

PickupPoint::__construct()

public function __construct(public string $carrier, public string $id, public string $name, public Address $address, public ?float $latitude = null, public ?float $longitude = null, public array $openingHours = [], public ?int $distance = null)
$openingHours

ISO weekday (1 = Monday) => [[open, close], ...], "HH:MM"

Rate class

final readonly class Rate Rate.php:6

What a service costs for a shipment (minor units) and how long it takes.

public string $carrier
public string $service
public string $label
public int $amount
public string $currency
public ?int $days
public bool $toPickupPoint

Rate::__construct()

public function __construct(public string $carrier, public string $service, public string $label, public int $amount, public string $currency = 'EUR', public ?int $days = null, public bool $toPickupPoint = false)

Shipment class

final readonly class Shipment Shipment.php:9

What goes where: from the sender to the recipient - at home, or at a pickup point - in one or more parcels, under a carrier's service.

public Address $sender
public Address $recipient
public array $parcels
public ?string $service
public ?string $pickupPoint
public ?string $reference
public array $options

carrier-specific (insurance, signature, instructions...)

public ?\DateTimeImmutable $shippingDate

Shipment::__construct()

public function __construct(public Address $sender, public Address $recipient, public array $parcels, public ?string $service = null, public ?string $pickupPoint = null, public ?string $reference = null, public array $options = [], public ?\DateTimeImmutable $shippingDate = null)
$options

carrier-specific (insurance, signature, instructions...)

Shipment::weight()

public function weight(): int

Grams, all parcels together.

Shipment::option()

public function option(string $name, mixed $default = null): mixed

Tracking class

final readonly class Tracking Tracking.php:6

Where a parcel is: its latest status and every step so far, oldest first.

public string $carrier
public string $trackingNumber
public TrackingStatus $status
public array $events

Tracking::__construct()

public function __construct(public string $carrier, public string $trackingNumber, public TrackingStatus $status, public array $events = [])

Tracking::latest()

public function latest(): ?TrackingEvent

TrackingEvent class

final readonly class TrackingEvent TrackingEvent.php:5

public \DateTimeImmutable $at
public TrackingStatus $status
public string $description
public ?string $location
public ?string $code

The carrier's own code, kept for whoever needs the detail

TrackingEvent::__construct()

public function __construct(public \DateTimeImmutable $at, public TrackingStatus $status, public string $description, public ?string $location = null, public ?string $code = null)

TrackingStatus enum

enum TrackingStatus TrackingStatus.php:6

Every carrier's statuses, folded onto one scale.

case PENDING = 'pending'
case IN_TRANSIT = 'in_transit'
case OUT_FOR_DELIVERY = 'out_for_delivery'
case AVAILABLE_FOR_PICKUP = 'available_for_pickup'
case DELIVERED = 'delivered'
case EXCEPTION = 'exception'
case RETURNED = 'returned'
case UNKNOWN = 'unknown'

TrackingStatus::isFinal()

public function isFinal(): bool

Omnibus\Request

Cancel class

final class Cancel extends Request Cancel.php:6

Cancel a shipment not handed over yet. Result: true when the carrier voided it.

public readonly string $trackingNumber

Cancel::__construct()

public function __construct(public readonly string $trackingNumber)

GetSlip class

final class GetSlip extends Request GetSlip.php:8

The label of a shipment booked earlier, again (a reprint). Result: the Label.

public readonly string $trackingNumber
public readonly string $format

GetSlip::__construct()

public function __construct(public readonly string $trackingNumber, public readonly string $format = Label::PDF)

GetSlip::getLabel()

public function getLabel(): ?Label

Paperless class

final class Paperless extends Request Paperless.php:13

Customs documents sent electronically (paperless trade) for a shipment leaving the customs union. Result: true once the carrier accepted them.

Part of the contract (and of the conformance suite) for the carriers that offer it; no carrier package answers it yet: supports(Paperless::class) is false for each of them, and execute() raises RequestNotSupportedException.

public readonly string $trackingNumber
public readonly array $documents

type (invoice, proforma...) => PDF content

Paperless::__construct()

public function __construct(public readonly string $trackingNumber, public readonly array $documents)
$documents

type (invoice, proforma...) => PDF content

Pickup class

final class Pickup extends Request Pickup.php:10

The pickup points near an address (that can take this parcel). Result: PickupPoint[]

public readonly Address $near
public readonly int $limit
public readonly ?Parcel $parcel

Pickup::__construct()

public function __construct(public readonly Address $near, public readonly int $limit = 10, public readonly ?Parcel $parcel = null)

Pickup::getPoints()

public function getPoints(): array

Rating class

final class Rating extends Request Rating.php:9

The services that can carry a shipment, and their price. Result: Rate[]

public readonly Shipment $shipment

Rating::__construct()

public function __construct(public readonly Shipment $shipment)

Rating::getRates()

public function getRates(): array

Request class

abstract class Request Request.php:9

A question put to a gateway. The action that supports it answers by setting the result; the gateway hands the request back.

Request::setResult()

public function setResult(mixed $result): void

Request::getResult()

public function getResult(): mixed

Request::isAnswered()

public function isAnswered(): bool

Shipping class

final class Shipping extends Request Shipping.php:9

Book the shipment with the carrier. Result: the Label.

public readonly Shipment $shipment

Shipping::__construct()

public function __construct(public readonly Shipment $shipment)

Shipping::getLabel()

public function getLabel(): ?Label

Tracking class

final class Tracking extends Request Tracking.php:8

Where is this parcel? Result: Model\Tracking

public readonly string $trackingNumber
public readonly string $locale

Tracking::__construct()

public function __construct(public readonly string $trackingNumber, public readonly string $locale = 'fr')

Tracking::getTracking()

public function getTracking(): ?TrackingModel

Omnibus\Testing

Fixtures class

final class Fixtures Fixtures.php:14

Addresses and shipments for a carrier's tests: a shop in Paris sending to a customer (in France unless told otherwise). Shipped with the core so a carrier's tests run where the carrier is installed alone.

Fixtures::shop()

public static function shop(): Address

Fixtures::customer()

public static function customer(string $country = 'FR'): Address

Fixtures::shipment()

public static function shipment(int ...$grams): Shipment

One parcel of 800 g unless weights (grams) are given, reference CMD-1042.

GatewayContractTests trait

trait GatewayContractTests GatewayContractTests.php:61

What every Omnibus gateway does, as PHPUnit tests a carrier runs against its own factory, offline: the carrier's API is replaced by its recorded answers (RecordedHttpClient), so no test reaches the network.

It checks that: - the factory's name is the name of the gateway it builds, and a Registry builds that gateway from {factory, options}; building it calls nothing; - each required option missing is an InvalidConfigException naming it; an operation that needs an option of its own (operationOptions()) is not supported without it, rather than failing when called; - supports() is what the gateway does, for each request: a supported one is answered with models that keep their invariants (the carrier's name, ids, amounts in minor units, ISO currencies and countries, rates cheapest first, pickup points nearest first and no more than asked, tracking events oldest first, a boolean for Cancel and Paperless), an unsupported one raises RequestNotSupportedException before any request is sent; - a "rates" option replaces the carrier's rating API: the configured price, no request; - every failure of the carrier - HTTP 401, 403, 404, 429, 500 and 503, a network error, a body it cannot read, a login refused - is a CarrierException naming the carrier, never an HTTP client's exception, a TypeError, or an answer made of nothing.

final class UpsContractTest extends TestCase { use GatewayContractTests;

    protected function gatewayFactory(HttpClientInterface $http): GatewayFactoryInterface { return new UpsGatewayFactory($http); }
    protected function gatewayOptions(): array { return ['client_id' => 'id', 'client_secret' => 's', 'account_number' => 'A1B2C3', 'sandbox' => true]; }
    protected function recordedAnswers(): array { return ['/oauth/token' => ['access_token' => 't'], '/Shop' => [...], ...]; }
    protected function sessionRoutes(): array { return ['/oauth/token']; }
}

The hooks below (shipment, tracking number, documents...) have defaults a carrier overrides where it legitimately differs. Requires phpunit/phpunit (the carrier's, in require-dev) and symfony/http-client.

GatewayContractTests::testTheFactoryNamesTheGatewayItBuilds()

public function testTheFactoryNamesTheGatewayItBuilds(): void

GatewayContractTests::testTheRegistryBuildsTheGatewayFromItsConfiguration()

public function testTheRegistryBuildsTheGatewayFromItsConfiguration(): void

GatewayContractTests::testEachRequiredOptionIsRequired()

public function testEachRequiredOptionIsRequired(): void

GatewayContractTests::testRating()

public function testRating(): void

GatewayContractTests::testShipping()

public function testShipping(): void

GatewayContractTests::testTracking()

public function testTracking(): void

GatewayContractTests::testPickupPoints()

public function testPickupPoints(): void

GatewayContractTests::testSlip()

public function testSlip(): void

GatewayContractTests::testCancellation()

public function testCancellation(): void

GatewayContractTests::testPaperless()

public function testPaperless(): void

GatewayContractTests::testConfiguredRatesReplaceTheRatingApi()

public function testConfiguredRatesReplaceTheRatingApi(): void

GatewayContractTests::testTheCarriersFailuresAreCarrierExceptions()

public function testTheCarriersFailuresAreCarrierExceptions(): void

RecordedHttpClient class

final class RecordedHttpClient implements HttpClientInterface RecordedHttpClient.php:37

A carrier's recorded answers in place of its API: no request leaves the process. Each route is "METHOD fragment" or "fragment" (any method), matched when the request's URL contains the fragment - or, for "body:fragment", when its body does (a SOAP operation, say); the first route declared that matches answers.

new RecordedHttpClient([ 'POST /security/v1/oauth/token' => ['access_token' => 'tok', 'expires_in' => 14399], '/api/rating/' => file_get_contents(__DIR__.'/recorded/rate.json'), 'GET /label/' => RecordedHttpClient::answer('%PDF-1.4', 200, ['content-type' => 'application/pdf']), '/track/' => fn (string $method, string $url, array $options) => [...], 'POST body:<TrackRequest' => '<soap:Envelope>...</soap:Envelope>', ]);

An answer is an array (sent as JSON), a string (the body as it is), a MockResponse, or a closure of the request returning one of those. A request no route matches fails at the transport (the carrier sees a network error) and is listed by unanswered(), so a test can say which route is missing.

failing() gives the same client answering every request with one failure - an HTTP status, a network error, a body no carrier can read - except the routes kept (a login, say), for checking how a carrier reports its errors.

Requires symfony/http-client (a carrier calling an API has it already).

RecordedHttpClient::__construct()

public function __construct(readonly array $answers = [], readonly ?\Closure $failure = null, readonly array $kept = [])
$answers

route => answer

$kept

routes that keep their answer while failing

RecordedHttpClient::answer()

public static function answer(array|string $body, int $status = 200, array $headers = []): MockResponse

A response with its status and headers, for an answer that is not a plain 200.

RecordedHttpClient::networkError()

public static function networkError(string $message = 'Connection refused (recorded)'): MockResponse

The answer of a network that fails: no status, no body.

RecordedHttpClient::failing()

public function failing(MockResponse $failure, array $kept = []): self

The same routes, every request but those of $kept answered with $failure.

RecordedHttpClient::request()

public function request(string $method, string $url, array $options = []): ResponseInterface

RecordedHttpClient::stream()

public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface

RecordedHttpClient::withOptions()

public function withOptions(array $options): static

RecordedHttpClient::requests()

public function requests(): array
Returns

every request made, in order

RecordedHttpClient::unanswered()

public function unanswered(): array
Returns

"METHOD url" of each request no route answered