Skip to content
docsv0.1.0

ProcessDefinition

A process definition: a set of `milpa/workflow` {@see StateDefinition}s connected by {@see TransitionDefinition}s, one of them flagged `isInitial`. Implements {@see DefinitionContract} so a {@see Reducer} can fold events against it directly, while also exposing the richer workflow entities (states, raw transitions, gates) a caller composing an actual process — or {@see HumanGate} — needs. `initialState()` is derived from `StateDefinition::isInitial()` (exactly one state must carry it) rather than accepted as a separate constructor argument, so there is exactly one source of truth for "where does this process start". At construction, every transition's `fromState`/`toState` must resolve to a state passed in, and the definition is validated acyclic among UNGATED, NON-SUBPROCESS transitions only: a `GateDefinition` attached to a state's outgoing transitions marks that state a human decision point, and a {@see SubprocessSpec} marks it a "waiting on a child process" point — either kind of checkpoint breaks any loop through it (see {@see self::assertAcyclicAmongUngatedTransitions()} for why a full-graph acyclic check would incorrectly reject a `review_gate --reject--> draft --submit--> review_gate` shape, which is a legitimate revise-and-resubmit loop). A state may ALSO be declared a subprocess state via the `$subprocesses` constructor argument (see {@see self::subprocessFor()}) — mutually exclusive with both being terminal and carrying a gate, enforced at construction.

ProcessDefinition::__construct()

public function __construct(array $states, array $transitions, array $subprocesses = []):

Parameters

Parameters of __construct()
NameTypeDescription
$stateslist<StateDefinition>every state this process can occupy; exactly one must have `isInitial() === true`
$transitionslist<TransitionDefinition>every transition between two of `$states`
$subprocessesarray<string, SubprocessSpec>subprocess declarations keyed by the state code they wait at — see {@see self::subprocessFor()}

Throws

\RuntimeException on a duplicate state code, a transition referencing an unknown state, a state count other than exactly-one-initial, a subprocess spec referencing an unknown or terminal state, a state carrying both a subprocess spec and a gate, or a cycle among ungated, non-subprocess transitions

ProcessDefinition::initialState()

public function initialState(): string

The state a fresh process instance starts in — the one state with `isInitial() === true`.

ProcessDefinition::transitionsFrom()

public function transitionsFrom(string $state): array

The narrow `{name, to}` shape {@see Reducer} needs, projected down from the real workflow `TransitionDefinition`s: `name` is the transition's `code` (the literal event `type` that advances it — see {@see Reducer::apply()}), `to` is its destination state's code. Unknown `$state` yields an empty list, matching {@see DefinitionContract}'s "no transitions" case.

Parameters

Parameters of transitionsFrom()
NameTypeDescription
$statestring

ProcessDefinition::workflowTransitionsFrom()

public function workflowTransitionsFrom(string $state): array

The raw `milpa/workflow` transitions leaving `$state`, unprojected — for callers that need more than `{name, to}` (e.g. reading a transition's attached {@see GateDefinition}s directly). Prefer {@see self::transitionsFrom()} or {@see self::gateFor()} where they suffice.

Parameters

Parameters of workflowTransitionsFrom()
NameTypeDescription
$statestring

ProcessDefinition::states()

public function states(): array

Every state code in this definition, in the order `$states` was passed to the constructor.

ProcessDefinition::isTerminal()

public function isTerminal(string $state): bool

Whether `$state` is terminal (`StateDefinition::isTerminal()`). An unknown `$state` is treated as not terminal.

Parameters

Parameters of isTerminal()
NameTypeDescription
$statestring

ProcessDefinition::gateFor()

public function gateFor(string $state): ?Milpa\Workflow\Entities\GateDefinition

The gate guarding `$state`'s outgoing transitions: the first {@see GateDefinition} found attached to any of `$state`'s transitions, or `null` when none of them carry one. A gated state's transitions are expected to share the SAME gate instance (one human checkpoint per state, however many outcomes it offers) — this is how {@see HumanGate} finds the single gate to open for a process instance sitting at `$state`.

Parameters

Parameters of gateFor()
NameTypeDescription
$statestring

ProcessDefinition::subprocessFor()

public function subprocessFor(string $state): ?Milpa\Orchestrator\SubprocessSpec

The {@see SubprocessSpec} declaring `$state` a subprocess state — the process WAITS here for a child process (resolved by name through a {@see ProcessDefinitionRegistry}) to reach its own terminal state, exactly like {@see self::gateFor()}'s state waits for a human decision. `null` when `$state` is not a subprocess state.

Parameters

Parameters of subprocessFor()
NameTypeDescription
$statestring

ProcessDefinition::isSubprocess()

public function isSubprocess(string $state): bool

Whether `$state` is a subprocess state — shorthand for {@see self::subprocessFor()} `!== null`.

Parameters

Parameters of isSubprocess()
NameTypeDescription
$statestring