Skip to content

Commit

Permalink
Merge pull request #224 from ralphjsmit/rjs/add-register-state-attribute
Browse files Browse the repository at this point in the history
Add missing `RegisterState` Attribute
  • Loading branch information
freekmurze authored Jan 24, 2023
2 parents f2ad7e6 + 26dbcbe commit 288bbd4
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 20 deletions.
38 changes: 21 additions & 17 deletions docs/working-with-states/01-configuring-states.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,23 +83,6 @@ abstract class PaymentState extends State
}
```

If you're using PHP 8 or higher, you can also configure your state using attributes:

```php
use Spatie\ModelStates\Attributes\AllowTransition;
use Spatie\ModelStates\State;

#[
AllowTransition(Pending::class, Paid::class),
AllowTransition(Pending::class, Failed::class),
DefaultState(Pending::class),
]
abstract class PaymentState extends State
{
abstract public function color(): string;
}
```

## Manually registering states
If you want to place your concrete state implementations in a different directory, you may do so and register them manually:

Expand Down Expand Up @@ -128,4 +111,25 @@ abstract class PaymentState extends State
}
```

## Configuring states using attributes

If you're using PHP 8 or higher, you can also configure your state using attributes:

```php
use Spatie\ModelStates\Attributes\AllowTransition;
use Spatie\ModelStates\Attributes\RegisterState;use Spatie\ModelStates\State;use const Grpc\STATUS_CANCELLED;

#[
AllowTransition(Pending::class, Paid::class),
AllowTransition(Pending::class, Failed::class),
DefaultState(Pending::class),
RegisterState(Cancelled::class),
RegisterState([ExampleOne::class, ExampleTwo::class]),
]
abstract class PaymentState extends State
{
abstract public function color(): string;
}
```

Next up, we'll take a moment to discuss how state classes are serialized to the database.
14 changes: 12 additions & 2 deletions src/Attributes/AttributeLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,17 @@ public function load(StateConfig $stateConfig): StateConfig

$stateConfig->default($defaultStateAttribute->defaultStateClass);
}

return $stateConfig;

$registerStateAttributes = $this->reflectionClass->getAttributes(RegisterState::class);

foreach($registerStateAttributes as $attribute) {
/** @var \Spatie\ModelStates\Attributes\RegisterState $registerStateAttribute */
$registerStateAttribute = $attribute->newInstance();

$stateConfig->registerState($registerStateAttribute->stateClass);
}


return $stateConfig;
}
}
15 changes: 15 additions & 0 deletions src/Attributes/RegisterState.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Spatie\ModelStates\Attributes;

use Attribute;
use JetBrains\PhpStorm\Immutable;

#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
class RegisterState
{
public function __construct(
#[Immutable] public string|array $stateClass,
) {
}
}
26 changes: 25 additions & 1 deletion tests/AttributeSateTest.php → tests/AttributeStateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

namespace Spatie\ModelStates\Tests;

use Spatie\ModelStates\Tests\Dummy\AttributeState\AnotherDirectory\AttributeStateC;
use Spatie\ModelStates\Tests\Dummy\AttributeState\AnotherDirectory\AttributeStateD;
use Spatie\ModelStates\Tests\Dummy\AttributeState\AnotherDirectory\AttributeStateE;
use Spatie\ModelStates\Tests\Dummy\AttributeState\AttributeStateA;
use Spatie\ModelStates\Tests\Dummy\AttributeState\AttributeStateB;
use Spatie\ModelStates\Tests\Dummy\AttributeState\AttributeStateTransition;
use Spatie\ModelStates\Tests\Dummy\AttributeState\TestModelWithAttributeState;

class AttributeSateTest extends TestCase
class AttributeStateTest extends TestCase
{
/** @test */
public function test_default()
Expand Down Expand Up @@ -39,4 +42,25 @@ public function test_allowed_transition()
$this->assertTrue($model->state->equals(AttributeStateB::class));
$this->assertTrue(AttributeStateTransition::$transitioned);
}

/** @test */
public function test_registered_states()
{
if (PHP_VERSION_ID < 80000) {
$this->markTestSkipped('Not PHP 8');

return;
}

$model = new TestModelWithAttributeState();

$this->assertSame([AttributeStateC::class, AttributeStateD::class, AttributeStateE::class], AttributeStateA::config()->registeredStates);
$this->assertSame([AttributeStateC::class, AttributeStateD::class, AttributeStateE::class], AttributeStateC::config()->registeredStates);

$this->assertTrue($model->state->equals(AttributeStateA::class));

$model->state->transitionTo(AttributeStateC::class);

$this->assertTrue($model->state->equals(AttributeStateC::class));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Spatie\ModelStates\Tests\Dummy\AttributeState\AnotherDirectory;

use Spatie\ModelStates\Tests\Dummy\AttributeState\AttributeState;

class AttributeStateC extends AttributeState
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Spatie\ModelStates\Tests\Dummy\AttributeState\AnotherDirectory;

use Spatie\ModelStates\Tests\Dummy\AttributeState\AttributeState;

class AttributeStateD extends AttributeState
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Spatie\ModelStates\Tests\Dummy\AttributeState\AnotherDirectory;

use Spatie\ModelStates\Tests\Dummy\AttributeState\AttributeState;

class AttributeStateE extends AttributeState
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Spatie\ModelStates\Tests\Dummy\AttributeState\AnotherDirectory;

use Spatie\ModelStates\Tests\Dummy\AttributeState\AttributeState;

class AttributeStateF extends AttributeState
{
}
7 changes: 7 additions & 0 deletions tests/Dummy/AttributeState/AttributeState.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@

use Spatie\ModelStates\Attributes\AllowTransition;
use Spatie\ModelStates\Attributes\DefaultState;
use Spatie\ModelStates\Attributes\RegisterState;
use Spatie\ModelStates\State;
use Spatie\ModelStates\Tests\Dummy\AttributeState\AnotherDirectory\AttributeStateC;
use Spatie\ModelStates\Tests\Dummy\AttributeState\AnotherDirectory\AttributeStateD;
use Spatie\ModelStates\Tests\Dummy\AttributeState\AnotherDirectory\AttributeStateE;

#[
AllowTransition(AttributeStateA::class, AttributeStateB::class, AttributeStateTransition::class),
AllowTransition(AttributeStateB::class, AttributeStateA::class),
AllowTransition(AttributeStateA::class, AttributeStateC::class),
DefaultState(AttributeStateA::class),
RegisterState(AttributeStateC::class),
RegisterState([AttributeStateD::class, AttributeStateE::class]),
]
abstract class AttributeState extends State
{
Expand Down

0 comments on commit 288bbd4

Please sign in to comment.