Skip to content

Commit 294235b

Browse files
committed
removed poor validation code, new example for README.md, several architectural adjustments
1 parent 434afd6 commit 294235b

6 files changed

Lines changed: 158 additions & 65 deletions

File tree

README.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,119 @@ State Machines are not what you usually do with PHP but when you do... just use
55

66

77
It's a work-in-progress project! Wanna contribute? Let me know.
8+
9+
Usage example:
10+
11+
```php
12+
<?php
13+
14+
class PetitionEnum extends StateEnum {
15+
const __default = self::DRAFT,
16+
DRAFT = 'draft',
17+
SENT = 'sent',
18+
VOTED = 'voted',
19+
ACCEPTED = 'accepted',
20+
REJECTED = 'rejected',
21+
CANCELED = 'canceled';
22+
23+
}
24+
25+
class Petition extends Machine {
26+
27+
protected $votesYes, $votesNo;
28+
29+
public function init() {
30+
$this->setInitState(PetitionEnum::DRAFT());
31+
32+
$this
33+
->allowTransition(PetitionEnum::DRAFT(), PetitionEnum::SENT())
34+
->allowTransition(PetitionEnum::DRAFT(), PetitionEnum::CANCELED())
35+
->allowTransition(PetitionEnum::SENT(), PetitionEnum::VOTED())
36+
->allowTransition(PetitionEnum::VOTED(), PetitionEnum::ACCEPTED())
37+
->allowTransition(PetitionEnum::VOTED(), PetitionEnum::REJECTED())
38+
;
39+
40+
}
41+
42+
public function send()
43+
{
44+
// shall throw an exception if current state is not DRAFT because it wasn't allowed transition
45+
$this->setMachineState(PetitionEnum::SENT());
46+
}
47+
48+
public function cancel()
49+
{
50+
// shall throw an exception if current state is not DRAFT because it wasn't allowed transition
51+
$this->setMachineState(PetitionEnum::CANCELED());
52+
}
53+
54+
55+
public function setVotes($ya, $nay)
56+
{
57+
$this->votesYes = $ya;
58+
$this->votesNo = $nay;
59+
}
60+
61+
public function assertSentToVoted()
62+
{
63+
if (null !== $this->votesYes && null !== $this->votesNo)
64+
{
65+
return true;
66+
}
67+
68+
return false;
69+
}
70+
71+
72+
public function assertVotedToAccepted()
73+
{
74+
if ($this->votesYes > $this->votesNo)
75+
{
76+
return true;
77+
}
78+
79+
return false;
80+
}
81+
82+
public function assertVotedToRejected()
83+
{
84+
if ($this->votesYes <= $this->votesNo)
85+
{
86+
return true;
87+
}
88+
89+
return false;
90+
}
91+
92+
public function onTransition(Transition $transition)
93+
{
94+
/* for purpose of this example we only echo this transition but you can
95+
easily dispatch an event from here */
96+
echo 'State changed from ' . $transition->getFromState() . ' to ' . $transition->getToState() . PHP_EOL;
97+
}
98+
}
99+
100+
101+
$p = new Petition();
102+
103+
$p->run();
104+
// <nothing happens>
105+
106+
$p->send();
107+
// State changed from draft to sent
108+
109+
$p->run();
110+
// <nothing happens>
111+
112+
$p->setVotes(5,1);
113+
114+
$p->run();
115+
// State changed from sent to voted
116+
// State changed from voted to accepted
117+
118+
119+
120+
121+
122+
```
123+
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/**
77
* False Assertion for unit testing
88
*/
9-
class FalseAssertion extends Assertion
9+
class AlwaysFalseAssertion extends Assertion
1010
{
1111
public function make(): bool
1212
{
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
4+
namespace Coff\SMF\Assertion;
5+
6+
7+
class AlwaysTrueAssertion extends Assertion
8+
{
9+
10+
public function make() : bool
11+
{
12+
return true;
13+
}
14+
}

src/Assertion/Assertion.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@
1010
*
1111
* @package Coff\SMF\Assertion
1212
*/
13-
class Assertion implements AssertionInterface
13+
abstract class Assertion implements AssertionInterface
1414
{
1515

16-
public function make() : bool
17-
{
18-
return true;
19-
}
2016
}

src/Machine.php

Lines changed: 19 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -143,75 +143,31 @@ public function assertTransition(Transition $transition) : bool
143143

144144
public function run() {
145145

146-
$allowedTrans = $this->getAllowedTransitions();
146+
do {
147147

148-
/**
149-
* @var StateEnum $nextState
150-
* @var Transition $transition
151-
*/
152-
foreach ($allowedTrans as $nextState => $transition) {
153-
154-
155-
if (true === $transition->assert()) {
156-
$this->machineState = $transition->getToState();
157-
158-
return $nextState;
159-
}
160-
}
161-
162-
return false;
163-
}
164-
165-
public function validate() {
166-
167-
$allowedTrans = $this->getAllowedTransitions($this->getInitState());
168-
169-
/**
170-
* @var StateEnum $nextState
171-
* @var Transition $transition
172-
*/
173-
foreach ($allowedTrans as $nextState => $transition) {
174-
175-
176-
if (true === $transition->assert()) {
177-
$this->machineState = $transition->getToState();
178-
179-
return $nextState;
180-
}
181-
}
182-
183-
return false;
184-
}
185-
186-
/**
187-
* @param StateEnum $state
188-
*/
189-
private function doValidate(StateEnum $state) {
148+
$allowedTrans = $this->getAllowedTransitions();
190149

191-
$allowedTrans = $this->getAllowedTransitions($state);
192-
193-
if (0 === count($allowedTrans)) {
194-
return false;
195-
}
150+
/**
151+
* @var StateEnum $nextState
152+
* @var Transition $transition
153+
*/
154+
foreach ($allowedTrans as $nextState => $transition) {
196155

197-
/**
198-
* @var StateEnum $nextState
199-
* @var Transition $transition
200-
*/
201-
foreach ($allowedTrans as $nextState => $transition) {
156+
$result = $transition->assert();
202157

203-
if ($transition->getToState() === $this->getInitState()) {
204-
// transition path ends on initial state
205-
} else {
206-
if (false === $this->doValidate($transition->getToState())) {
158+
if (true === $result) {
159+
$this->machineState = $transition->getToState();
207160

161+
$this->onTransition($transition);
208162
}
209163
}
210-
}
211164

212-
return true;
165+
} while (true == $result);
166+
167+
return $this->machineState;
213168
}
214169

170+
215171
/**
216172
* Machine-internal method for setting new state. Normally this should only be allowed from within the machine
217173
* assertState() method. To set machine's state externally create dedicated methods like:
@@ -230,8 +186,12 @@ protected function setMachineState(StateEnum $newState) {
230186
throw new TransitionException('State transition from ' . (string) $this->getMachineState() . ' to ' . (string) $newState . 'is not allowed.');
231187
}
232188

189+
$oldState = $this->machineState;
190+
233191
$this->machineState = $newState;
234192

193+
$this->onTransition($this->getTransition($oldState, $newState));
194+
235195
return $this;
236196
}
237197
}

src/MachineInterface.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ public function isMachineState(StateEnum $state) : bool;
4040
*/
4141
public function assertTransition(Transition $transition) : bool;
4242

43+
/**
44+
* This method is called on any state transition
45+
* @param Transition $transition
46+
* @return $this
47+
*/
48+
public function onTransition(Transition $transition);
49+
4350
/**
4451
* Runs state machine. Performs assertions for all transitions defined for current state.
4552
* @return mixed

0 commit comments

Comments
 (0)