robertripoll/automatic-finite-state-machine

基于 Symfony Workflows 的基本有限状态机。它允许创建和使用自动有限状态机,即它们根据当前状态和可用的转换来应用转换。

0.0.1 2022-05-08 20:56 UTC

This package is auto-updated.

Last update: 2024-09-09 02:08:44 UTC


README

基于 Symfony Workflows 的基本 PHP 有限状态机。

它允许创建和使用自动有限状态机,即它们根据当前状态和可用的转换来应用转换。

安装

$ composer require robertripoll/automatic-finite-state-machine

使用方法

传统有限状态机

<?php

use RobertRipoll\Definition;
use RobertRipoll\FiniteStateMachine;
use RobertRipoll\State;
use RobertRipoll\StateStoreInterface;
use RobertRipoll\Transition;

// The subject on which to store the finite machine's current status
$order = new stdClass();
$order->id = 123;
$order->status = null;

// The possible finite machine statuses/nodes
$states = [
  $initialState = new State(0, 'creation'),
  $paidState = new State(1, 'paid'),
  $preparingState = new State(2, 'preparing'),
  $shippedState = new State(3, 'shipped'),
];

// The transitions between the possible finite machine nodes
$transitions = [
  new Transition($initialState, $paidState, 'pay'),
  new Transition($paidState, $preparingState, 'prepare', fn (object $order) => $paymentService->isPaid($order->id)),
  new Transition($preparingState, $shippedState, 'ship'),
];

// The definition of the finite machine
$definition = new Definition($states, $initialState, $transitions);

// The logic behind the retrieval and storage of the state
$stateStore = new class () implements StateStoreInterface {
  public function getState(object $subject) {
    return $subject->status;
  }

  public function setState(object $subject, $newState): void {
    $subject->status = $newState;
  }
};

$stateMachine = new FiniteStateMachine($definition, $order, $stateStore, null, 'Traditional finite state machine');

if ($stateMachine->can('prepare')) {
  $stateMachine->apply('prepare');
}

自动有限状态机

<?php

use RobertRipoll\AutomaticFiniteStateMachine;
use RobertRipoll\Definition;
use RobertRipoll\Events\FiniteStateMachineEventInterface;
use RobertRipoll\Events\StateChangedEvent;
use RobertRipoll\State;
use RobertRipoll\StateStoreInterface;
use RobertRipoll\Transition;

// The subject on which to store the finite machine's current status
$order = new stdClass();
$order->id = 123;
$order->status = null;

// The possible finite machine statuses/nodes
$states = [
  $initialState = new State(0, 'created'),
  $paidState = new State(1, 'paid'),
  $preparingState = new State(2, 'preparing'),
  $shippedState = new State(3, 'shipped'),
];

// The transitions between the possible finite machine nodes
$transitions = [
  new Transition($initialState, $paidState, 'pay', fn (object $order) => $paymentService->isPaid($order->id)),
  new Transition($paidState, $preparingState, 'prepare'),
  new Transition($preparingState, $shippedState, 'ship', fn (object $order) => $shipmentService->isShipped($order->id)),
];

// The definition of the finite machine
$definition = new Definition($states, $initialState, $transitions);

// The logic behind the retrieval and storage of the state
$stateStore = new class () implements StateStoreInterface {
  public function getState(object $subject) {
    return $subject->status;
  }

  public function setState(object $subject, $newState): void {
    $subject->status = $newState;
  }
};

$eventDispatcher = new class ($logService) implements EventDispatcherInterface {
  private LogService $logService;

  public function __construct(LogService $logService) {
    $this->logService = $logService;
  }

  public function dispatch(object $event)
  {
    /** @var FiniteStateMachineEventInterface $event */

    if ($event->getEventName() == StateChangedEvent::EVENT_NAME)
    {
      /** @var StateChangedEvent $event */
      $oldState = $event->hasOldState() ? $event->getOldState()->getValue() : 'null';
      $logService->log("Subject state changed from $oldState to {$event->getNewState()->getValue()}");
    }
  }
};

$stateMachine = new AutomaticFiniteStateMachine($definition, $order, $stateStore, $eventDispatcher, 'Automatic finite state machine');
$stateMachine->run();