Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 50 additions & 23 deletions src/EntityContext.php
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,9 +41,11 @@
use Bottledcode\DurablePhp\Events\WithOrchestration;
use Bottledcode\DurablePhp\Exceptions\Unwind;
use Bottledcode\DurablePhp\Glue\Provenance;
use Bottledcode\DurablePhp\Proxy\SpyException;
use Bottledcode\DurablePhp\Proxy\SpyProxy;
use Bottledcode\DurablePhp\State\EntityHistory;
use Bottledcode\DurablePhp\State\EntityId;
use Bottledcode\DurablePhp\State\EntityState;
use Bottledcode\DurablePhp\State\Ids\StateId;
use Closure;
use Crell\Serde\Attributes\ClassSettings;
Expand DownExpand Up@@ -111,29 +113,6 @@ public function setState(mixed $value): void
$this->state = $value;
}

public function signalEntity(
EntityId $entityId,
string $operation,
array $input = [],
?DateTimeImmutable $scheduledTime = null,
): void {
$event = $this->addFrom(
WithEntity::forInstance(
StateId::fromEntityId($entityId),
RaiseEvent::forOperation($operation, $input),
),
);
if ($scheduledTime) {
$event = WithDelay::forEvent($scheduledTime, $event);
}
$this->eventDispatcher->fire($event);
}

private function addFrom(Event $event): Event
{
return WithFrom::forEvent($this->from, $event);
}

public function getId(): EntityId
{
return $this->id;
Expand DownExpand Up@@ -161,6 +140,11 @@ public function startNewOrchestration(string $orchestration, array $input = [],
);
}

private function addFrom(Event $event): Event
{
return WithFrom::forEvent($this->from, $event);
}

public function delay(Closure $self, DateTimeInterface $until = new DateTimeImmutable()): void
{
$classReflector = new ReflectionClass($this->history->getState());
Expand DownExpand Up@@ -283,4 +267,47 @@ public function revokeRole(string $role): void
),
);
}

public function signal(EntityId $entityId, callable $signal): void
{
$proxy = $this->spyProxy->define($entityId->name);
$operationName = null;
$arguments = null;
$proxy = new $proxy($operationName, $arguments);
try {
$proxy($signal);

if ($operationName === null || $arguments === null) {
return;
}
} catch (SpyException) {
$this->signalEntity($entityId, $operationName, $arguments ?? []);
}
}

public function signalEntity(
EntityId $entityId,
string $operation,
array $input = [],
?DateTimeImmutable $scheduledTime = null,
): void {
$event = $this->addFrom(
WithEntity::forInstance(
StateId::fromEntityId($entityId),
RaiseEvent::forOperation($operation, $input),
),
);
if ($scheduledTime) {
$event = WithDelay::forEvent($scheduledTime, $event);
}
$this->eventDispatcher->fire($event);
}

public function getSnapshot(EntityId $entityId): EntityState
{
$state = $this->eventDispatcher->getState(StateId::fromEntityId($entityId));
assert($state instanceof EntityHistory);

return $state->getState();
}
}
21 changes: 21 additions & 0 deletions src/EntityContextInterface.php
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@

use Bottledcode\DurablePhp\Events\Shares\Operation;
use Bottledcode\DurablePhp\State\EntityId;
use Bottledcode\DurablePhp\State\EntityState;
use Closure;
use Crell\Serde\Attributes\ClassNameTypeMap;
use DateTimeImmutable;
Expand DownExpand Up@@ -102,6 +103,26 @@ public function getId(): EntityId;
*/
public function getOperation(): string;

/**
* Call the entity with a single signal
*
* @template T of EntityState
*
* @param EntityId<T> $entityId
* @param callable(T): void $signal
*/
public function signal(EntityId $entityId, callable $signal): void;

/**
* Retrieve a snapshot of the remote entity state
*
* @template T of EntityState
*
* @param EntityId<T> $entityId
* @return EntityState<T>
*/
public function getSnapshot(EntityId $entityId): EntityState;

public function startNewOrchestration(string $orchestration, array $input = [], ?string $id = null): void;

public function delayUntil(
Expand Down
13 changes: 11 additions & 2 deletions src/Proxy/Generator.php
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,8 +34,13 @@

abstract class Generator
{
public function __construct(protected string|null $cacheDir = null) {}
public function __construct(protected ?string $cacheDir = null) {}

/**
* Ensures that the given interface is implemented
*
* @throws \ReflectionException
*/
public function define(string $interface): string
{
$name = $this->getName($class = new ReflectionClass($interface));
Expand All@@ -45,14 +50,15 @@ public function define(string $interface): string
$cacheFile = $this->cacheDir . DIRECTORY_SEPARATOR . $name . '.php';
if (file_exists($cacheFile)) {
require_once $cacheFile;

return '\\' . $namespace . '\\' . $name;
}
}

$reflection = new ReflectionClass($interface);
$fullname = $this->getInterfaceNamespace($reflection) . '\\' . $this->getName($reflection);

if (!class_exists($fullname)) {
if (!class_exists($fullname)) {
eval($output = $this->generate($interface));
if ($cacheFile) {
file_put_contents($cacheFile, "<?php\n{$output}");
Expand DownExpand Up@@ -106,6 +112,7 @@ function (ReflectionMethod $method) {
$hooks[] = $this->pureMethod($hook, true);
}
$hooks[] = '}';

return implode(
"\n",
array_filter(
Expand All@@ -115,6 +122,7 @@ function (ReflectionMethod $method) {
);
}, $props);
$props = implode("\n", $props);

return <<<EOT
{$namespace}

Expand All@@ -139,6 +147,7 @@ protected function getTypes(ReflectionIntersectionType|ReflectionNamedType|Refle
if ($type->isBuiltin()) {
return $nullable . $type->getName();
}

return $nullable . '\\' . $type->getName();
}

Expand Down
5 changes: 4 additions & 1 deletion src/State/EntityId.php
Original file line numberDiff line numberDiff line change
Expand Up@@ -28,10 +28,13 @@
use Withinboredom\Record;

/**
* @template T
* @template T of EntityState
*/
readonly class EntityId extends Record implements Stringable
{
/**
* @var class-string<T>
*/
public protected(set) string $name;

public protected(set) string $id;
Expand Down