SIGNALS Documentation
API Reference

Demand Source Registry

Contract for registering availability demand definitions and their container-resolved resolvers.

Overview

App\Services\DemandSourceRegistry maps availability demand source types to display metadata and resolver classes.

Core binds the registry as a singleton in AppServiceProvider. Repair actions resolve their source-specific handler through it, while Gantt output uses registered display names and colours.

Public surface

Method Purpose
register() Store one DemandSourceDefinition under its type
get() Return a definition for a type or throw
resolve() Resolve the definition's resolver class from Laravel's container
has() Check whether a source type is registered
all() Return the complete keyed definition map

Accepted definition and resolver contracts

The accepted registration value is App\Services\DemandSourceDefinition:

new DemandSourceDefinition(
    type: 'rental_item',
    displayName: 'Bookings',
    resolverClass: RentalItemDemandResolver::class,
    colour: '#3B82F6',
    icon: 'calendar',
);

type is the stable registry key. displayName, colour, and icon provide presentation metadata. resolverClass is a class-string for an App\Contracts\DemandResolverContract implementation.

That resolver contract requires:

  • sourceType(): string
  • syncDemands(Model $source): void
  • releaseDemands(Model $source): void
  • resolvePhase(Model $source): DemandPhase
  • buildMetadata(Model $source): array

syncDemands() must be idempotent: repeated calls for the same source converge on the same demand set instead of creating duplicates. Resolvers are intentionally stateful application services that create, update, or release demand records; they are not pure functions.

Identity, collisions, and failure behavior

register() stores a definition under its type. A later definition with the same type replaces the earlier definition; duplicate registration is not rejected.

Both get($type) and resolve($type) throw InvalidArgumentException with Unknown demand source: {type} when the type is missing. resolve() first calls get(), then asks Laravel's container to instantiate the declared resolver class.

The registry does not validate that a resolver's sourceType() matches its definition key at registration time. A registration is responsible for keeping those values aligned and for supplying a container-resolvable class that implements DemandResolverContract.

Current core registrations

The complete built-in set is:

Type Display name Resolver Colour Icon
rental_item Bookings RentalItemDemandResolver #3B82F6 calendar
flightcase Flightcases FlightcaseDemandResolver #0EA5E9 cube
virtual_stock_intake Virtual Stock VirtualStockDemandResolver #8B5CF6 arrow-down-circle
repair Repair RepairDemandResolver #EF4444 shield-exclamation
warehouse_transfer Warehouse Transfers WarehouseTransferDemandResolver #F59E0B arrows-right-left

There is no priority or sorting contract. all() returns the keyed definition map, while current write workflows resolve the exact type they own. Catalogue order does not determine demand precedence.

Runtime consumption

Current consumers use the registry in two forms:

  1. repair actions call resolve('repair') and then syncDemands()
  2. AvailabilityService reads registered colours and display names for Gantt demand bars, guarding with has() so unknown historical types can fall back safely

Other current core workflows for rental items, flightcases, virtual-stock intakes, and warehouse transfers resolve their concrete resolver classes directly. Their definitions are still part of this registry's complete source catalogue, but the current framework does not route every built-in write through resolve().

When resolve() is used, the flightcase constructs the resolver so its dependencies remain injectable and the registry stores definitions rather than resolver instances.

Worked example

The framework's repair actions use the current core definition like this:

app(DemandSourceRegistry::class)
    ->resolve('repair')
    ->syncDemands($repair);

The registry resolves RepairDemandResolver through the container. The resolver then synchronises the demand rows for that repair according to the idempotent resolver contract.