getTransitions() public method

All known/loaded transitions for this statemachine
public getTransitions ( ) : Transition[]
return Transition[]
 /**
  * @test
  */
 public function shouldLoadTransitionsFromFile()
 {
     $machine = new StateMachine(new Context(new Identifier('xml-test', 'test-machine')));
     $this->assertCount(0, $machine->getTransitions());
     //this is a symbolic link to the asset/xml/example.xml file
     $loader = XML::createFromFile(__DIR__ . '/fixture-example.xml');
     $count = $loader->load($machine);
     $this->assertCount(4, $machine->getTransitions(), 'there is a regex transition that adds 2 transitions (a-c and b-c)');
     $this->assertEquals(4, $count);
     $this->assertEquals(0, MyStatic::$guard);
     $this->assertTrue($machine->ab());
     $this->assertEquals(1, MyStatic::$guard, 'guard callable specified in xml should be called');
     $this->assertTrue($machine->bdone());
     $this->assertEquals(2, MyStatic::$entry, '2 entry state callables in config');
     $this->assertEquals(1, MyStatic::$exit, '1 exit state callable in config');
 }
 /**
  * Checks a fully loaded statemachine for a valid configuration.
  *
  * This is useful in a debug situation so you can check for the validity of
  * rules, commands and callables in guard logic, transition logic and state entry/exit logic
  * before they hit a
  *
  * This does not instantiate any objects. It just checks if callables can be found
  * and if classes for rules and commands can be found
  *
  * @param StateMachine $machine
  * @return Exception[] an array of exceptions if anything is wrong with the configuration
  */
 public static function checkConfiguration(StateMachine $machine)
 {
     //TODO: also check the rules and commands
     $exceptions = array();
     $output = array();
     //check state callables
     foreach ($machine->getStates() as $state) {
         $exceptions[] = self::getExceptionForCheckingCallable($state->getExitCallable(), State::CALLABLE_ENTRY, $state);
         $exceptions[] = self::getExceptionForCheckingCallable($state->getEntryCallable(), State::CALLABLE_ENTRY, $state);
     }
     //check transition callables
     foreach ($machine->getTransitions() as $transition) {
         $exceptions[] = self::getExceptionForCheckingCallable($transition->getGuardCallable(), Transition::CALLABLE_GUARD, $transition);
         $exceptions[] = self::getExceptionForCheckingCallable($transition->getTransitionCallable(), Transition::CALLABLE_TRANSITION, $transition);
     }
     //get the exceptions
     foreach ($exceptions as $e) {
         if (is_a($e, '\\Exception')) {
             $output[] = $e;
         }
     }
     return $output;
 }
 /**
  * @test
  */
 public function shouldLoadAndWriteViaDelegator()
 {
     $loader = XML::createFromFile(__DIR__ . '/../loader/fixture-example.xml');
     $writer = new Memory();
     $identifier = new Identifier('readerwriter-test', 'test-machine');
     $delegator = new ReaderWriterDelegator($loader, $writer);
     $context = new Context($identifier, null, $delegator);
     $machine = new StateMachine($context);
     $this->assertCount(0, $machine->getTransitions());
     $count = $delegator->load($machine);
     //add to the backend
     $this->assertTrue($context->add('a'));
     $this->assertCount(4, $machine->getTransitions(), 'there is a regex transition that adds 2 transitions (a-c and b-c)');
     $this->assertEquals(4, $count);
     $this->assertTrue($machine->ab());
     //get the data from the memory storage facility
     $data = $writer->getStorageFromRegistry($machine->getContext()->getIdentifier());
     $this->assertEquals('b', $data->state);
     $this->assertEquals('b', $machine->getCurrentState()->getName());
     $this->assertTrue($machine->bdone());
     $data = $writer->getStorageFromRegistry($machine->getContext()->getIdentifier());
     $this->assertEquals('done', $data->state);
 }
