cosma/simple-state-machine

v1.0.3 2015-01-12 18:09 UTC

This package is not auto-updated.

Last update: 2022-01-22 01:22:22 UTC


README

Circle CI SensioLabsInsight

  • A Simple State Machine without timeouts.
  • States can modify a Data object which will be injected in the initial State.
  • The State Machine graph can be visualised in a UML diagram generated in different formats.

Table of Contents

Installation

Simple State Machine is installable via Composer as cosma/simple-state-machine.

{
    "require": {
        "cosma/simple-state-machine": "1.0.*"
    }
}

Usage

Let's follow the example of a simple price calculator state machine.

namespace \MyProject;

/**
*   Simple State Machine
*/
$priceStateMachine = \Cosma\SimpleStateMachine\StateMachine('Price Calculator State Machine');


/**
*   Your Data object which can be modify by the State Machines
*   Has to implement the interface \Cosma\SimpleStateMachine\InterfaceData
*/
$price = new \YourProject\Price();

/**
*   Start State of the State Machine
*   Has to extends the abstract \Cosma\SimpleStateMachine\AbstractState
*/
$initialPriceState = \YourProject\PriceStateMachine\States\InitialPrice($price);

/**
*   Simple State Machine cannot run without setting the start State
*/
$priceStateMachine->setState($initialPriceState);

/**
*   Running the State Machine
*   During this process the Data object will be modified depending on teh configuration of the Machine
*/
$priceStateMachine->run();

/**
*   Retrieve the Data object at the end of the process
*/
$finalPrice = $priceStateMachine->getState()->getData();


/**
*   Generate the Diagram of the State Machine.
*   Choose the format
*/
$graphic = new Graphic('svg');
$diagramSVG = $priceStateMachine->draw($graphic);
echo $diagramSVG;

Reference

Defining Data Object

The Data object can be modify by the State Machines transitions and State.

The Data class must implement the interface \Cosma\SimpleStateMachine\InterfaceData.

InterfaceData is a empty interface but is used to force Type hinting.

namespace \MyProject\PriceStateMachine;

class Price implements \Cosma\SimpleStateMachine\InterfaceData
{
    /**
    *   @var float
    */
    private $value;

    public function __constructor()
    {
        $this->value = $this->getPriceFromDB();
    }

    /**
    *    getters, setters and other functions
    */
    ...
}

Defining States

All states must extend the class \Cosma\SimpleStateMachine\AbstractState

namespace \MyProject\PriceStateMachine\States;

class AddVATState extends \Cosma\SimpleStateMachine\AbstractState
{
    /**
    *   Set the label for this State used in State Machine diagram
    */
    public function getLabel()
    {
        return 'Add VAT Tax';
    }

    /**
    *   Modify the Data object
    */
    protected function process()
    {
        $price = $this->getData();
        $price->setValue($price->getValue() * 1.19);
        ...
    }

    /**
    *   Configure the Transitions from this State to another States or itself in case of a loop
    *   You may set in what Condition that Transition takes place
    *   The order to check upon the validity of conditions and forward to next State is from up to down
    */
    protected function configureAvailableTransitions()
    {
        $this->addTransition(
                            '\YourProject\PriceStateMachine\States\AddDiscount',
                            '\YourProject\PriceStateMachine\Conditions\IfGreaterThan1000'
        );

        $this->addTransition('NewStateClass', 'ConditionClass');

        $this->addTransition('\YourProject\PriceStateMachine\States\AddDiscount');
        ...
    }
}

Defining Conditions

A Transition between states is possible directly when there is no condition or, if there is a condition, only when that condition is true.

All Conditions must extend \Cosma\SimpleStateMachine\AbstractCondition class

namespace namespace \MyProject\PriceStateMachine\Conditions;

class SomeWildCondition extends \Cosma\SimpleStateMachine\AbstractCondition
{
    /**
    *   @return string
    */
    public function getLabel()
    {
        return "Some Wild Condition";
    }

    /**
    *   @return bool
    */
    public function isTrue()
    {
        $data = $this->getData();
        return $this->checkSomething($data);
    }
    ...
}

Graph Diagram

You can easily visualise the State Machine Diagram

namespace \MyProject;

/**
*   Generate the Diagram of the State Machine.
*   Choose the format
*/
$graphic = new Graphic('svg');
$diagramSVG = $priceStateMachine->draw($graphic);

echo $diagramSVG;

Export Formats

The output is delivered in various formats.

The most used export formats are:

All supported formats are the DOT output formats: bmp, canon, cgimage, cmap, cmapx, cmapx_np, dot, eps, exr, fig, gif, gv, icns, ico, imap, imap_np, ismap, jp2, jpe, jpeg, jpg, pct, pdf, pic, pict, plain, plain-ext, png, pov, ps, ps2, psd, sgi, svg, svgz, tga, tif, tiff, tk, vml, vmlz, x11, xdot, xdot1.2, xdot1.4, xlib

DOT Language

Stands for graph description language and you can read more here

To take fully advantage of style attributes you need to know DOT language.

When defining a Condition or a State, you can easily modify the protected $styleAttributes property and overwrite the default style for a State or a Condition.

By this you can manipulate the color, font and shape of States and Conditions

namespace \MyProject\PriceStateMachine\States;

class MyState extends \Cosma\SimpleStateMachine\AbstractState
{
    ...
    /**
    *   An array of DOT attributes to overwrite the default style of a State/Condition
    */
    protected $styleAttributes = array(
        'fillcolor' => '#A8CE9F',
        'style' => 'filled',
        'fontcolor' => '#000000',
        'fontsize' => 12,
        'penwidth' => 1,
    );
    ...
}

DOT Useful Links:

  1. Drawing graphs with DOT - download a pdf

  2. Node Shapes - shapes of a node

Tests

vendor/phpunit/phpunit/phpunit --coverage-text  --coverage-html=tests/coverage tests

License

Released under the MIT License, see LICENSE.