addTransition() public method

It is possible to add transition that have 'regex' states: states that have a name in the format of 'regex://' or 'not-regex://'. When adding a transition with a regex state, it will be matched against all currently known states if there is a match. If you just want to use regex transitions, it might be preferable to store some states via 'addState' first, so the Self transitions for regex states are disallowed by default since you would probably only want to do that explicitly. Regex states can be both the 'to' and the 'from' state of a transition. Transitions from a 'final' type of state are not allowed. the order in which transitions are added matters insofar that when a StateMachine::run() is called, the first Transition for the current State will be tried first. Since a transition has complete knowledge about it's states, the addition of a transition will also trigger the adding of the to and from state on this class. this method can also be used to add a Transition directly (instead of via a loader). Make sure that transitions that share a common State use the same instance of that State object and vice versa.
public addTransition ( Transition $transition, boolean $allow_self_transition_by_regex = false ) : integer
$transition Transition
$allow_self_transition_by_regex boolean optional: to allow regexes to set a self transition.
return integer a count of how many transitions were added. In case of a regex transition this might be multiple and in case a transition already exists it might be 0.
 /**
  * @test
  */
 public function shouldBeAbleToStoreAndRetrieveData()
 {
     $redis = new Redis();
     $redis->setDatabase(15);
     //clear the redis database for testing
     $redis->flushdb();
     $machine = new StateMachine(new Context(new Identifier('1', 'test-machine'), null, $redis));
     //create the loader
     //get the configuration from the json file
     $configuration = file_get_contents(__DIR__ . '/../loader/fixture-example.json');
     //set it. normally, this would be done by a seperate process that has already loaded the configuration
     $redis->set(Redis::KEY_CONFIGURATION, $configuration);
     //load the machine
     $count = $redis->load($machine);
     //add the machine to the backend system
     $this->assertTrue($machine->add('this is the first addition'));
     $this->assertFalse($machine->add(), 'returns false, already added');
     $this->assertTrue($machine->run('this is a test run message'), 'succesful transitions so it returns true');
     $this->assertEquals('b', $machine->getCurrentState());
     $this->assertContains('1', $redis->getEntityIds('test-machine'));
     $this->assertTrue($machine->hasEvent('goToC'));
     try {
         $machine->goToC();
         $this->fail('should not come here');
     } catch (Exception $e) {
         $this->assertEquals(Exception::RULE_APPLY_FAILURE, $e->getCode());
     }
     $this->assertEquals('b', $machine->getCurrentState());
     //create new instance of same machine
     $machine2 = new StateMachine(new Context(new Identifier('1', 'test-machine'), null, $redis));
     $this->assertNotSame($machine2, $machine);
     $redis->load($machine2);
     $this->assertEquals('b', $machine2->getCurrentState(), 'should retrieve the same value');
     //create new instance of other machine
     $machine3 = new StateMachine(new Context(new Identifier('2', 'test-machine'), null, $redis));
     $this->assertNotSame($machine2, $machine3);
     $redis->load($machine3);
     $this->assertTrue($machine3->add());
     $this->assertNotEquals('b', $machine3->getCurrentState()->getName(), 'should not retrieve the same value as the other machine');
     $this->assertEquals('a', $machine3->getCurrentState()->getName(), 'initial state');
     //echo $machine3->toString(true);
     $this->assertEquals(2, $machine3->runToCompletion("go to the final state"));
     $this->assertEquals('done', $machine3->getCurrentState()->getName(), 'final state');
     $machine4 = new StateMachine(new Context(new Identifier('3', 'another-machine'), null, $redis));
     $a = new State('begin', State::TYPE_INITIAL);
     $b = new State('enter', State::TYPE_NORMAL);
     $c = new State('leave', State::TYPE_FINAL);
     $machine4->addTransition(new Transition($a, $b));
     $machine4->addTransition(new Transition($b, $c));
     $machine4->add('creating another machine to see that all goes well storing the data for multiple machines in redis');
     $this->assertEquals(2, $machine4->runToCompletion('running the machine to completion'));
     $ids = $redis->getEntityIds('test-machine');
     $this->assertEquals(array('1', '2'), $ids);
     $ids = $redis->getEntityIds('another-machine');
     $this->assertEquals(array('3'), $ids);
     $ids = $redis->getEntityIds('test-machine', 'done');
     $this->assertEquals(array('2'), $ids, 'only 2 was run to completion and in state done');
     $ids = $redis->getEntityIds('another-machine', 'leave');
     $this->assertEquals(array('3'), $ids, 'only 3 was run to completion and in state leave');
     //$redis->hmset("key" , array("name1" => "value1", "name2" => "value2"));
 }
 */
