Search by

jooservices / state-machine

A PHP 8.5+ configuration-driven finite state machine for any PHP object

Maintainers

Package info

github.com/jooservices/state-machine

pkg:composer/jooservices/state-machine

Transparency log

Statistics

Installs: 4

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v4.0.0 2026-09-04 23:48 UTC

This package is auto-updated.

Last update: 2026-09-04 23:51:37 UTC


README

CI OpenSSF Scorecard PHP Version License: MIT Release Packagist Version

The JOOservices State Machine is a PHP 8.5+ configuration-driven finite state machine for any PHP object — DTOs, POPOs, or framework models. Zero framework coupling. State is a string property on the subject.

Package name: jooservices/state-machine

Latest stable release: v4.0.0 — no backward compatibility with the retired v1.x archive.

Install

composer require jooservices/state-machine:^4.0

Quick example

use JOOservices\StateMachine\StateMachineFactory;

final class Order
{
    public function __construct(
        public string $status = 'pending',
    ) {}
}

$config = [
    'property' => 'status',
    'states' => ['pending', 'confirmed', 'shipped', 'cancelled'],
    'initial_state' => 'pending',
    'transitions' => [
        'confirm' => ['from' => ['pending'], 'to' => 'confirmed'],
        'ship' => ['from' => ['confirmed'], 'to' => 'shipped'],
        'cancel' => ['from' => ['pending', 'confirmed'], 'to' => 'cancelled'],
    ],
];

$order = new Order();
$machine = (new StateMachineFactory())->create($order, 'order', $config);

if ($machine->can('confirm')) {
    $machine->apply('confirm');
}

echo $machine->getState(); // confirmed

What is supported today

  • configuration-driven graphs validated at construction time
  • can() / apply() / getAvailableTransitions()
  • pluggable state accessors (property reflection or getter/setter)
  • guards and before/after callbacks as class strings
  • optional PSR-14 lifecycle events
  • multiple independent graphs per subject (separate machine instances)
  • pure PHP 8.5+ with no Laravel/Symfony runtime requirement

Important current limitations

  • guards and callbacks are constructed with new $class() (no container resolution)
  • guard/callback class-strings are validated at config construction (must exist and implement the contract)
  • accessors throw StateAccessException when the write target is missing or readonly
  • event dispatcher is optional; consumers bring their own PSR-14 implementation
  • no built-in persistence, Eloquent casts, or service providers

Documentation

Start with:

Development

make install
make lint
make test
make ci

Or with Composer inside Docker / host PHP 8.5:

composer lint
composer lint:all
composer test
composer test:coverage
composer check
composer ci

Contributor workflow details live in:

Approved Git flow summary:

  • normal feature and fix work branches from develop and PRs back into develop
  • release preparation uses release/<version> from develop, then PRs into master
  • releases are tagged from master
  • master merges back into develop after release or hotfix completion

Community

GitHub Actions and Services

See WORKFLOWS.md. Current coverage:

  • CI + CI Gate: security, lint matrix, tests, 95% coverage
  • Commitlint + Semantic PR Title
  • Release (tag-driven — do not use until owner approves v4.0.0)
  • OpenSSF Scorecard / optional Codacy / Fortify when secrets exist

License

This project is licensed under the MIT License.