2017 © Pedro Peláez
 

library state-machine

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

image

gomachan46/state-machine

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

  • Monday, June 15, 2015
  • by gomachan46
  • Repository
  • 1 Watchers
  • 19 Stars
  • 11,509 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 1 Open issues
  • 6 Versions
  • 7 % Grown

The README.md

StateMachine

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

Build Status, (*2)

Description

StateMachine is ... ?, (*3)

  • 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

As an example, you want to manage the states of Job class., (*4)

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., (*5)

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!, (*6)

VS.

StateMachine vs. Other state machine for PHP ..., (*7)

  • 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

StateMachine works with PHP 5.4.0 or later., (*8)

Installation (via composer)

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

Usage

Adding a state machine is as simple as:, (*9)

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., (*10)

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

  • @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

Methods

StateMachine provides some methods., (*11)

$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

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

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

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

Direct assignment

StateMachine support direct assign., (*13)

$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

If you do not want to forgive direct assign, you can use noDirectAssignment option., (*14)

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

Only this!, (*15)

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

Callbacks

You can set callback method when ..., (*16)

  • 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

```php <?php, (*17)

namespace StateMachine\Tests\Entity;, (*18)

use StateMachine\Annotations as SM; use StateMachine\Traits\StateMachineTrait;, (*19)

/** * CallbackJob * * @SM\StateMachine( * property="status", * states={ * @SM\State( * name="sleeping", * beforeExit="beforeExitSleeping", * exit="exitSleeping", * afterExit="afterExitSleeping" * ), * @SM\State( * name="running", * beforeEnter="beforeEnterRunning", * enter="enterRunning", * afterEnter="afterEnterRunning" * ), * @SM\State(name="cleaning") * }, * events={ * @SM\Event( * name="run", * transitions={ * @SM\Transition( * from="sleeping", * to="running", * after="afterTransition" * ) * }, * before="beforeRunEvent", * after="afterRunEvent" * ), * @SM\Event( * name="clean", * transitions={ * @SM\Transition(from="running", to="cleaning") * } * ), * @SM\Event( * name="sleep", * transitions={ * @SM\Transition(from={"running", "cleaning"}, to="sleeping") * } * ) * } * ) */ class CallbackJob { use StateMachineTrait;, (*20)

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

/**
 *
 */
private function beforeEnterRunning()
{
    ...
}

/**
 *
 */
private function enterRunning()
{
    ...
}

/**
 *
 */
private function afterEnterRunning()
{
    ...
}

/**
 *
 */
private function beforeExitSleeping()
{
    ...
}

/**
 *
 */
private function exitSleeping()
{
    ...
}

/**
 *
 */
private function afterExitSleeping()
{
    ...
}

/**
 *
 */
private function beforeRunEvent()
{
    ...
}

/**
 *
 */
private function afterRunEvent()
{
    ...
}

/**
 *
 */
private function afterTransition()
{
    ...
}

} ```, (*21)

In this case,, (*22)

```php $job = new CallbackJob(); $job->run();, (*23)

/** * run methods in this order. * * beforeRunEvent() * beforeExitSleeping() * exitSleeping() * afterTransition() * beforeEnterRunning() * enterRunning() * setStatus('running') * afterExitSleeping() * afterEnterRunning() * afterRunEvent() */ ```, (*24)

You can run methods with args, too., (*25)

For example,, (*26)

php public function beforeRunEvent() { $args = func_get_args(); echo join(', ', $args); }, (*27)

php $job->run('foo', 'bar'); // echo 'foo, bar';, (*28)

In future

In future, I am going to implement like AASM provides services:, (*29)

  • Guards
  • Inspection
  • and more ...

Questions

  • create an issue on GitHub
  • send us a tweet @gomachan46
  • send mail shiro.gomachan46@gmail.com

Feel free!, (*30)

Contribution

  1. Please fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request :)

I'm looking forward to your contributions!, (*31)

Licence

MIT, (*32)

Author

gomachan46, (*33)

Acknowledgement

aasm, (*34)

Thank you for the great product., (*35)

The Versions

15/06 2015

dev-master

9999999-dev

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

  Sources   Download

MIT

The Requires

 

The Development Requires

by Go Nakanishi

trait bundle symfony doctrine2 event statemachine status annotation workflow finite state transition sm aasm

15/06 2015

1.1.1

1.1.1.0

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

  Sources   Download

MIT

The Requires

 

The Development Requires

by Go Nakanishi

trait bundle symfony doctrine2 event statemachine status annotation workflow finite state transition sm aasm

15/06 2015

1.1.1.x-dev

1.1.1.9999999-dev

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

  Sources   Download

MIT

The Requires

 

The Development Requires

by Go Nakanishi

trait bundle symfony doctrine2 event statemachine status annotation workflow finite state transition sm aasm

07/06 2015

1.2.0.x-dev

1.2.0.9999999-dev

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

  Sources   Download

MIT

The Requires

 

The Development Requires

by Go Nakanishi

trait bundle symfony doctrine2 event statemachine status annotation workflow finite state transition sm aasm

07/06 2015

1.1.0

1.1.0.0

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

  Sources   Download

MIT

The Requires

 

The Development Requires

by Go Nakanishi

trait bundle symfony doctrine2 event statemachine status annotation workflow finite state transition sm aasm

21/03 2015

1.0.0

1.0.0.0

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

  Sources   Download

MIT

The Requires

 

The Development Requires

by Go Nakanishi

trait bundle symfony doctrine2 event statemachine status annotation workflow finite state transition sm aasm