jooservices / state-machine
A PHP 8.5+ configuration-driven finite state machine for any PHP object
v4.0.0
2026-09-04 23:48 UTC
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-09-04 23:51:37 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.
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
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 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
developand PRs back intodevelop - release preparation uses
release/<version>fromdevelop, then PRs intomaster - releases are tagged from
master mastermerges back intodevelopafter release or hotfix completion
Community
GitHub Actions and Services
See WORKFLOWS.md. Current coverage:
CI+CI Gate: security, lint matrix, tests, 95% coverageCommitlint+Semantic PR TitleRelease(tag-driven — do not use until owner approvesv4.0.0)- OpenSSF Scorecard / optional Codacy / Fortify when secrets exist
License
This project is licensed under the MIT License.