Skip to content

Commit 2ca065e

Browse files
authored
Merge pull request #265 from jonjakoblich/main
Make using allowAllTransitions() less cumbersome
2 parents 56e6207 + 91f00c3 commit 2ca065e

11 files changed

+106
-22
lines changed

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
"illuminate/contracts": "^8.73 | ^9.0 | ^10.0 | ^11.0",
2323
"illuminate/database": "^8.73 | ^9.0 | ^10.0 | ^11.0",
2424
"illuminate/support": "^8.73 | ^9.0 | ^10.0 | ^11.0",
25-
"spatie/laravel-package-tools": "^1.9"
25+
"spatie/laravel-package-tools": "^1.9",
26+
"spatie/php-structure-discoverer": "^2.2"
2627
},
2728
"require-dev": {
2829
"orchestra/testbench": "^6.23 | ^7.0 | ^8.0 | ^9.0",

docs/working-with-transitions/01-configuring-transitions.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ abstract class PaymentState extends State
2323
}
2424
```
2525

26-
In this example we're using both a simple transition, and a custom one. You can also allow all transitions if your states are already properly registered:
26+
In this example we're using both a simple transition, and a custom one. You can also allow all transitions for all registered states. Concrete states extending the abstract state class that are located in the same directory as the abstract state class will be automatically registered:
2727

2828
```php
2929
abstract class PaymentState extends State

src/StateConfig.php

+18
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
namespace Spatie\ModelStates;
44

5+
use ReflectionClass;
56
use Spatie\ModelStates\Events\StateChanged;
67
use Spatie\ModelStates\Exceptions\InvalidConfig;
8+
use Spatie\StructureDiscoverer\Discover;
79

