Skip to content

Commit

Permalink
Allow union types in event properties (#189)
Browse files Browse the repository at this point in the history
* Allow union types in event properties

* Add test with union types

* Account for ReflectionIntersectionType

---------

Co-authored-by: Chris Morrell <[email protected]>
  • Loading branch information
badger-adam and inxilpro authored Dec 19, 2024
1 parent 86488ab commit 5c2ed3c
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 7 deletions.
38 changes: 31 additions & 7 deletions src/Support/EventStateRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
use InvalidArgumentException;
use ReflectionAttribute;
use ReflectionClass;
use ReflectionIntersectionType;
use ReflectionNamedType;
use ReflectionProperty;
use ReflectionUnionType;
use Thunk\Verbs\Attributes\Autodiscovery\StateDiscoveryAttribute;
use Thunk\Verbs\Event;
use Thunk\Verbs\Lifecycle\StateManager;
Expand All @@ -20,7 +23,7 @@ class EventStateRegistry
protected array $discovered_properties = [];

public function __construct(
protected StateManager $manager
protected StateManager $manager,
) {}

public function getStates(Event $event): StateCollection
Expand Down Expand Up @@ -54,7 +57,7 @@ protected function discoverAndPushState(StateDiscoveryAttribute $attribute, Even
$states = Arr::wrap(
$attribute
->setDiscoveredState($discovered)
->discoverState($target, $this->manager)
->discoverState($target, $this->manager),
);

$discovered->push(...$states);
Expand Down Expand Up @@ -120,17 +123,38 @@ protected function findAllProperties(Event $target): Collection

return collect($reflect->getProperties(ReflectionProperty::IS_PUBLIC))
->filter(function (ReflectionProperty $property) use ($target) {
$propertyType = $property->getType();
$propertyTypeName = $propertyType?->getName();
$property_type = $property->getType();

if ($propertyType->allowsNull() && $property->getValue($target) === null) {
if (
$property_type instanceof ReflectionNamedType
&& $property_type->allowsNull()
&& $property->getValue($target) === null
) {
return false;
}

return $propertyTypeName
&& (is_subclass_of($propertyTypeName, State::class) || $propertyTypeName === State::class || $propertyTypeName === StateCollection::class);
$all_property_types = match ($property_type::class) {
ReflectionUnionType::class, ReflectionIntersectionType::class => $property_type->getTypes(),
default => [$property_type],
};

foreach ($all_property_types as $type) {
$name = $type?->getName();
if ($name && $this->isStateClass($name)) {
return true;
}
}

return false;
})
->map(fn (ReflectionProperty $property) => $property->getValue($target))
->flatten();
}

protected function isStateClass(string $name): bool
{
return is_subclass_of($name, State::class)
|| $name === State::class
|| $name === StateCollection::class;
}
}
32 changes: 32 additions & 0 deletions tests/Unit/UseStatesDirectlyInEventsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,33 @@
$this->assertEquals($event2->id, $user_request2->last_event_id);
});

it('supports union typed properties in events', function() {
$user_request = UserRequestState::new();

UserRequestsWithUnionTypes::commit(
user_request: $user_request,
value: 'foo'
);

$this->assertEquals($user_request->unionTypedValue, 'foo');

UserRequestsWithUnionTypes::commit(
user_request: $user_request,
value: 12
);

$this->assertEquals($user_request->unionTypedValue, 12);
});

class UserRequestState extends State
{
public bool $acknowledged = false;

public bool $processed = false;

public bool $nullable = false;

public string|int $unionTypedValue = '';
}

class UserRequestAcknowledged extends Event
Expand Down Expand Up @@ -149,6 +169,18 @@ public function apply()
}
}

class UserRequestsWithUnionTypes extends Event
{
public function __construct(
public UserRequestState $user_request,
public string|int $value
) {}

public function apply() {
$this->user_request->unionTypedValue = $this->value;
}
}

class ParentState extends State
{
public ChildState $child;
Expand Down

0 comments on commit 5c2ed3c

Please sign in to comment.