tyhand / workflow-bundle
实验性工作流包
Requires
- doctrine/doctrine-bundle: 1.2.*
- doctrine/orm: >=2.2.3
- symfony/symfony: >=2.3.0
Requires (Dev)
- codeclimate/php-test-reporter: ^0.2.0
- phpunit/phpunit: ^4.8
- satooshi/php-coveralls: ^0.6.1
- sensiolabs/security-checker: ^3.0
- twig/twig: ^1.22
This package is not auto-updated.
Last update: 2024-09-20 10:03:29 UTC
README
这是一个简单的实验性Symfony包,旨在帮助我们管理应用的一些工作流程。不知道最终结果是否满意,但这是它。
要求
Symfony 2.3 或更高版本以及 Doctrine 2.2 或更高版本。
安装
要使用composer安装,请将包添加到您的composer json中。
$ composer require tyhand/workflow-bundle
接下来,通过AppKernel注册该包。
// app/AppKernel.php public function registerBundles() { $bundles = [ // ... new Tyhand\WorkflowBundle\TyHandWorkflowBundle() ]; }
用法
创建工作流实例
要使实体能够作为工作流实例使用,您需要在实体类中实现上下文接口。
use TyHand\WorkflowBundle\Workflow\Context\ContextInterface; class MyEntity implements ContextInterface { //... }
之后,需要实现接口中的方法,或者您可以将TyHand\WorkflowBundle\Workflow\Context\ContextTrait特质添加到实体中来实现接口中的所有方法。添加了接口并实现了方法或添加了特质后,运行Doctrine模式命令以添加工作流表。SQL转储应显示工作流上下文表以及实现上下文接口的每个实体的多对多表。
$ app/console doctrine:schema:update --dump-sql
一旦验证了转储的SQL,就可以通过强制更新或数据库迁移来更新模式。
$ app/console doctrine:schema:update --force
创建工作流
通过创建一个新的工作流定义类来扩展包提供的抽象工作流定义来启动新的工作流。
use TyHand\WorkflowBundle\Workflow\AbstractWorkflowDefinition; use TyHand\WorkflowBundle\Workflow\Builder\WorkflowflowBuilder; class MyWorkflow extends AbstractWorkflowDefinition { //... }
抽象工作流定义有三个抽象方法需要实现。第一个是getName(),它只返回工作流的一个名称。这个名称应该在应用的作用域内是唯一的。第二个方法是getContextClass(),它返回工作流上下文类的名称。
// ... class MyWorkflow extends AbstractWorkflowDefinition { public function getName() { return 'my_workflow'; } public function getContextClass() { return 'AppBundle\MyEntity'; } // ... }
第三个必需的方法是build方法,这是工作流定义的核心。此方法将接收并返回一个工作流构建器,该构建器指定了工作流的架构。
\\... class MyWorkflow extends AbstractWorkflowDefinition { // ... public function build(WorkflowBuilder $builder) { return $builder ->activeLimit(1) // The number of times a single context can be active in the workflow ->totalLimit(1) // The maximum number of times a single context can go through a workflow ->initial('state_a') // The initial state // States follow here // ... ; } }
工作流的主要部分是状态。每个状态都有一个唯一的名称(在工作流的作用域内),一组退出条件,以及一组可选的动作。如果一个状态没有退出条件,则被认为是终止状态,并且一旦工作流实例达到这一点,就不再被认为是活动的。动作是在实例进入工作流时可以调用的方法。退出条件可以是可以在应用的其他地方触发的事件,是一个在实例进入状态时评估的条件语句,以及一个时间限制,如果实例在该状态下停留了足够长的时间,则移动到给定的状态。注意:要使用时间限制条件,需要运行cron作业或类似的东西来定期运行app/console check time limit命令('tyhand_workflow:states:check_time_limit')。
示例
public function build(WorkflowBuilder $builder) { return $builder ->activeLimit(1) // The number of times a single context can be active in the workflow ->totalLimit(1) // The maximum number of times a single context can go through a workflow ->initial('state_a') // The initial state ->startState('state_a') ->addEvent('move_state', 'state_b') // EVENT EXIT (when move_state workflow event is thrown, move to state b) ->end() ->startState('state_b') ->startCondition() // CONDITIONAL EXIT ->conditionalFunction(function ($context) { return 5 < $context->getBar(); }) ->ifTrue('state_c1') // GOTO state_c1 if bar < 5 ->ifFalse('state_c2') // GOTO state_c2 if bar >= 5 ->end() ->end() ->startState('state_c1') ->addAction(function ($context) { // ACTION $context->incrementFoo(); }) ->startCondition() // CONDITIONAL EXIT (with no ifFalse) ->conditionalFunction(function($context) { return 10 === $context->getFoo(); }) ->ifTrue('state_d') ->end() ->startCondition() // CONDITIONS called in order ->conditionalFunction(function($context) { return 2 < $context->getBar(); }) ->ifTrue('state_d') ->end() ->setTimeLimit(3600, 'state_d') // TIME LIMIT EXIT In 3600 second (1 hour) goto state d ->end() ->startState('state_c2') ->addAction(function ($context) { // ACTION $context->decrementFoo(); }) ->addEvent('move_state', 'state_d') // EVENT EXIT goto d if workflow event move state is thrown ->end() ->startState('state_d') // terminal state ->end() ; }
为了使状态动作和条件更有用,只需将各种服务注入到工作流定义中并将它们添加到条件或动作函数中。例如,假设我们想在工作流结束时抛出一个事件,那么只需添加一个类似这样的动作到您的终端状态。
// WORKFLOW BUILDER METHOD // ... ->startState('complete') ->addAction(function ($context) use ($eventDispatcher, $entityManager) { $eventDispatcher->dispatcher( MyObjectEvent::PROCESS_COMPLETE, new MyObjectEvent($entityManager, $context) ); }) ->end()
通过将其作为服务并添加'tyhand_workflow.definition'标签来让工作流管理器知道定义类。示例
services: # ... my_workflow: tags: - { name: tyhand_workflow.definition }
将实例放入工作流中
通过使用工作流管理器服务将上下文放入工作流中。
// Create a new instance at the initial state $instance = $this->get('tyhand_workflow.manager')->getWorkflow('my_workflow')->start($myEntity); // Persist and flush the new instance entity $this->getDoctrine()->getManager()->persist($instance); $this->getDoctrine()->getManager()->flush($instance);
工作流事件
通过抛出一个带有上下文、工作流名称和事件名称的工作流事件来触发事件转换。
$this->get('event_dispatcher')->dispatch( \TyHand\WorkflowBundle\Event\WorkflowEvent::WORKFLOW_EVENT, new \TyHand\WorkflowBundle\Event\WorkflowEvent($myEntity, 'my_workflow', 'my_event') );
测试
PHPUnit 用于测试该包。从包根目录下找到的 phpunit.xml.dist 文件创建一个 phpunit.xml,然后运行 phpunit 进行测试。
许可证
此包受 MIT 许可证 保护