Skip to content

Commit

Permalink
Merge pull request #89 from tarfin-labs/WB-675-event-machine-introduc…
Browse files Browse the repository at this point in the history
…e-calculator-behaviors

Wb 675 event machine introduce calculator behaviors
  • Loading branch information
aydinfatih authored Nov 18, 2024
2 parents 2d4f0f1 + f66b5fe commit 424e0cd
Show file tree
Hide file tree
Showing 8 changed files with 498 additions and 16 deletions.
13 changes: 13 additions & 0 deletions src/Behavior/CalculatorBehavior.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Tarfinlabs\EventMachine\Behavior;

/**
* Abstract base class for calculator behaviors.
*
* Calculators are responsible for performing computations and preparing data
* before guards and actions are executed in a transition.
*/
abstract class CalculatorBehavior extends InvokableBehavior {}
34 changes: 30 additions & 4 deletions src/Definition/TransitionBranch.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,19 @@ class TransitionBranch
/** The target state definition for this transition branch, or null if there is no target. */
public ?StateDefinition $target;

/** The calculators to be executed before guards in this transition branch. */
public ?array $calculators = null;

/** The guards to be checked before this transition branch is taken. */
public ?array $guards = null;

/**
* The actions to be performed when this transition branch is taken.
*
* @var null|array<string>
*/
public ?array $actions = null;

/** The guards to be checked before this transition branch is taken. */
public ?array $guards = null;

/** The description of the transition branch. */
public ?string $description = null;

Expand Down Expand Up @@ -95,11 +98,30 @@ public function __construct(

$this->description = $this->transitionBranchConfig['description'] ?? null;

$this->initializeCalculators();
$this->initializeGuards();
$this->initializeActions();
}
}

/**
* Initializes calculator behaviors for the transition branch.
* Handles both inline calculators and calculator class definitions.
*/
protected function initializeCalculators(): void
{
if (isset($this->transitionBranchConfig[BehaviorType::Calculator->value])) {
$this->calculators = is_array($this->transitionBranchConfig[BehaviorType::Calculator->value])
? $this->transitionBranchConfig[BehaviorType::Calculator->value]
: [$this->transitionBranchConfig[BehaviorType::Calculator->value]];

$this->initializeInlineBehaviors(
inlineBehaviors: $this->calculators,
behaviorType: BehaviorType::Calculator
);
}
}

/**
* Initializes the guard/s for this transition.
*/
Expand Down Expand Up @@ -178,7 +200,11 @@ public function runActions(
}

foreach ($this->actions as $actionDefinition) {
$this->transitionDefinition->source->machine->runAction($actionDefinition, $state, $eventBehavior);
$this->transitionDefinition->source->machine->runAction(
$actionDefinition,
$state,
$eventBehavior
);
}
}

Expand Down
62 changes: 62 additions & 0 deletions src/Definition/TransitionDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Tarfinlabs\EventMachine\Definition;

use Throwable;
use Tarfinlabs\EventMachine\Actor\State;
use Tarfinlabs\EventMachine\Enums\BehaviorType;
use Tarfinlabs\EventMachine\Enums\InternalEvent;
Expand Down Expand Up @@ -145,6 +146,10 @@ public function getFirstValidTransitionBranch(
): ?TransitionBranch {
/* @var TransitionBranch $branch */
foreach ($this->branches as $branch) {
if ($this->runCalculators($state, $eventBehavior, $branch) === false) {
return null;
}

if (!isset($branch->guards)) {
return $branch;
}
Expand Down Expand Up @@ -217,5 +222,62 @@ public function getFirstValidTransitionBranch(
return null;
}

/**
* Executes calculator behaviors associated with this transition.
*
* Returns false if any calculator fails, preventing the transition.
*/
public function runCalculators(
State $state,
EventBehavior $eventBehavior,
TransitionBranch $branch,
): bool {
if (!isset($branch->calculators)) {
return true;
}

foreach ($branch->calculators as $calculatorDefinition) {
[$calculatorDefinition, $calculatorArguments] = array_pad(explode(':', $calculatorDefinition, 2), 2, null);
$calculatorArguments = $calculatorArguments === null ? [] : explode(',', $calculatorArguments);

$calculatorBehavior = $this->source->machine->getInvokableBehavior(
behaviorDefinition: $calculatorDefinition,
behaviorType: BehaviorType::Calculator
);

$shouldLog = $calculatorBehavior->shouldLog ?? false;

try {
$calculatorParameters = InvokableBehavior::injectInvokableBehaviorParameters(
actionBehavior: $calculatorBehavior,
state: $state,
eventBehavior: $eventBehavior,
actionArguments: $calculatorArguments,
);

($calculatorBehavior)(...$calculatorParameters);

$state->setInternalEventBehavior(
type: InternalEvent::CALCULATOR_PASS,
placeholder: $calculatorDefinition,
shouldLog: $shouldLog
);
} catch (Throwable $e) {
$state->setInternalEventBehavior(
type: InternalEvent::CALCULATOR_FAIL,
placeholder: $calculatorDefinition,
payload: [
'error' => "Calculator failed: {$e->getMessage()}",
],
shouldLog: $shouldLog
);

return false;
}
}

return true;
}

// endregion
}
23 changes: 13 additions & 10 deletions src/Enums/BehaviorType.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Tarfinlabs\EventMachine\Behavior\GuardBehavior;
use Tarfinlabs\EventMachine\Behavior\ActionBehavior;
use Tarfinlabs\EventMachine\Behavior\ResultBehavior;
use Tarfinlabs\EventMachine\Behavior\CalculatorBehavior;

/**
* Class BehaviorType.
Expand All @@ -17,11 +18,12 @@
*/
enum BehaviorType: string
{
case Guard = 'guards';
case Action = 'actions';
case Result = 'results';
case Event = 'events';
case Context = 'context';
case Calculator = 'calculators';
case Guard = 'guards';
case Action = 'actions';
case Result = 'results';
case Event = 'events';
case Context = 'context';

/**
* Returns the behavior class based on the current value of $this.
Expand All @@ -31,11 +33,12 @@ enum BehaviorType: string
public function getBehaviorClass(): string
{
return match ($this) {
self::Guard => GuardBehavior::class,
self::Action => ActionBehavior::class,
self::Result => ResultBehavior::class,
self::Event => EventBehavior::class,
self::Context => ContextManager::class,
self::Calculator => CalculatorBehavior::class,
self::Guard => GuardBehavior::class,
self::Action => ActionBehavior::class,
self::Result => ResultBehavior::class,
self::Event => EventBehavior::class,
self::Context => ContextManager::class,
};
}
}
8 changes: 6 additions & 2 deletions src/Enums/InternalEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ enum InternalEvent: string

case ACTION_START = '{machine}.action.{placeholder}.start';
case ACTION_FINISH = '{machine}.action.{placeholder}.finish';
case GUARD_PASS = '{machine}.guard.{placeholder}.pass';
case GUARD_FAIL = '{machine}.guard.{placeholder}.fail';

case GUARD_PASS = '{machine}.guard.{placeholder}.pass';
case GUARD_FAIL = '{machine}.guard.{placeholder}.fail';

case CALCULATOR_PASS = '{machine}.calculator.{placeholder}.pass';
case CALCULATOR_FAIL = '{machine}.calculator.{placeholder}.fail';

case EVENT_RAISED = '{machine}.event.{placeholder}.raised';

Expand Down
Loading

0 comments on commit 424e0cd

Please sign in to comment.