Example #4
0
 /**
  * @test
  */
 public function shouldLoadTransitionsFromJSONString()
 {
     $machine = new StateMachine(new Context(new Identifier('json-test', 'json-machine')));
     $this->assertCount(0, $machine->getTransitions());
     $json = $this->getJSON();
     $loader = new JSON($json);
     $this->assertEquals($this->getJSON(), $loader->getJSON());
     $count = $loader->load($machine);
     $this->assertCount(2, $machine->getTransitions());
     $this->assertEquals(2, $count);
     $tbd = $machine->getTransition('b_to_done');
     $b = $tbd->getStateFrom();
     $d = $tbd->getStateTo();
     $tab = $machine->getTransition('a_to_b');
     $a = $tab->getStateFrom();
     $this->assertEquals($b, $tab->getStateTo());
     $this->assertSame($b, $tab->getStateTo());
     $this->assertTrue($a->isInitial());
     $this->assertTrue($b->isNormal());
     $this->assertTrue($d->isFinal());
 }
 /**
  * @test
  */
 public function shouldAddRegexesLoaderOnlyWhenStatesAreSet()
 {
     $context = new Context(new Identifier(Identifier::NULL_ENTITY_ID, Identifier::NULL_STATEMACHINE));
     $machine = new StateMachine($context);
     $transitions = array();
     $s1 = new State("1");
     $s2 = new State("2");
     $s3 = new State("3");
     //many to many
     $transitions[] = new Transition(new State('regex:/.*/'), new State('regex:/.*/'));
     $loader = new LoaderArray($transitions);
     $this->assertEquals(count($transitions), $loader->count());
     $this->assertEquals(1, $loader->count());
     $this->assertEquals(0, count($machine->getStates()));
     $this->assertEquals(0, count($machine->getTransitions()));
     $count = $loader->load($machine);
     $this->assertEquals(0, $count, 'nothing because there are no known states');
     $this->assertTrue($machine->addState($s1));
     $this->assertTrue($machine->addState($s2));
     $this->assertTrue($machine->addState($s3));
     $this->assertEquals(3, count($machine->getStates()));
     $this->assertFalse($machine->addState($s1));
     $this->assertFalse($machine->addState($s2));
     $this->assertFalse($machine->addState($s3));
     $this->assertEquals(3, count($machine->getStates()));
     $count = $loader->load($machine);
     $this->assertEquals(6, count($machine->getTransitions()));
     $this->assertEquals(6, $count, 'regexes have matched all states and created a mesh');
     $count = $loader->load($machine);
     $this->assertEquals(0, $count, 'transitions are not added since they have already been added');
     $this->assertEquals(3, count($machine->getStates()));
     $this->assertEquals(6, count($machine->getTransitions()));
 }
 /**
  * creates plantuml state output for a statemachine
  *
  * @param string $machine            
  * @return string plant uml code, this can be used to render an image
  * @link http://www.plantuml.com/plantuml/
  * @link http://plantuml.sourceforge.net/state.html
  * @throws Exception
  */
 public function createStateDiagram(StateMachine $machine)
 {
     $transitions = $machine->getTransitions();
     // all states are aliased so the plantuml parser can handle the names
     $aliases = array();
     $end_states = array();
     $EOL = "\\n\\" . PHP_EOL;
     /* for multiline stuff in plantuml */
     $NEWLINE = PHP_EOL;
     // start with declaration
     $uml = "@startuml" . PHP_EOL;
     // skins for colors etc.
     $uml .= $this->getPlantUmlSkins() . PHP_EOL;
     // the order in which transitions are executed
     $order = array();
     // create the diagram by drawing all transitions
     foreach ($transitions as $t) {
         // get states and state aliases (plantuml cannot work with certain
         // characters, so therefore we create an alias for the state name)
         $from = $t->getStateFrom();
         $from_alias = $this->plantUmlStateAlias($from->getName());
         $to = $t->getStateTo();
         $to_alias = $this->plantUmlStateAlias($to->getName());
         // get some names to display
         $command = $t->getCommandName();
         $rule = self::escape($t->getRuleName());
         $name_transition = $t->getName();
         $description = $t->getDescription() ? "description: '" . $t->getDescription() . "'" . $EOL : '';
         $event = $t->getEvent() ? "event: '" . $t->getEvent() . "'" . $EOL : '';
         $f_description = $from->getDescription();
         $t_description = $to->getDescription();
         $f_exit = $from->getExitCommandName();
         $f_entry = $from->getEntryCommandName();
         $t_exit = $to->getExitCommandName();
         $t_entry = $to->getEntryCommandName();
         // only write aliases if not done before
         if (!isset($aliases[$from_alias])) {
             $uml .= 'state "' . $from . '" as ' . $from_alias . PHP_EOL;
             $uml .= "{$from_alias}: description: '" . $f_description . "'" . PHP_EOL;
             $uml .= "{$from_alias}: entry / '" . $f_entry . "'" . PHP_EOL;
             $uml .= "{$from_alias}: exit / '" . $f_exit . "'" . PHP_EOL;
             $aliases[$from_alias] = $from_alias;
         }
         // store order in which transitions will be handled
         if (!isset($order[$from_alias])) {
             $order[$from_alias] = 1;
         } else {
             $order[$from_alias] = $order[$from_alias] + 1;
         }
         // get 'to' alias
         if (!isset($aliases[$to_alias])) {
             $uml .= 'state "' . $to . '" as ' . $to_alias . PHP_EOL;
             $aliases[$to_alias] = $to_alias;
             $uml .= "{$to_alias}: description: '" . $t_description . "'" . PHP_EOL;
             $uml .= "{$to_alias}: entry / '" . $t_entry . "'" . PHP_EOL;
             $uml .= "{$to_alias}: exit / '" . $t_exit . "'" . PHP_EOL;
         }
         // write transition information
         $uml .= $from_alias . ' --> ' . $to_alias;
         $uml .= " : <b><size:10>{$name_transition}</size></b>" . $EOL;
         $uml .= $event;
         $uml .= "transition order from '{$from}': <b>" . $order[$from_alias] . "</b>" . $EOL;
         $uml .= "rule/guard: '{$rule}'" . $EOL;
         $uml .= "command/action: '{$command}'" . $EOL;
         $uml .= $description;
         $uml .= PHP_EOL;
         // store possible end states aliases
         if ($t->getStateFrom()->isFinal()) {
             $end_states[$from_alias] = $from_alias;
         }
         if ($t->getStateTo()->isFinal()) {
             $end_states[$to_alias] = $to_alias;
         }
     }
     // only one begin state
     $initial = $machine->getInitialState();
     $initial = $initial->getName();
     $initial_alias = $this->plantUmlStateAlias($initial);
     if (!isset($aliases[$initial_alias])) {
         $uml .= 'state "' . $initial . '" as ' . $initial_alias . PHP_EOL;
     }
     $uml .= "[*] --> {$initial_alias}" . PHP_EOL;
     // note for initial alias with explanation
     $uml .= "note right of {$initial_alias} {$NEWLINE}";
     $uml .= "state diagram for machine '" . $machine->getMachine() . "'{$NEWLINE}";
     $uml .= "created by izzum plantuml generator {$NEWLINE}";
     $uml .= "@link http://plantuml.sourceforge.net/state.html\"" . $NEWLINE;
     $uml .= "end note" . $NEWLINE;
     // add end states to diagram
     foreach ($end_states as $end) {
         $uml .= "{$end} --> [*]" . PHP_EOL;
     }
     // close plantuml
     $uml .= "@enduml" . PHP_EOL;
     return $uml;
 }