PHPackages                             uuf6429/state-engine - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. uuf6429/state-engine

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

uuf6429/state-engine
====================

A library providing interfaces and basic implementation of a State Engine or Machine

2.1.0(1y ago)1171MITPHPPHP ^7.4 || ^8.0

Since Jul 21Pushed 1y ago1 watchersCompare

[ Source](https://github.com/uuf6429/state-engine-php)[ Packagist](https://packagist.org/packages/uuf6429/state-engine)[ Docs](https://github.com/uuf6429/state-engine-php)[ Fund](https://paypal.me/uuf6429)[ GitHub Sponsors](https://github.com/uuf6429)[ RSS](/packages/uuf6429-state-engine/feed)WikiDiscussions main Synced 5d ago

READMEChangelog (6)Dependencies (6)Versions (7)Used By (0)

🚦 State Engine / Machine (PHP)
==============================

[](#-state-engine--machine-php)

[![CI](https://github.com/uuf6429/state-engine-php/actions/workflows/ci.yml/badge.svg)](https://github.com/uuf6429/state-engine-php/actions/workflows/ci.yml)[![codecov](https://camo.githubusercontent.com/e511913ed0d90689c94568cfeccd1263432d3f167d9831122cfec3e55e385f95/68747470733a2f2f636f6465636f762e696f2f67682f757566363432392f73746174652d656e67696e652d7068702f6272616e63682f6d61696e2f67726170682f62616467652e737667)](https://codecov.io/gh/uuf6429/state-engine-php)[![Minimum PHP Version](https://camo.githubusercontent.com/b4c5b22c5d4b22afa104d352e9212e63318131d682168261e127b6f9f570cbea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545372e34253230253743253230253545382d3838393242462e737667)](https://php.net/)[![License](https://camo.githubusercontent.com/6967a5c480ca38d67233869163d26d497e5f1dee86b0fc30571509fe5c2a54bd/68747470733a2f2f706f7365722e707567782e6f72672f757566363432392f73746174652d656e67696e652f6c6963656e7365)](https://packagist.org/packages/uuf6429/state-engine)[![Latest Stable Version](https://camo.githubusercontent.com/2435e0a0b016c917f820b89c4c2c553b578a65380da889a015f83b22127d2405/68747470733a2f2f706f7365722e707567782e6f72672f757566363432392f73746174652d656e67696e652f76657273696f6e)](https://packagist.org/packages/uuf6429/state-engine)[![Latest Unstable Version](https://camo.githubusercontent.com/853316533594794ca0e9de3c8233231d23da20a553729f697853abb5fa0a1121/68747470733a2f2f706f7365722e707567782e6f72672f757566363432392f73746174652d656e67696e652f762f756e737461626c65)](https://packagist.org/packages/uuf6429/state-engine)

This library provides some interfaces and a basic implementation of a State Engine or State Machine.

✨ **Highlights:**

- Dual functionality:
    1. Either as a basic state engine; switching to a desired state as long the transition is defined ([see "JiraIssueTest"](#jiraissuetest-state-engine))
    2. Or a more sophisticated state machine; same as above but matching data for any state ([see "TurnstileTest"](#turnstiletest-state-machine))
- Highly composable - everything can be replaced as desired
- [PSR-14](http://www.php-fig.org/psr/psr-14/) (Event Dispatcher) compatible
- Fluent builder interface ([see "From Scratch"](#from-scratch))
- Generates Mermaid or PlantUML markup ([see "Examples &amp; Testing"](#-examples--testing))

🔌 Installation
--------------

[](#-installation)

The recommended and easiest way to install this library is through [Composer](https://getcomposer.org/):

```
composer require "uuf6429/state-engine-php"
```

🧐 Why?
------

[](#-why)

In principle such an engine is easy to implement, but in practice it is typically implemented badly or forgotten.

For instance, one might have an `is_active` field thinking there will not be other states and then later on an `is_pending` field is needed, at which point refactoring flags to state is too late.

In any case, this library abstracts away that situation or at least decreases the amount of code.

🤔 How?
------

[](#-how)

There are a few key parts to how this works:

- **State** - an object representing a single state of a model. So models may have different state levels, for example a door can have *open* and *closed* states, but it can also be *locked* and *unlocked*. In such a case, either consider the door lock as a separate model (with a separate engine instance) or merge all the states: *open*, *closed-unlocked*and *closed-locked*.
- **Transition** - an object representing a transition from one state to another. This is how you define the various state flows that your model can go through.
- **TransitionRepository** - an object that is aware of and provides all possible allowed transitions.
- **Engine** - an object that performs the transition of a model from one state to another. Usually you would have an engine instance for each stateful model in your application.

🚀 Usage
-------

[](#-usage)

You have the possibility to use it from scratch or plug it into your existing. There are basically three parts to it:

1. configuring the engine (creating states and transitions)
2. using the engine (eg, in a web controller or service)
3. (optionally) handling events (with the same event dispatcher provided to the engine)

A slightly different situation would be when you need to provide a list of valid transitions, for example to the user. In this case, having the [`StateTraversion`](https://github.com/uuf6429/state-engine-php/blob/main/src/Implementation/Traits/StateTraversion.php)trait on the repository would be useful.

### From Scratch

[](#from-scratch)

Here's a quick &amp; dirty example with the provided implementation (that assumes that there is a "door" model):

```
use App\Models\Door;  // example model that implements StateAwareInterface

use uuf6429\StateEngine\Implementation\Builder;
use uuf6429\StateEngine\Implementation\Entities\State;

$doorStateManager = Builder::create()
    ->defState('open', 'Open')
    ->defState('closed', 'Closed')
    ->defState('locked', 'Locked')
    ->defTransition('open', 'closed', 'Close the door')
    ->defTransition('closed', 'locked', 'Lock the door')
    ->defTransition('locked', 'closed', 'Unlock the door')
    ->defTransition('closed', 'open', 'Open the door')
    ->getEngine(); // you can pass an event dispatcher to the engine here

// find Door 123 (laravel-style repository-model)
$door = Door::find(123);

// close the door :)
$doorStateManager->changeState($door, new State('closed'));
```

### From Scratch (Custom)

[](#from-scratch-custom)

You don't like how the Engine works? Or you feel that State could have more details? Then you're in luck! With the whole library based on interfaces, you can easily replace parts of the implementation. For example, you could store states or transitions in a database, in which case you can have your own `TransitionRepository` that accesses the database.

### Existing Code

[](#existing-code)

The library provides some flexibility so that you can connect your existing code with it. In more complicated scenarios, you may have to build a small layer to bridge the gap. The example below illustrates how one can handle models with flags instead of a single state.

```
use App\Models\Door;  // example model

use uuf6429\StateEngine\Implementation\Builder;
use uuf6429\StateEngine\Implementation\Entities\State;

$door = Door::find(123);

$doorStateMutator = Builder::makeStateMutator(
    // define how we get the state
    static function () use ($door): State {
        if ($door->is_locked) {
            return new State('locked');
        }

        return $door->is_open
            ? new State('open')
            : new State('closed');
    },
    // define how we set the state
    static function (State $newState) use ($door): void {
        $door->update([
            'is_locked' => $newState->getName() === 'locked',
            'is_open' => $newState->getName() === 'open',
        ]);
    }
);

// assumes engine $doorStateManager was already defined
$doorStateManager->changeState($doorStateMutator, new State('closed'));
```

😎 Examples &amp; Testing
------------------------

[](#-examples--testing)

You can find some examples in this readme as well as [the tests](https://github.com/uuf6429/state-engine-php/tree/main/tests), some of which are explained below.

### [`JiraIssueTest`](https://github.com/uuf6429/state-engine-php/blob/main/tests/JiraIssueTest.php) State Engine

[](#jiraissuetest-state-engine)

This test provides a realistic example of how Jira Issue states could be set up.

The test also generates the Mermaid diagram below, thanks to the [Mermaidable trait](https://github.com/uuf6429/state-engine-php/blob/main/src/Implementation/Traits/Mermaidable.php):

 ```
stateDiagram
    s1_backlog: Backlog
    s2_analysis: Analysis
    s3_in_dev: In Dev
    s4_ready_for_dev: Ready for Dev
    s5_ready_for_qa: Ready for QA
    s6_ready_for_release: Ready for Release
    s7_in_qa: In QA
    s8_resolved: Resolved
    s1_backlog --> s2_analysis: Begin analysis
    s1_backlog --> s3_in_dev: Fast-track for development
    s2_analysis --> s4_ready_for_dev: Analysis complete
    s2_analysis --> s1_backlog: Return to backlog
    s4_ready_for_dev --> s2_analysis: Need more details
    s4_ready_for_dev --> s3_in_dev: Begin development
    s3_in_dev --> s5_ready_for_qa: Send to QA
    s3_in_dev --> s6_ready_for_release: Fast-track for release
    s3_in_dev --> s4_ready_for_dev: Stop development
    s5_ready_for_qa --> s7_in_qa: Begin testing
    s7_in_qa --> s4_ready_for_dev: QA Failed
    s7_in_qa --> s6_ready_for_release: QA Passed
    s6_ready_for_release --> s8_resolved: Released
    s8_resolved --> s1_backlog: Reopen
```

      Loading ### [`TurnstileTest`](https://github.com/uuf6429/state-engine-php/blob/main/tests/JiraIssueTest.php) State Machine

[](#turnstiletest-state-machine)

This test illustrates how a [state machine](https://en.wikipedia.org/wiki/Finite-state_machine) can be used to model a [turnstile gate](https://en.wikipedia.org/wiki/Turnstile). As before, here's the generated diagram:

 ```
stateDiagram
    s1_locked: Impassable
    s2_open: Passable
    s1_locked --> s2_open: Coin placed
    s2_open --> s1_locked: Person walks through
```

      Loading Here's how the state machine definition looks like and how it could be used:

```
use App\Models\Turnstile;  // example model that implements StateAwareInterface

use uuf6429\StateEngine\Implementation\Builder;

$turnstileStateMachine = Builder::create()
    // make states
    ->defState('locked', 'Impassable')
    ->defState('open', 'Passable')
    // make transitions
    ->defDataTransition('locked', ['insert_coin'], 'open', 'Coin placed')
    ->defDataTransition('open', ['walk_through'], 'locked', 'Person walks through')
    ->getMachine();

$turnstile = Turnstile::find(123);

// put coin in turnstile (notice that the final state is not mentioned)
$turnstileStateMachine->processInput($turnstile, ['insert_coin']);

// now $turnstile will be in "open" state
```

###  Health Score

30

—

LowBetter than 64% of packages

Maintenance35

Infrequent updates — may be unmaintained

Popularity8

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~228 days

Recently: every ~285 days

Total

6

Last Release

616d ago

Major Versions

1.1.0 → 2.0.02021-07-24

### Community

Maintainers

![](https://www.gravatar.com/avatar/450767af6ef832ad662c169bf718d6d25c025c08b2d91b810959d190bccebba1?d=identicon)[uuf6429](/maintainers/uuf6429)

---

Top Contributors

[![uuf6429](https://avatars.githubusercontent.com/u/230049?v=4)](https://github.com/uuf6429 "uuf6429 (11 commits)")

---

Tags

enginemachinephpstatestate-enginestate-machineuuf6429workflowstateworkflowenginemachinestate-machineuuf6429state-engine

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/uuf6429-state-engine/health.svg)

```
[![Health](https://phpackages.com/badges/uuf6429-state-engine/health.svg)](https://phpackages.com/packages/uuf6429-state-engine)
```

###  Alternatives

[yohang/finite

A simple PHP Finite State Machine

1.3k3.5M10](/packages/yohang-finite)[symfony/workflow

Provides tools for managing a workflow or finite state machine

62842.3M170](/packages/symfony-workflow)[ringierimu/state-workflow

Laravel State Workflow provide tools for defining and managing workflows and activities with ease.

3251.1k](/packages/ringierimu-state-workflow)[gomachan46/state-machine

simple state machine with annotations for PHP, inspired by AASM known as a Ruby state machine.

1893.9k](/packages/gomachan46-state-machine)[tarfin-labs/event-machine

Event-driven state machines for Laravel with event sourcing, type-safe context, and full audit trail.

188.5k](/packages/tarfin-labs-event-machine)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
