Search by

small / workflow

small

Framework-independent PHP workflow management library.

0.1.0 2026-11-02 20:57 UTC

This package is auto-updated.

Last update: 2026-11-02 21:09:33 UTC


README

Small Workflow

Framework-independent PHP workflow management package (small/workflow).

The engine owns business validation orchestration and execution order. The application owns business entities, persistence implementation, transactions and locking mechanisms.

Lifecycle

When configured with a lock and a persister, WorkflowEngine::execute() performs:

  1. WorkflowLock::lock($context) — acquire the business resource lock.
  2. Resolve current states and validate business rules via WorkflowState::getPossibleActions() and WorkflowGuard::check() inside the lock.
  3. Resolve a permitted transition and invoke WorkflowActionHandler::execute() to mutate business entities.
  4. WorkflowPersister::persist($context) — application persists its entities.
  5. Dispatch completed event, or failed when the handler/persister fails.
  6. Always WorkflowLock::unlock($context) in finally after successful acquisition.

If locking fails, the engine does not unlock a lock it never acquired. Validation failures do not call handler or persister.

Quick start

name: approval
parallel: false
states:
  draft: App\Workflow\DraftState
  approved: App\Workflow\ApprovedState
transitions:
  submit:
    from: draft
    to: approved
    action: submit
    guards:
      - App\Workflow\CanSubmit
$definition = (new WorkflowDefinitionLoader())->fromFile('workflow.yaml');
$engine = new WorkflowEngine(
    definition: $definition,
    handlers: ['submit' => $submitHandler],
    services: [CanSubmit::class => $guard],
    events: $dispatcher,
    lock: $applicationLock,
    persister: $businessEntityPersister,
);

$context = new WorkflowContext(['entity' => $entity, 'user' => $user]);
$decision = $engine->can(AffaireAction::Submit, $context);
$result = $engine->execute(AffaireAction::Submit, $context);

can() and evaluate() are read-only advisory operations; execute() rechecks business validations under the lock.

Persistence and consistency

This package does not contain an ORM, a database schema or a repository for workflow state. A WorkflowPersister implementation delegates to business entities/managers owned by the consumer. A WorkflowLock implementation must be appropriate to the runtime (row lock, advisory lock or distributed lock) and scoped to the relevant business resource.

Important: locking is optional for compatibility, but production consumers with concurrent writers should supply a lock. The package cannot create an atomic transaction merely by holding a lock. The application must provide a transaction boundary if it needs rollback of mutations, persistence and event/outbox consistency. A failure after an in-memory entity mutation does not roll back that object automatically. The completed event is sent only once the persister returns successfully, but event dispatch is not transactional by default.

Parallel states

With parallel: true, multiple states may be active. All source states of a transition must be present; the transition replaces those sources with its targets and preserves other active states. The engine does not spawn workers or manage distributed execution.

Quality gates

vendor/bin/phpstan analyse --no-progress
XDEBUG_MODE=coverage vendor/bin/pest --coverage --min=100

See docs/00-index.md for the chapter-by-chapter documentation.