- 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.
Simple State Machine is installable via Composer as cosma/simple-state-machine.
{
"require": {
"cosma/simple-state-machine": "1.0.*"
}
}
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;
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
*/
...
}
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');
...
}
}
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);
}
...
}
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;
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
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:
-
Drawing graphs with DOT - download a pdf
-
Node Shapes - shapes of a node
vendor/phpunit/phpunit/phpunit --coverage-text --coverage-html=tests/coverage tests
Released under the MIT License, see LICENSE.