dflydev/finite-state-machine

又一种有限状态机实现

dev-master / 0.0.x-dev 2020-04-17 06:12 UTC

This package is auto-updated.

Last update: 2024-09-19 04:47:48 UTC


README

这个库是另一个有限状态机的实现。

Build Status Scrutinizer Code Quality Code Coverage Code Climate

安装

composer require dflydev/finite-state-machine

用法

给定以下领域类的定义

class DomainObject
{
    public string $state;
    public ?string $spy = null;

    public function __construct(string $state = 'new')
    {
        $this->state = $state;
    }
}

给定以下领域对象 "graphA" 图的状态定义

$domainObjectGraphDefinition = [
   'class' => DomainObject::class,
   'graph' => 'graphA', // default is "default"
   'property_path' => 'state', // Configures `PropertyObjectProxy`
   'metadata' => [
       'title' => 'Graph A',
   ],
   'states' => [
       // a state as associative array
       ['name' => 'new'],
       // a state as associative array with metadata
       [
           'name' => 'pending_review',
           'metadata' => ['title' => 'Pending Review'],
       ],
       // states as string
       'awaiting_changes',
       'accepted',
       'published',
       'rejected',
   ],

   // list of all possible transitions
   'transitions' => [
       'create' => [
           'from' => ['new'],
           'to' => 'pending_review',
       ],
       'ask_for_changes' => [
           'from' =>  ['pending_review', 'accepted'],
           'to' => 'awaiting_changes',
           'metadata' => ['title' => 'Ask for changes'],
       ],
       'cancel_changes' => [
           'from' => ['awaiting_changes'],
           'to' => 'pending_review',
       ],
       'submit_changes' => [
           'from' => ['awaiting_changes'],
           'to' =>  'pending_review',
       ],
       'approve' => [
           'from' => ['pending_review', 'rejected'],
           'to' =>  'accepted',
       ],
       'publish' => [
           'from' => ['accepted'],
           'to' =>  'published',
       ],
   ],

   // list of all callbacks
   'callbacks' => [
       // will be called when testing a transition
       'guard' => [
           'guard_on_approving_from_rejected' => [
               // call the callback on a specific transition
               'on' => 'approve',
               'from' => 'rejected',
               // will call the method of this class
               'do' => function (
                   object $object,
                   Transition $transition,
                   State $fromState,
                   State $toState
               ) {
                   $object->spy = 'guard_on_approving_from_rejected';

                   // If a guard returns false, the transition will not happen
                   return false;
               },
               // arguments for the callback
               'args' => ['object'],
           ],
       ],

       // will be called before applying a transition
       'before' => [
           'spy-before-approve' => [
               'on' => 'ask_for_changes',
               'from' => 'accepted',
               'do' => function (
                   string $when,
                   object $object,
                   Transition $transition,
                   State $fromState,
                   State $toState
               ) {
                   Assert::equals($fromState->name(), $object->state);

                   $object->spy = $when . ' ask_for_changes from accepted';
               },
           ]
       ],

       // will be called after applying a transition
       'after' => [
           'spy-after-approve' => [
               'on' => 'ask_for_changes',
               'from' => 'accepted',
               'do' => function (
                   string $when,
                   object $object,
                   Transition $transition,
                   State $fromState,
                   State $toState
               ) {
                   Assert::equals($toState->name(), $object->state);
                   Assert::equals('before ask_for_changes from accepted', $object->spy);

                   $object->spy = $when . ' ask_for_changes from accepted';
               },
           ]
       ],
   ]        
];
use Dflydev\FiniteStateMachine\FiniteStateMachineFactory;
use Dflydev\FiniteStateMachine\Graph\GraphResolver;
use Dflydev\FiniteStateMachine\Loader\WinzouArrayLoader;
use Dflydev\FiniteStateMachine\ObjectProxy\ObjectProxyResolver;
use Dflydev\FiniteStateMachine\ObjectProxy\PropertyObjectProxyFactory;

$graphResolver = new GraphResolver();
$objectProxyResolver = new ObjectProxyResolver();

// Add an object proxy that can directly read the state property from our objects
$objectProxyResolver->add(new PropertyObjectProxyFactory());

// Load a graph definition into our graph resolver
(new WinzouArrayLoader($graphResolver))->load($domainObjectGraphDefinition);

$finiteStateMachineFactory = new FiniteStateMachineFactory(
    $this->getGraphResolver(),
    $this->getObjectProxyResolver()
);

$finiteStateMachine = $finiteStateMachineFactory->build($object);

// "new"
$finiteStateMachine->currentState()->name();

// (bool) false
$finiteStateMachine->can('ask_for_changes');

// (bool) true
$finiteStateMachine->can('create');

$finiteStateMachine->apply('create');

// "pending_review"
$finiteStateMachine->currentState()->name();

图定义和加载器

图是由状态、转换和回调组成的命名集合。一个对象可以定义多个图。

GraphResolver 负责解析给定对象(和可选的图名)的图定义。

可以手动创建 Graph 并将其添加到 GraphResolver 中。可以使用 Loader 根据特定的资源类型将 Graph 加载到 GraphResolver 中。

winzou/state-machine

此库附带 WinzouArrayLoader,这是一个与 winzou/state-machine 数组图定义松散兼容的 Loader 实现。

自定义

此库附带一个 Loader 合同。实现此接口允许创建自定义图定义。

许可证

MIT,见 LICENSE