jooservices / state-machine
A PHP 8.5+ configuration-driven finite state machine for any PHP object
Requires
- php: ^8.5
- psr/event-dispatcher: ^1.0
Requires (Dev)
- captainhook/captainhook: ^5.23
- captainhook/plugin-composer: ^5.3
- fakerphp/faker: ^1.24
- friendsofphp/php-cs-fixer: ^3.65
- laravel/pint: ^1.18
- phpbench/phpbench: ^1.6
- phpmd/phpmd: ^2.15
- phpstan/phpstan: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^12.0 || ^13.0
- squizlabs/php_codesniffer: ^3.8 || ^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-11 12:58:18 UTC
README
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.
Latest stable release: v4.0.0 — no backward compatibility with the retired v1.x archive.
Features
- 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.5with no Laravel/Symfony runtime requirement
Requirements
- PHP
^8.5 - Composer 2.x
Installation
composer require jooservices/state-machine:^4.0
Quick start
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
Design notes
- 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
StateAccessExceptionwhen 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:
- Documentation Hub
- Changelog
- Support
- Governance
- Workflows
- phpDocumentor config:
phpdoc.dist.xml - Installation
- Quick Start
Development
make validate
make install
make lint
make test
make ci
Or with Composer inside Docker / host PHP 8.5:
composer validate --strict
composer lint
composer lint:all
composer test
composer test:coverage
composer check
composer ci
Contributor workflow details live in:
Branch, release, CI, and integration details are documented in WORKFLOWS.md and the linked development guides.
Community
License
This project is licensed under the MIT License.