PHPackages                             gomachan46/state-machine - 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. gomachan46/state-machine

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

gomachan46/state-machine
========================

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

1.1.1(10y ago)1893.9k↓29%[1 PRs](https://github.com/gomachan46/StateMachine/pulls)MITPHPPHP &gt;=5.4.0

Since Mar 21Pushed 10y agoCompare

[ Source](https://github.com/gomachan46/StateMachine)[ Packagist](https://packagist.org/packages/gomachan46/state-machine)[ RSS](/packages/gomachan46-state-machine/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (2)Dependencies (3)Versions (6)Used By (0)

StateMachine
============

[](#statemachine)

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

[![Build Status](https://camo.githubusercontent.com/f35e7835679f6ebda503b5a491343902020e4c23d27020fa1a1af63ac40915d2/68747470733a2f2f7472617669732d63692e6f72672f676f6d616368616e34362f53746174654d616368696e652e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/gomachan46/StateMachine)

Description
-----------

[](#description)

StateMachine is ... ?

- using some features of Doctrine. doctrine/annotations and doctrine/inflector only.
    - Doctrine is known as ORM, but StateMachine is not related to the database.
    - StateMachine is anything available if the PHP class.
- composed of Doctrine's custom annotations and traits.
- very easily available. Describe the annotations and `use StateMachineTrait` to what you want to manage the state, only this.
- provides `@StateMachine`, `@State`, `Event`, and `@Transition` annotations.

Demo
----

[](#demo)

As an example, you want to manage the states of Job class.

```
Job has `sleeping`, `running`, and `cleaning` states.

Transition to be forgiven,

* from `sleeping` to `running`
* from `running` to `cleaning`
* from `sleeping` or `cleaning` to `cleaning`

Job's initial state is `sleeping`.

```

This case, you can use StateMachine, only this.

```
use StateMachine\Annotations as SM;
use StateMachine\Traits\StateMachineTrait;

/**
 * Job
 *
 * @SM\StateMachine(
 *     property="status",
 *     states={
 *         @SM\State(name="sleeping"),
 *         @SM\State(name="running"),
 *         @SM\State(name="cleaning")
 *     },
 *     events={
 *         @SM\Event(
 *             name="run",
 *             transitions={
 *                 @SM\Transition(from="sleeping", to="running")
 *             }
 *         ),
 *         @SM\Event(
 *             name="clean",
 *             transitions={
 *                 @SM\Transition(from="running", to="cleaning")
 *             }
 *         ),
 *         @SM\Event(
 *             name="sleep",
 *             transitions={
 *                 @SM\Transition(from={"running", "cleaning"}, to="sleeping")
 *             }
 *         )
 *     }
 * )
 */
class Job
{
    use StateMachineTrait;

    /**
     * @var string
     */
    private $status = 'sleeping';

    /**
     * Get status
     *
     * @return string
     */
    public function getStatus()
    {
        return $this->status;
    }
}
```

So simple! So easy!

VS.
---

[](#vs)

StateMachine vs. Other state machine for PHP ...

- using annotations.
- using trait.
- no configuration files.
- no state object.
- no state machine class, only trait.
- no state machine factory.
- when state changed, is immediately reflected.

Requirement
-----------

[](#requirement)

StateMachine works with PHP 5.4.0 or later.

Installation (via composer)
---------------------------

[](#installation-via-composer)

```
{
    "require": {
        "gomachan46/state-machine": "~1.0"
    }
}

```

Usage
-----

[](#usage)

Adding a state machine is as simple as:

```
use StateMachine\Annotations as SM;
use StateMachine\Traits\StateMachineTrait;

/**
 * state machine annotations ...
 */

class ClassName
{
    use StateMachineTrait;

    private $status = 'initial status';

    ...
```

and start defining states and events together with their transitions.

### Basic Setting

[](#basic-setting)

```
## use StateMachine;
use StateMachine\Annotations as SM;
use StateMachine\Traits\StateMachineTrait;

/**
 * Job
 *
 * @SM\StateMachine(
 *     property="status", // write you want to manage states property name
 *     states={ // all states write here
 *         @SM\State(name="sleeping"), // isSleeping() is available
 *         @SM\State(name="running"), // isRunning() is available
 *         @SM\State(name="cleaning") // isCleaning() is available
 *     },
 *     events={ // all events write here
 *         @SM\Event(
 *             name="run", // run() and canRun() are available
 *             transitions={
 *                 @SM\Transition(from="sleeping", to="running")
 *             }
 *         ),
 *         @SM\Event(
 *             name="clean", clean() and canClean() are available
 *             transitions={
 *                 @SM\Transition(from="running", to="cleaning")
 *             }
 *         ),
 *         @SM\Event(
 *             name="sleep", // sleep() and canSleep() are available
 *             transitions={
 *                 @SM\Transition(from={"running", "cleaning"}, to="sleeping") // "from" can be set multiple state
 *             }
 *         )
 *     }
 * )
 */
class Job
{
    use StateMachineTrait; // Do not forget it!

    /**
     * @var string
     */
    private $status = 'sleeping'; // write initial state.

    /**
     * Get status
     *
     * @return string
     */
    public function getStatus()
    {
        return $this->status;
    }

    /**
     * StateMachine added methods setStatus() automatically.
     * Please be careful if override setStatus() method.
     * I recommend that you do not override. (if you manage the state appropriately)
     */
    // public function setStatus()
    // {
    // }
}
```

### Annotations description

[](#annotations-description)

- `@SM\StateMachine`
    - `property`target property name to manage the states (e.g. property="status")
        this name is used to like `setStatus()`
    - `states`
    - `events`
- `@SM\State`
    - name state name (e.g. name="sleeping")
- `@SM\Event`
    - name event name (e.g. name="run")
        this name is used to like `run() canRun()`
    - transitions
- `@SM\Transition`
    - from transition from ... (e.g. from="sleeping")
        you can set array or string.
    - to transition to ... (e.g. to="running")

### Provides

[](#provides)

#### Methods

[](#methods)

StateMachine provides some methods.

```
$job = new Job();
$job->isSleeping(); // true
$job->canRun(); // true
$job->run();
$job->isRunning(); // true
$job->isSleeping(); // false
$job->canRun(); // false
$job->getSleeping(); // 'sleeping'
$job->getRunning(); // 'running'
$job->getCleaning(); // 'cleaning'
$job->run(); // raises StateMachine\Exceptions\InvalidTransitionException
```

#### Whiny transition

[](#whiny-transition)

If you do not like exceptions and prefer a simple `true` or `false` as response, you can use `whinyTransitions` option.

```
/**
 * @SM\StateMachine(
 *     ...,
 *     whinyTransitions=true
 * )
 **/

job.isRunning()  # => true
job.canRun()  # => false
job.run       # => false
```

#### Direct assignment

[](#direct-assignment)

StateMachine support direct assign.

```
$job = new Job();
$job->getStatus(); // 'sleeping'
$job->setStatus('running'); // return $job
$job->getStatus(); // 'running'
$job->setStatus('sleeping'); // raises StateMachine\Exceptions\NoDirectAssignmentException
```

##### No direct assignment option

[](#no-direct-assignment-option)

If you do not want to forgive direct assign, you can use `noDirectAssignment` option.

```
/**
 * @SM\StateMachine(
 *     ...,
 *     noDirectAssignment=true
 * )
 **/
```

Only this!

```
$job = new Job();
$job->getStatus(); // 'sleeping'
$job->setStatus('running'); // raises StateMachine\Exceptions\NoDirectAssignmentException
```

#### Callbacks

[](#callbacks)

You can set callback method when ...

- before event
- before exit old state
- exit old state
- after transition
- before enter new state
- enter new state
- update state
- after exit old state
- after enter new state
- after event

```
