Giter Site home page Giter Site logo

light-fsm's Introduction

Light FSM

License Build Status Coverage Status HHVM Status Scrutinizer Code Quality SensioLabsInsight

Finite-state machine FSM PHP library. Create state machines and lightweight state machine-based workflows directly in PHP code.

$phoneCall = new StateMachine(State::OFF_HOOK);

$phoneCall->configure(State::OFF_HOOK)
    ->permit(Event::CALL_DIALED, State::RINGING);

$phoneCall->configure(State::RINGING)
    ->permit(Event::HUNG_UP, State::OFF_HOOK)
    ->permit(Event::CALL_CONNECTED, State::CONNECTED);

$phoneCall->configure(State::CONNECTED)
    ->onEntry([$this, 'startTimer'])
    ->onExit([$this, 'stopTimer'])
    ->permit(Event::HUNG_UP, State::OFF_HOOK)
    ->permit(Event::PLACE_ON_HOLD, State::ON_HOLD);

$phoneCall->fire(Event::CALL_DIALED);
$this->assertEquals(State::RINGING, $phoneCall->getCurrentState());

This project, as well as the example above, was inspired by stateless.

Features

  • State and trigger events of type string or int
  • Firing trigger events with additional data
  • Hierarchical states
  • Entry/exit events for states
  • Introspection
  • Guard callbacks to support conditional transitions
  • Ability to store state externally (for example, in a property tracked by an ORM)
  • Export to DOT graph

Firing trigger events with additional data

Event can be fired with additional data StateMachine::fire($event, $data) that will be passed and available to entry/exit and guard listeners, so they can base their logic based on it.

Hierarchical States

In the example below, the ON_HOLD state is a substate of the CONNECTED state. This means that an ON_HOLD call is still connected.

$phoneCall->configure(State::ON_HOLD)
    ->subStateOf(State::CONNECTED)
    ->permit(Event::CALL_CONNECTED, State::CONNECTED);

In addition to the StateMachine::getCurrentState() method, which will report the precise current state, an isInState($state) method is also provided. isInState($state) will take substates into account, so that if the example above was in the ON_HOLD state, isInState(State::CONNECTED) would also evaluate to true.

Entry/Exit Events

In the example, the startTimer() method will be executed when a call is connected. The stopTimer() will be executed when call completes.

When call moves between the CONNECTED and ON_HOLD states, since the ON_HOLD state is a substate of the CONNECTED state, these listeners can distinguish substates and note that call is still connected based on the first $isSubState argument.

External State Storage

In order to listen for state changes for persistence purposes, for example with some ORM tool, pass the listener callback to the StateMachine constructor.

$stateObject = $orm-find();

$stateMachine = new StateMachine(
    function () use ($stateObject) {
        return $stateObject->getValue();
    },
    function ($state) use ($stateObject) {
        $stateObject->setValue($state);
        $orm->persist($stateObject);
    }
);

In this case, when StateMachine is constructed with two callbacks, the state is held totaly external, and each time StateMachine needs current state, the first callback will be called, and each time the state changes, the second callback will be called.

Introspection

The state machine can provide a list of the trigger events than can be successfully fired within the current state by the StateMachine::getPermittedTriggers() method.

Guard Clauses

The state machine will choose between multiple transitions based on guard clauses, e.g.:

$phoneCall->configure(State::OFF_HOOK)
    .permit(Trigger::CALL_DIALLED, State::RINGING, function ($data) { return IsValidNumber($data); })
    .permit(Trigger::CALL_DIALLED, State::BEEPING, function ($data) { return !IsValidNumber($data); });

Export to DOT graph

It can be useful to visualize state machines on runtime. With this approach the code is the authoritative source and state diagrams are by-products which are always up to date.

$phoneCall->configure(State::OFF_HOOK)
    .permit(Trigger::CALL_DIALED, State::RINGING, 'IsValidNumber');
$graph = phoneCall->toDotGraph();

The StateMachine::toDotGraph() method returns a string representation of the state machine in the DOT graph language, e.g.:

digraph {
 "off-hook" -> "ringing" [label="call-dialed [IsValidNumber]"];
}

This can then be rendered by tools that support the DOT graph language, such as the dot command line tool from graphviz.org or viz.js. See (http://www.webgraphviz.com) for instant gratification. Command line example to generate a PDF file:

> dot -T pdf -o phoneCall.pdf phoneCall.dot

light-fsm's People

Contributors

tmilos avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.