diff --git a/.gitignore b/.gitignore index 4520b24..c404936 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ vendor bin composer.lock +.idea diff --git a/spec/SM/StateMachine/StateMachineSpec.php b/spec/SM/StateMachine/StateMachineSpec.php index 5324cd0..b8674a0 100644 --- a/spec/SM/StateMachine/StateMachineSpec.php +++ b/spec/SM/StateMachine/StateMachineSpec.php @@ -204,4 +204,24 @@ function it_returns_possible_transitions($object, $callbackFactory, CallbackInte $this->getPossibleTransitions()->shouldReturn(array('create', 'confirm')); } + + function it_can_accept_specific_from_to_transition_mappings($object, $dispatcher, $callbackFactory, CallbackInterface $guard) + { + $transition = $this->config['transitions']['create']; + + $this->config['transitions']['create'] = array( + $transition + ); + + $object->getState()->shouldBeCalled()->willReturn('checkout'); + $object->setState(Argument::any())->shouldNotBeCalled(); + + $dispatcher->dispatch(SMEvents::TEST_TRANSITION, Argument::type('SM\\Event\\TransitionEvent'))->shouldBeCalled(); + + $callbackFactory->get($this->config['callbacks']['guard']['guard-confirm'])->shouldBeCalled()->willReturn($guard); + + $guard->__invoke(Argument::type('SM\\Event\\TransitionEvent'))->shouldBeCalled()->willReturn(true); + + $this->can('create')->shouldReturn(true); + } } diff --git a/src/SM/StateMachine/StateMachine.php b/src/SM/StateMachine/StateMachine.php index 6b785c2..ba97216 100644 --- a/src/SM/StateMachine/StateMachine.php +++ b/src/SM/StateMachine/StateMachine.php @@ -83,23 +83,16 @@ public function __construct( /** * {@inheritDoc} */ - public function can($transition) + public function can($transitionName) { - if (!isset($this->config['transitions'][$transition])) { - throw new SMException(sprintf( - 'Transition "%s" does not exist on object "%s" with graph "%s"', - $transition, - get_class($this->object), - $this->config['graph'] - )); - } + $transition = $this->getTransition($transitionName); - if (!in_array($this->getState(), $this->config['transitions'][$transition]['from'])) { + if (!$transition) { return false; } $can = true; - $event = new TransitionEvent($transition, $this->getState(), $this->config['transitions'][$transition], $this); + $event = new TransitionEvent($transitionName, $this->getState(), $transition, $this); if (null !== $this->dispatcher) { $this->dispatcher->dispatch(SMEvents::TEST_TRANSITION, $event); @@ -112,23 +105,25 @@ public function can($transition) /** * {@inheritDoc} */ - public function apply($transition, $soft = false) + public function apply($transitionName, $soft = false) { - if (!$this->can($transition)) { + if (!$this->can($transitionName)) { if ($soft) { return false; } throw new SMException(sprintf( 'Transition "%s" cannot be applied on state "%s" of object "%s" with graph "%s"', - $transition, + $transitionName, $this->getState(), get_class($this->object), $this->config['graph'] )); } - $event = new TransitionEvent($transition, $this->getState(), $this->config['transitions'][$transition], $this); + $transition = $this->getTransition($transitionName); + + $event = new TransitionEvent($transitionName, $this->getState(), $transition, $this); if (null !== $this->dispatcher) { $this->dispatcher->dispatch(SMEvents::PRE_TRANSITION, $event); @@ -140,7 +135,7 @@ public function apply($transition, $soft = false) $this->callCallbacks($event, 'before'); - $this->setState($this->config['transitions'][$transition]['to']); + $this->setState($transition['to']); $this->callCallbacks($event, 'after'); @@ -232,4 +227,36 @@ protected function callCallbacks(TransitionEvent $event, $position) } return $result; } + + /** + * @param $transitionName + * + * @return bool|mixed + * @throws SMException + */ + private function getTransition($transitionName) + { + if (!isset($this->config['transitions'][$transitionName])) { + throw new SMException(sprintf( + 'Transition "%s" does not exist on object "%s" with graph "%s"', + $transitionName, + get_class($this->object), + $this->config['graph'] + )); + } + + $transition = $this->config['transitions'][$transitionName]; + + if (array_key_exists('from', $transition)) { + $transition = array($transition); + } + + $state = $this->getState(); + + $results = array_filter($transition, function($value) use ($state) { + return in_array($state, $value['from']); + }); + + return count($results) > 0 ? array_shift($results) : false; + } } diff --git a/src/SM/StateMachine/StateMachineInterface.php b/src/SM/StateMachine/StateMachineInterface.php index b09da5f..6420d5a 100644 --- a/src/SM/StateMachine/StateMachineInterface.php +++ b/src/SM/StateMachine/StateMachineInterface.php @@ -18,25 +18,25 @@ interface StateMachineInterface /** * Can the transition be applied on the underlying object * - * @param string $transition + * @param string $transitionName * * @return bool * * @throws SMException If transition doesn't exist */ - public function can($transition); + public function can($transitionName); /** * Applies the transition on the underlying object * - * @param string $transition Transition to apply - * @param bool $soft Soft means do nothing if transition can't be applied (no exception thrown) + * @param string $transitionName Transition to apply + * @param bool $soft Soft means do nothing if transition can't be applied (no exception thrown) * * @return bool If the transition has been applied or not (in case of soft apply or rejected pre transition event) * * @throws SMException If transition can't be applied or doesn't exist */ - public function apply($transition, $soft = false); + public function apply($transitionName, $soft = false); /** * Returns the current state