//create machine. context defaults to in-memory state handling
$context = new Context(new Identifier("interactive-example", "interactive-machine"));
$machine = new StateMachine($context);
//define the states and the state types
$new = new State('new', State::TYPE_INITIAL);
$eating = new State('eating');
$drinking = new State('drinking');
$sleep = new State('sleep');
$hungry = new State('hungry');
$drunk = new State('drunk');
$smoking = new State('smoking');
$high = new State('high');
$dead = new State('dead', State::TYPE_FINAL);
//add transitions to the machine, with event names
$machine->addTransition(new Transition($new, $hungry, 'wakeup'));
$machine->addTransition(new Transition($hungry, $sleep, 'sleep'));
$machine->addTransition(new Transition($hungry, $eating, 'eat'));
$machine->addTransition(new Transition($hungry, $drinking, 'drink'));
$machine->addTransition(new Transition($hungry, $drunk, 'drinkalot'));
$machine->addTransition(new Transition($hungry, $smoking, 'izzumJo'));
//http://www.urbandictionary.com/define.php?term=Izzum
$machine->addTransition(new Transition($eating, $eating, 'eatmore'));
$machine->addTransition(new Transition($eating, $drinking, 'party'));
$machine->addTransition(new Transition($drinking, $drunk, 'morebooze'));
$machine->addTransition(new Transition($drinking, $sleep, 'sleep'));
$machine->addTransition(new Transition($drunk, $sleep, 'crash'));
$machine->addTransition(new Transition($drunk, $high, 'weedz'));
$machine->addTransition(new Transition($sleep, $hungry, 'wakeup'));
$machine->addTransition(new Transition($drunk, $dead, 'moreboozzz'));
$machine->addTransition(new Transition($smoking, $hungry, 'munchies'));
 */
require_once '../autoload.php';
//all states, the color of the rainbow
$new = new State('white', State::TYPE_INITIAL);
$red = new State('red');
$orange = new State('orange');
$yellow = new State('yellow');
$green = new State('green');
$blue = new State('blue');
$indigo = new State('indigo');
$violet = new State('violet');
// create the machine with the correct session adapter to store the state accross page refreshes
$adapter = new Session();
$machine = new StateMachine(new Context(new Identifier('session-example', 'rainbow-machine'), null, $adapter));
//add the transitions, going from one color to the next and back to the first
$machine->addTransition(new Transition($new, $red));
$machine->addTransition(new Transition($red, $orange));
$machine->addTransition(new Transition($orange, $yellow));
$machine->addTransition(new Transition($yellow, $green));
$machine->addTransition(new Transition($green, $blue));
$machine->addTransition(new Transition($blue, $indigo));
$machine->addTransition(new Transition($indigo, $violet));
$machine->addTransition(new Transition($violet, $red));
//initialize the first time to 'red' and then cycle through the
//colors for each page refresh
$machine->run();
//get some data to put in the output
$current = $machine->getCurrentState();
$next_transitions = implode(',', $current->getTransitions());
$next = $current->getTransitions()[0]->getStateTo();
//generate the ouput
 *
 * run this script from the (bash) command line:
 * php -f index.php
 * and stop it with ctrl+c
 */