810
class StateConfig
911
{
@@ -132,6 +134,8 @@ public function stateChangedEvent(string $event): StateConfig
132134
*/
133135
public function allowAllTransitions(): StateConfig
134136
{
137+
$this->registerBaseStateClassDirectoryStates();
138+
135139
if (empty($this->registeredStates)) {
136140
throw new InvalidConfig('No states registered for ' . $this->baseStateClass);
137141
}
@@ -141,6 +145,20 @@ public function allowAllTransitions(): StateConfig
141145
return $this;
142146
}
143147

148+
private function registerBaseStateClassDirectoryStates(): void
149+
{
150+
$reflector = new ReflectionClass($this->baseStateClass);
151+
$filename = $reflector->getFileName();
152+
$baseStateClassDirectory = dirname($filename);
153+
154+
$stateClasses = Discover::in($baseStateClassDirectory)
155+
->classes()
156+
->extending($this->baseStateClass)
157+
->get();
158+
159+
$this->registerState($stateClasses);
160+
}
161+
144162
/**
145163
* @param string|\Spatie\ModelStates\State $from
146164
* @param string|\Spatie\ModelStates\State $to

tests/Dummy/AllowAllTransitionsState/AllowAllTransitionsState.php

-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ public static function config(): StateConfig
1111
{
1212
return parent::config()
1313
->default(StateA::class)
14-
->registerState(StateA::class)
15-
->registerState(StateB::class)
16-
->registerState(StateC::class)
1714
->allowAllTransitions();
1815
}
1916
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithExplicitlyRegisteredStates;
4+
5+
use Spatie\ModelStates\State;
6+
use Spatie\ModelStates\StateConfig;
7+
use Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithNoRegisteredStates\StateAWithNoRegisteredStates;
8+
use Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithNoRegisteredStates\StateBWithNoRegisteredStates;
9+
use Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithNoRegisteredStates\StateCWithNoRegisteredStates;
10+
11+
abstract class AllowAllTransitionsStateWithExplicitlyRegisteredStates extends State
12+
{
13+
public static function config(): StateConfig
14+
{
15+
return parent::config()
16+
->registerState(StateAWithNoRegisteredStates::class)
17+
->registerState(StateBWithNoRegisteredStates::class)
18+
->registerState(StateCWithNoRegisteredStates::class)
19+
->default(StateAWithNoRegisteredStates::class)
20+
->allowAllTransitions();
21+
}
22+
}

tests/Dummy/AllowAllTransitionsStateWithNoRegisteredStates/AllowAllTransitionsStateWithNoRegisteredStates.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44

55
use Spatie\ModelStates\State;
66
use Spatie\ModelStates\StateConfig;
7+
use Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState\StateA;
78

89
abstract class AllowAllTransitionsStateWithNoRegisteredStates extends State
910
{
1011
public static function config(): StateConfig
1112
{
1213
return parent::config()
13-
->default(StateAWithNoRegisteredStates::class)
14+
->default(StateA::class)
1415
->allowAllTransitions();
1516
}
1617
}

tests/Dummy/AllowAllTransitionsStateWithNoRegisteredStates/StateAWithNoRegisteredStates.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithNoRegisteredStates;
44

5-
class StateAWithNoRegisteredStates extends AllowAllTransitionsStateWithNoRegisteredStates
5+
use Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithExplicitlyRegisteredStates\AllowAllTransitionsStateWithExplicitlyRegisteredStates;
6+
7+
class StateAWithNoRegisteredStates extends AllowAllTransitionsStateWithExplicitlyRegisteredStates
68
{
79

810
}

tests/Dummy/AllowAllTransitionsStateWithNoRegisteredStates/StateBWithNoRegisteredStates.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithNoRegisteredStates;
44

5-
class StateBWithNoRegisteredStates extends AllowAllTransitionsStateWithNoRegisteredStates
5+
use Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithExplicitlyRegisteredStates\AllowAllTransitionsStateWithExplicitlyRegisteredStates;
6+
7+
class StateBWithNoRegisteredStates extends AllowAllTransitionsStateWithExplicitlyRegisteredStates
68
{
79

810
}

tests/Dummy/AllowAllTransitionsStateWithNoRegisteredStates/StateCWithNoRegisteredStates.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithNoRegisteredStates;
44

5-
class StateCWithNoRegisteredStates extends AllowAllTransitionsStateWithNoRegisteredStates
5+
use Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithExplicitlyRegisteredStates\AllowAllTransitionsStateWithExplicitlyRegisteredStates;
6+
7+
class StateCWithNoRegisteredStates extends AllowAllTransitionsStateWithExplicitlyRegisteredStates
68
{
79

810
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Spatie\ModelStates\Tests\Dummy;
4+
5+
use Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithExplicitlyRegisteredStates\AllowAllTransitionsStateWithExplicitlyRegisteredStates;
6+
7+
class TestModelAllowAllTransitionsWithExplicitlyRegisteredStates extends TestModel
8+
{
9+
protected $casts = [
10+
'state' => AllowAllTransitionsStateWithExplicitlyRegisteredStates::class,
11+
];
12+
}

tests/StateTest.php

+40-13
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use Illuminate\Support\Facades\Event;
44
use Spatie\ModelStates\Exceptions\InvalidConfig;
5-
use Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithNoRegisteredStates\AllowAllTransitionsStateWithNoRegisteredStates;
5+
use Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsStateWithNoRegisteredStates;
66
use Spatie\ModelStates\Events\StateChanged;
77
use Spatie\ModelStates\Exceptions\ClassDoesNotExtendBaseClass;
88
use Spatie\ModelStates\Tests\Dummy\CustomEventModelState\CustomEventModelStateB;
@@ -22,12 +22,14 @@
2222
use Spatie\ModelStates\Tests\Dummy\OtherModelStates\StateY;
2323
use Spatie\ModelStates\Tests\Dummy\TestModel;
2424
use Spatie\ModelStates\Tests\Dummy\TestModelAllowAllTransitions;
25+
use Spatie\ModelStates\Tests\Dummy\TestModelAllowAllTransitionsWithExplicitlyRegisteredStates;
2526
use Spatie\ModelStates\Tests\Dummy\TestModelAllowAllTransitionsWithNoRegisteredStates;
2627
use Spatie\ModelStates\Tests\Dummy\TestModelCustomEvent;
2728
use Spatie\ModelStates\Tests\Dummy\TestModelCustomInvalidEvent;
2829
use Spatie\ModelStates\Tests\Dummy\TestModelUpdatingEvent;
2930
use Spatie\ModelStates\Tests\Dummy\TestModelWithCustomTransition;
3031
use Spatie\ModelStates\Tests\Dummy\TestModelWithDefault;
32+
use Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState;
3133

3234
it('resolve state class', function () {
3335
expect(ModelState::resolveStateClass(StateA::class))->toEqual(StateA::class);
@@ -255,27 +257,52 @@
255257
it('should allow all transitions', function () {
256258
$model = TestModelAllowAllTransitions::create();
257259

258-
expect($model->state->canTransitionTo(\Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState\StateA::class))->toBeTrue()
259-
->and($model->state->canTransitionTo(\Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState\StateB::class))->toBeTrue()
260-
->and($model->state->canTransitionTo(\Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState\StateC::class))->toBeTrue();
260+
expect($model->state)
261+
->canTransitionTo(AllowAllTransitionsState\StateA::class)->toBeTrue()
262+
->canTransitionTo(AllowAllTransitionsState\StateB::class)->toBeTrue()
263+
->canTransitionTo(AllowAllTransitionsState\StateC::class)->toBeTrue();
261264

262-
$model->state->transitionTo(\Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState\StateB::class);
265+
$model->state->transitionTo(AllowAllTransitionsState\StateB::class);
263266

264-
expect($model->state->canTransitionTo(\Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState\StateA::class))->toBeTrue()
265-
->and($model->state->canTransitionTo(\Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState\StateB::class))->toBeTrue()
266-
->and($model->state->canTransitionTo(\Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState\StateC::class))->toBeTrue();
267+
expect($model->state)
268+
->canTransitionTo(AllowAllTransitionsState\StateA::class)->toBeTrue()
269+
->canTransitionTo(AllowAllTransitionsState\StateB::class)->toBeTrue()
270+
->canTransitionTo(AllowAllTransitionsState\StateC::class)->toBeTrue();
267271

268-
$model->state->transitionTo(\Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState\StateC::class);
272+
$model->state->transitionTo(AllowAllTransitionsState\StateC::class);
269273

270-
expect($model->state->canTransitionTo(\Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState\StateA::class))->toBeTrue()
271-
->and($model->state->canTransitionTo(\Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState\StateB::class))->toBeTrue()
272-
->and($model->state->canTransitionTo(\Spatie\ModelStates\Tests\Dummy\AllowAllTransitionsState\StateC::class))->toBeTrue();
274+
expect($model->state)
275+
->canTransitionTo(AllowAllTransitionsState\StateA::class)->toBeTrue()
276+
->canTransitionTo(AllowAllTransitionsState\StateB::class)->toBeTrue()
277+
->canTransitionTo(AllowAllTransitionsState\StateC::class)->toBeTrue();
278+
});
279+
280+
it('should allow all transitions for explicitly registered states', function () {
281+
$model = TestModelAllowAllTransitionsWithExplicitlyRegisteredStates::create();
282+
283+
expect($model->state)
284+
->canTransitionTo(AllowAllTransitionsStateWithNoRegisteredStates\StateAWithNoRegisteredStates::class)->toBeTrue()
285+
->canTransitionTo(AllowAllTransitionsStateWithNoRegisteredStates\StateBWithNoRegisteredStates::class)->toBeTrue()
286+
->canTransitionTo(AllowAllTransitionsStateWithNoRegisteredStates\StateCWithNoRegisteredStates::class)->toBeTrue();
287+
288+
$model->state->transitionTo(AllowAllTransitionsStateWithNoRegisteredStates\StateBWithNoRegisteredStates::class);
289+
290+
expect($model->state)
291+
->canTransitionTo(AllowAllTransitionsStateWithNoRegisteredStates\StateAWithNoRegisteredStates::class)->toBeTrue()
292+
->canTransitionTo(AllowAllTransitionsStateWithNoRegisteredStates\StateBWithNoRegisteredStates::class)->toBeTrue()
293+
->canTransitionTo(AllowAllTransitionsStateWithNoRegisteredStates\StateCWithNoRegisteredStates::class)->toBeTrue();
294+
295+
$model->state->transitionTo(AllowAllTransitionsStateWithNoRegisteredStates\StateCWithNoRegisteredStates::class);
273296

297+
expect($model->state)
298+
->canTransitionTo(AllowAllTransitionsStateWithNoRegisteredStates\StateAWithNoRegisteredStates::class)->toBeTrue()
299+
->canTransitionTo(AllowAllTransitionsStateWithNoRegisteredStates\StateBWithNoRegisteredStates::class)->toBeTrue()
300+
->canTransitionTo(AllowAllTransitionsStateWithNoRegisteredStates\StateCWithNoRegisteredStates::class)->toBeTrue();
274301
});
275302

276303
it('should throw exception when allowing all transitions when there are no registered states', function () {
277304
$this->expectException(InvalidConfig::class);
278-
$this->expectExceptionMessage('No states registered for ' . AllowAllTransitionsStateWithNoRegisteredStates::class);
305+
$this->expectExceptionMessage('No states registered for ' . AllowAllTransitionsStateWithNoRegisteredStates\AllowAllTransitionsStateWithNoRegisteredStates::class);
279306

280307
TestModelAllowAllTransitionsWithNoRegisteredStates::create();
281308
});

0 commit comments

Comments
 (0)