Skip to content

Commit

Permalink
State initializing and factories
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielCoulbourne committed Dec 12, 2023
1 parent 6c33c49 commit 476fe93
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 2 deletions.
32 changes: 32 additions & 0 deletions examples/Counter/tests/InitializeStateTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Thunk\Verbs\Facades\Verbs;
use Thunk\Verbs\Examples\Counter\States\CountState;
use Thunk\Verbs\Examples\Counter\Events\IncrementCount;
use Thunk\Verbs\Events\VerbsStateInitialized;
use Thunk\Verbs\Models\VerbEvent;

it('State factory initializes a state', function () {
$count_state = CountState::factory([
'count' => 1337
]);

expect($events = VerbEvent::all())
->toHaveCount(1);

expect($events->first())
->type->toBe(VerbsStateInitialized::class);

expect($count_state)
->toBeInstanceOf(CountState::class)
->count
->toBe(1337);

IncrementCount::fire();
Verbs::commit();

expect($count_state)
->toBeInstanceOf(CountState::class)
->count
->toBe(1338);
});
12 changes: 12 additions & 0 deletions src/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
abstract class Event
{
protected $verbs_should_commit_immediately = false;

public int $id;

public static function __callStatic(string $name, array $arguments)
Expand All @@ -33,6 +35,11 @@ public function metadata(?string $key = null, mixed $default = null): mixed
return app(MetadataManager::class)->get($this, $key, $default);
}

public function registerStates(): array
{
return [];
}

public function states(): StateCollection
{
// TODO: This is a bit hacky, but is probably OK right now
Expand Down Expand Up @@ -74,4 +81,9 @@ protected function assert($assertion, string $message): static

return $this;
}

public function shouldCommitImmediately(): bool
{
return $this->verbs_should_commit_immediately;
}
}
42 changes: 42 additions & 0 deletions src/Events/VerbsStateInitialized.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Thunk\Verbs\Events;

use Thunk\Verbs\Event;

class VerbsStateInitialized extends Event
{
protected $verbs_should_commit_immediately = true;

public function __construct(
public int|string|null $state_id,
public string $state_class,
public array $state_data,
) {}

public function registerStates(): array
{
return [
$this->state_id
? $this->state_class::load($this->state_id)
: $this->state_class::singleton(),
];
}

public function validate()
{
$this->assert(
! $this->state()->__verbs_initialized,
'State has already been initialized',
);
}

public function apply()
{
foreach ($this->state_data as $key => $value) {
$this->state()->$key = $value;
}

$this->state()->__verbs_initialized = true;
}
}
5 changes: 4 additions & 1 deletion src/Lifecycle/Broker.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ public function fire(Event $event): ?Event

app(Queue::class)->queue($event);

if ($this->commit_immediately) {
if (
$this->commit_immediately
|| $event->shouldCommitImmediately()
) {
$this->commit();
}

Expand Down
14 changes: 13 additions & 1 deletion src/State.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@

use Glhd\Bits\Bits;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Uid\AbstractUid;
use Thunk\Verbs\Lifecycle\EventStore;
use Symfony\Component\Uid\AbstractUid;
use Thunk\Verbs\Lifecycle\StateManager;
use Thunk\Verbs\Support\StateSerializer;
use Thunk\Verbs\Events\VerbsStateInitialized;

abstract class State
{
public Bits|UuidInterface|AbstractUid|int|string|null $id = null;

public Bits|UuidInterface|AbstractUid|int|string|null $last_event_id = null;

public bool $__verbs_initialized = false;

public static function make(...$args): static
{
if ((count($args) === 1 && isset($args[0]) && is_array($args[0]))) {
Expand Down Expand Up @@ -63,4 +66,13 @@ public function fresh(): static
{
return app(StateManager::class)->load($this->id, static::class);
}

public static function factory(array $data, ?int $id = null): static
{
return VerbsStateInitialized::fire(
state_id: $id,
state_class: static::class,
state_data: $data
)->state();
}
}
8 changes: 8 additions & 0 deletions src/Support/EventStateRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ public function getStates(Event $event): StateCollection
}
}

foreach ($event->registerStates() as $alias => $state) {
$discovered->push($state);

if (! is_numeric($alias)) {
$discovered->alias($alias, $state::class);
}
}

// Once we've loaded everything else, try to discover any deferred attributes
$deferred->each(fn (StateDiscoveryAttribute $attr) => $this->discoverAndPushState($attr, $event, $discovered));

Expand Down

0 comments on commit 476fe93

Please sign in to comment.