//create machine. context defaults to in-memory state handling
$context = new Context(new Identifier("webshopcheckout-example", "webshopcheckout-machine"));
$machine = new StateMachine($context);
//define the states and the state types
$basket = new State('basket', State::TYPE_INITIAL);
$customerdata = new State('customerdata');
$shipping = new State('shipping');
$payment = new State('payment');
$complete = new State('complete', State::TYPE_FINAL);
//add transitions to the machine, with event names
$machine->addTransition(new Transition($basket, $customerdata, 'Checkout'));
$machine->addTransition(new Transition($customerdata, $shipping, 'ChooseHowToShip'));
$machine->addTransition(new Transition($shipping, $payment, 'ChooseHowToPay'));
$machine->addTransition(new Transition($payment, $complete, 'ready'));
//start the interactive demo
//with some coloring that works in the bash shell
echo PHP_EOL . "Izzum statemachine webshopcheckout demo. press ctrl+c to stop it." . PHP_EOL . PHP_EOL;
//loop the machine
while (true) {
    $state = $machine->getCurrentState();
    echo "current state: {$state}" . PHP_EOL;
    echo "possible transitions from {$state}: " . PHP_EOL;
    if ($state->isFinal()) {
        //Sold! Thanks and hope to see you again soon.
        echo "Sold! Thanks and hope to see you again soon. ;)" . PHP_EOL . PHP_EOL;
        exit;
 /**
  * {@inheritDoc}
  */
 public function load(StateMachine $stateMachine)
 {
     $count = 0;
     $unsorted = $this->getTransitions();
     $has_regex = array();
     $has_no_regex = array();
     foreach ($unsorted as $transition) {
         $to = $transition->getStateTo();
         $from = $transition->getStateFrom();
         //sort on regexes. they should come last in an automated loader like this
         if ($from->isRegex() || $to->isRegex()) {
             $has_regex[] = $transition;
         } else {
             $has_no_regex[] = $transition;
         }
     }
     $sorted = array_merge($has_no_regex, $has_regex);
     // add the sorted transitions. the transitions added will set the
     // states (from/to) on the statemachine
     foreach ($sorted as $transition) {
         // when using transitions with 'regex' states, the statemachine will handle this for you.
         $count += $stateMachine->addTransition($transition);
     }
     return $count;
 }
 public function testFull()
 {
     $entity_id = "id";
     $machine = "test machine";
     $identifier = new Identifier($entity_id, $machine);
     $builder = new EntityBuilder();
     $io = new Memory();
     // all parameters
     $o = new Context($identifier, $builder, $io);
     $this->assertEquals($entity_id, $o->getEntityId());
     $this->assertEquals($machine, $o->getMachine());
     $this->assertNull($o->getStateMachine());
     $this->assertTrue(is_a($o->getPersistenceAdapter(), 'izzum\\statemachine\\persistence\\Memory'));
     $this->assertTrue(is_a($o->getBuilder(), 'izzum\\statemachine\\EntityBuilder'));
     $this->assertEquals($o->getIdentifier(), $o->getEntity());
     $this->assertTrue(is_string($o->getEntityId()));
     $this->assertTrue(is_string($o->toString()));
     $this->assertContains($entity_id, $o->toString());
     $this->assertContains($machine, $o->toString());
     $this->assertContains('izzum\\statemachine\\Context', $o->toString());
     // even though we have a valid reader, the state machine does not exist.
     $this->assertEquals(State::STATE_UNKNOWN, $o->getState());
     $this->assertTrue($o->setState('lala'));
     $this->assertEquals('lala', $o->getState());
     // for coverage.
     $this->assertNotNull($o->getId());
     $this->assertNotNull($o->getId(true));
     $this->assertNotNull($o->getId(false));
     $this->assertNotNull($o->getId(true, true));
     $this->assertNotNull($o->getId(false, true));
     // adding
     $machine = 'add-experiment-machine';
     $context = new Context(new Identifier('add-experiment-id', $machine), $builder, $io);
     $sm = new StateMachine($context);
     $sm->addTransition(new Transition(new State('c', State::TYPE_FINAL), new State('d'), State::TYPE_NORMAL));
     $sm->addTransition(new Transition(new State('a', State::TYPE_INITIAL), new State('b')));
     $this->assertCount(0, $context->getPersistenceAdapter()->getEntityIds($machine));
     $state = $sm->getInitialState()->getName();
     $this->assertEquals('a', $state);
     $this->assertTrue($context->add($state));
     // var_dump( Memory::get());
     $this->assertCount(1, $context->getPersistenceAdapter()->getEntityIds($machine));
 }