/** * returns the associated Command for the entry/exit/transition action on a * State or a Transition. * the Command will be configured with the 'reference' of the stateful * object * * @param string $command_name * entry~,exit~ or transition command name. * multiple commands can be split by a ',' in which case a * composite command will be returned. * @param Context $context * to be able to get the entity * @return ICommand * @throws Exception */ public static function getCommand($command_name, Context $context) { // it's oke to have no command, as there might be 'marker' states, where // we just need to transition something to a next state (according to a // rule) // where useful work can be done (eg: from the 'initial' type state to // a 'shortcut' state for special cases. if ($command_name === '' || $command_name === null) { // return a command without side effects return new Null(); } $output = new Composite(); // a command string can be made up of multiple commands seperated by a // comma $all_commands = explode(',', $command_name); // get the correct object to inject in the command(s) $entity = $context->getEntity(); foreach ($all_commands as $single_command) { if (!class_exists($single_command)) { $e = new Exception(sprintf("failed command creation, class does not exist: (%s) for Context (%s)", $single_command, $context->toString()), Exception::COMMAND_CREATION_FAILURE); throw $e; } try { $command = new $single_command($entity); $output->add($command); } catch (\Exception $e) { $e = new Exception(sprintf("command (%s) objects to construction for Context (%s). message: '%s'", $single_command, $context->toString(), $e->getMessage()), Exception::COMMAND_CREATION_FAILURE); throw $e; } } return $output; }
/** * returns the associated Rule for this Transition, * configured with a 'reference' (stateful) object * * @param Context $context * the associated Context for a our statemachine * @return IRule a Rule or chained AndRule if the rule input was a ',' * seperated string of rules. * @throws Exception */ public function getRule(Context $context) { // if no rule is defined, just allow the transition by default if ($this->rule === '' || $this->rule === null) { return new TrueRule(); } $entity = $context->getEntity(); // a rule string can be made up of multiple rules seperated by a comma $all_rules = explode(',', $this->rule); $rule = new TrueRule(); foreach ($all_rules as $single_rule) { // guard clause to check if rule exists if (!class_exists($single_rule)) { $e = new Exception(sprintf("failed rule creation, class does not exist: (%s) for Context (%s).", $this->rule, $context->toString()), Exception::RULE_CREATION_FAILURE); throw $e; } try { $and_rule = new $single_rule($entity); // create a chain of rules that need to be true $rule = new AndRule($rule, $and_rule); } catch (\Exception $e) { $e = new Exception(sprintf("failed rule creation, class objects to construction with entity: (%s) for Context (%s). message: %s", $this->rule, $context->toString(), $e->getMessage()), Exception::RULE_CREATION_FAILURE); throw $e; } } return $rule; }
/** * test the factory method with all parameters provided * implicitely tests the constructor */ public function testContext() { $entity_id = "id1"; $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($identifier, $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(State::STATE_NEW, 'this is an informational message about why we set this state: we set this state to new for a unittest'), 'added'); $this->assertFalse($o->setState(State::STATE_NEW), 'already there'); // for coverage. $statemachine = new StateMachine($o); $this->assertNull($o->setStateMachine($statemachine)); $this->assertContains('Context', $o . '', '__toString()'); }