Passed
Pull Request — master (#19)
by Yannick
02:27
created

StateMachine::setCurrentState()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the php-state project.
4
 *
5
 * (c) Yannick Voyer <[email protected]> (http://github.com/yvoyer)
6
 */
7
8
namespace Star\Component\State;
9
10
use Star\Component\State\Callbacks\AlwaysThrowExceptionOnFailure;
11
use Star\Component\State\Callbacks\TransitionCallback;
12
use Star\Component\State\Event\StateEventStore;
13
use Star\Component\State\Event\TransitionWasFailed;
14
use Star\Component\State\Event\TransitionWasSuccessful;
15
use Star\Component\State\Event\TransitionWasRequested;
16
use Webmozart\Assert\Assert;
17
18
final class StateMachine
19
{
20
    /**
21
     * @var EventRegistry
22
     */
23
    private $listeners;
24
25
    /**
26
     * @var StateRegistry
27
     */
28
    private $states;
29
30
    /**
31
     * @var string
32
     */
33
    private $currentState;
34
35
    /**
36
     * @param string $currentState
37
     * @param StateRegistry $states
38
     * @param EventRegistry $listeners
39
     */
40 47
    public function __construct(
41
        $currentState,
42
        StateRegistry $states,
43
        EventRegistry $listeners
44
    ) {
45 47
        Assert::string($currentState);
46 47
        $this->listeners = $listeners;
47 47
        $this->states = $states;
48 47
        $this->setCurrentState($currentState);
49 47
    }
50
51
    /**
52
     * @param string $transitionName The transition name
53
     * @param mixed $context
54
     * @param TransitionCallback|null $callback
55
     *
56
     * @return string The next state to store on your context
57
     * @throws InvalidStateTransitionException
58
     * @throws NotFoundException
59
     */
60 30
    public function transit($transitionName, $context, TransitionCallback $callback = null)
61
    {
62 30
        if (! $callback) {
63 29
            $callback = new AlwaysThrowExceptionOnFailure();
64
        }
65
66 30
        $this->listeners->dispatch(
67 30
            StateEventStore::BEFORE_TRANSITION,
68 30
            new TransitionWasRequested($transitionName)
69
        );
70
71 30
        Assert::string($transitionName);
72 30
        $transition = $this->states->getTransition($transitionName);
73 29
        $callback->beforeStateChange($context, $this);
74
75 29
        $newState = $transition->getDestinationState();
76 29
        if (! $transition->isAllowed($this->currentState)) {
77 11
            $exception = InvalidStateTransitionException::notAllowedTransition(
78 11
                $transitionName,
79 11
                $context,
80 11
                $this->currentState
81
            );
82
83 11
            $this->listeners->dispatch(
84 11
                StateEventStore::FAILURE_TRANSITION,
85 11
                new TransitionWasFailed($transitionName, $exception)
86
            );
87
88 11
            $newState = $callback->onFailure($exception, $context, $this);
89
        }
90 19
        Assert::string($newState);
91
92 19
        $this->setCurrentState($newState);
93
94 19
        $callback->afterStateChange($context, $this);
95
96 19
        $this->listeners->dispatch(
97 19
            StateEventStore::AFTER_TRANSITION,
98 19
            new TransitionWasSuccessful($transitionName)
99
        );
100
101 19
        return $this->currentState;
102
    }
103
104
    /**
105
     * @param string $stateName
106
     * @return bool
107
     * @throws NotFoundException
108
     */
109 34
    public function isInState($stateName)
110
    {
111 34
        Assert::string($stateName);
112 34
        if (! $this->states->hasState($stateName)) {
113 1
            throw NotFoundException::stateNotFound($stateName);
114
        }
115
116 33
        return $this->currentState === $stateName;
117
    }
118
119
    /**
120
     * @param string $attribute
121
     *
122
     * @return bool
123
     */
124 9
    public function hasAttribute($attribute)
125
    {
126 9
        Assert::string($attribute);
127 9
        return $this->states->getState($this->currentState)->hasAttribute($attribute);
128
    }
129
130
    /**
131
     * @param string $event
132
     * @param \Closure $listener
133
     */
134
    public function addListener($event, \Closure $listener)
135
    {
136
        Assert::string($event);
137
        $this->listeners->addListener($event, $listener);
138
    }
139
140
    /**
141
     * @param TransitionVisitor $visitor
142
     */
143 3
    public function acceptTransitionVisitor(TransitionVisitor $visitor)
144
    {
145 3
        $this->states->acceptTransitionVisitor($visitor);
146 3
    }
147
148
    /**
149
     * @param StateVisitor $visitor
150
     */
151 2
    public function acceptStateVisitor(StateVisitor $visitor)
152
    {
153 2
        $this->states->acceptStateVisitor($visitor);
154 2
    }
155
156
    /**
157
     * @param string $state
158
     */
159 47
    private function setCurrentState($state)
160
    {
161 47
        Assert::string($state);
162 47
        $this->currentState = $state;
163 47
    }
164
}
165