PHP code example of rolfvreijdenberger / izzum-statemachine
1. Go to this page and download the library: Download rolfvreijdenberger/izzum-statemachine library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
rolfvreijdenberger / izzum-statemachine example snippets
//retrieve the id somewhere from your application (form, database, domain model, user input etc)
$identifier = new Identifier('198442', 'order');//the identifier for your machine
$context = new Context($identifier);//other parameters for Context will be explained later
$machine = new StateMachine($context);//create the statemachine
$new = new State('new', State::TYPE_INITIAL);//there must be 1 initial state
$action = new State('action');//a normal state
$done = new State('done', State::TYPE_FINAL);//one of potentially many final states
$machine->addTransition(new Transition($new, $action, 'go'));//add a transition between states that is triggered by an event
$machine->addTransition(new Transition($action, $done, 'finish'));
//result: 3 states and 2 transitions defined on the statemachine
$context = $machine->getContext();
echo $context->getPersistenceAdapter();//echo works because of Memory::__toString()
# Memory
echo $context->getEntityId();//get the id for your domain model (entity)
# 198442
echo $context->getMachine();//get the name of the statemachine
# order
echo count($machine->getStates());//get the defined states directly from the machine
# 3
echo count($machine->getTransitions());//get the defined transitions directly from the machine
# 2
$state = $machine->getCurrentState();
echo $state->getName();
# new
echo $state->getType();
# initial
echo $machine->getInitialState();//echo works because of State::__toString()
# new
foreach($machine->getStates() as $state) {
echo $state->getName();
}
# new, action, done
//action, or any state ending with 'ew'
$regex = new State('regex:/action|.*ew$/', State::TYPE_REGEX);
$pause = new State('pause');
$machine->addTransition(new Transition($regex, $pause), 'pause');
//new->pause, action->pause
//the current state 'new', has a transition that can be triggered by the 'go' event
echo $machine->hasEvent('go');
# true
//current state is 'new' and 'finish' is only a valid event for the 'action' state
echo $machine->hasEvent('finish');
# false
echo $machine->canHandle('go');//this will check the guard logic for the 'go' event (explanation later)
# true
//transitions have a name derived from their 'from' and 'to' states
echo $machine->canTransition('new_to_action');
# true
//not in the 'action' state
echo $machine->canTransition('action_to_done');
# false
//check the state itself for a transition
echo $machine->getCurrentState()->hasTransition('new_to_action');
# true
foreach ($machine->getTransitions() as $transition) {
echo $transition->getName() . ":" . $transition->getEvent();
}
# new_to_action:go, action_to_done:finish, new_to_pause:pause, action_to_pause:pause
//the next three lines all produce the same result and are different ways to perform the transition to 'action' from the state 'new'
$machine->handle('go');//handle the 'go' trigger/event to transition to 'action' state
$machine->go();//use the trigger name directly as a method on the machine
$machine->transition('new_to_action');//transition by name <from>_to_<to>
//suppose we are in the 'action' state, the next lines produce the same result: a transition to 'done'
$machine->handle('finish');//transition to 'done' state via 'finish' trigger/event
$machine->finish();
$machine->transition('action_to_done');
echo $machine->run();//perform the first transition from the current state that can run
# true
//perform as many transitions as the machine allows:
//each transition will go to the 'to' state and will try the next transition from there,
//until it is in a final state or transitions are not possible for that new current state.
echo $machine->runToCompletion();//suppose we started in 'new', then 2 transitions will be made
# 2
$identifier = new Identifier('198442', 'order-machine');
$builder = new OrderBuilder();
$context = new Context($identifier, $builder);
$machine = new StateMachine($context);
//the builder class for an Order would look like this:
class OrderBuilder extends EntityBuilder{
protected function build(Identifier $identifier) {
return new Order($identifier->getEntityId());
}
}
$forbidden = new State('forbidden');
$closure = function($entity, $event){return false;};
$transition = new Transition($new, $forbidden, 'thoushaltnotpass', null, null, $closure);
// or: $transition->setGuardCallable($closure);
$machine->addTransition($transition);
echo $machine->hasEvent('thoushaltnotpass');
# true
echo $machine->handle('thoushaltnotpass');//transition will not be made
# false
echo $machine->transition('new_to_forbidden');
# false
echo $machine->getCurrentState();//still in the same state
# new
$forbidden = new State('forbidden');
$rule = '\izzum\rules\FalseRule';
$transition = new Transition($new, $forbidden, 'thoushaltnotpass', $rule);
// or: $transition->setRuleName($rule);
$machine->addTransition($transition);
echo $machine->hasEvent('thoushaltnotpass');
# true
echo $machine->handle('thoushaltnotpass');//transition will not be made
# false
echo $machine->transition('new_to_forbidden');
#> false
echo $machine->getCurrentState();//still in the same state
# new
class IsAllowedToShip extends Rule {
public function __construct(Order $order) { $this->order = $order;}
protected function _applies() { return $this->order->isPaid(); }
}
$rule = '\izzum\rules\IsAllowedToShip';
$transition = new Transition($action, new State('shipping'), 'ship', $rule);
class MyEventHandlingClass {
public function onCheckCanTransition($identifier, $transition, $event) {
echo "checking transition (" . $identifier->getEntityId() . ") " . $transition->getName() ' for event: ' . $event;
//normally, you would put your guard logic here...
return true;
}
}
$builder = new ModelBuilder(new MyEventHandlingClass());
$context = new Context($identifier, $builder);
$statemachine = new StateMachine($context);
//load the machine here and assume we are in the 'new' state in which a transition can be triggered by the 'go' event
$statemachine->handle('go');
# checking transition (198442) new_to_action for event: go
Class OrderDelivery extends Command {
public function __construct(Order $order) { $this->order = $order;}
protected function _execute() { $this->order->deliver(); }
}
$command = '\izzum\command\OrderDelivery';
//assume we are using the rule from the example
$transition = new Transition($action, new State('shipping'), 'ship', $rule, $command);
$adapter = new Session();
$machine = new StateMachine(new Context(new Identifier('session', 'rainbow-machine'), null, $adapter));
$machine->run();
$identifier('UUID-1234-ACD3-2156', 'data-migration-machine');
$adapter = new PDO('pgsql:host=localhost;port=5432;dbname=izzum');
//or for mysql
$adapter = new PDO('mysql:host=localhost;dbname=izzum');
//or for sqlite
$adapter = new PDO('"sqlite:izzum.db"');
$context = new Context($identifier, $builder, $adapter);
$statemachine = new StateMachine($context);
$adapter->load($statemachine);//the adapter can also act as a loader
$statemachine->add('creation of machine...');
$identifier('UUID-1234-ACD3-2156', 'data-migration-machine');
$adapter = new Redis('127.0.0.1', 6379);
//or use mongodb
$adapter = new MongoDB('mongodb://localhost:27017');
$context = new Context($identifier, $builder, $adapter);
$statemachine = new StateMachine($context);
$adapter->load($statemachine);//the adapter can also act as a loader
$statemachine->add('creation of machine...');
$statemachine = new StateMachine(new Context(new Identifier('spiderman' , 'superhero-machine')));
$adapter = new PDO('pgsql:host=208.64.123.130;port=5432;dbname=izzum');
$adapter->load($statemachine);
$statemachine->run();
$redis = new Redis('127.0.0.1', 6379);
$machine = new StateMachine(new Context(new Identifier(1988442, 'crazy-machine'), null, $redis));
//set the configuration. Normally, this would be done directly on redis in a
//seperate process before using the statemachine (eg: during deployment)
$configuration = file_get_contents(__DIR__ .'/redis-configuration-example.json');
$redis->set(Redis::KEY_CONFIGURATION, $configuration);
//load the machine
$redis->load($machine);
$loader = XML::createFromFile(__DIR__ . '/configuration.xml');
$writer = new PDO('pgsql:host=208.64.123.130;port=5432;dbname=izzum');//postgres backend
$identifier = new Identifier('198442', 'awesome-machine');
$delegator = new ReaderWriterDelegator($loader, $writer);
$context = new Context($identifier, null, $delegator);
$machine = new StateMachine($context);
$delegator->load($machine);//loads from xml file
$machine->run();//stores data in postgres
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.