gtt/workflow-extensions-bundle

扩展工作流管理和自动化的组件包

2.0.0-RC1 2016-12-05 16:59 UTC

This package is auto-updated.

Last update: 2024-09-08 00:44:53 UTC


README

Build Status Coverage Status Scrutinizer Code Quality Latest Stable Version Latest Unstable Version License

原始Symfony 3 工作流组件 和整合到Symfony生态系统中的部分 Symfony的FrameworkBundle,明确声明所有事物作为主要概念。这意味着,如果您需要应用工作流转换,必须在业务逻辑代码中找到目标工作流对象并调用 $workflow->apply()。另一个例子:如果您想阻止转换,必须创建一个订阅GuardEvent的监听器,并决定是否在内部阻止或允许转换。

但是,有时工作流过程很复杂,处理转换管理的代码增长很快。

WorkflowExtensionsBundle为原始Symfony 3工作流组件提供了扩展和附加功能,可以帮助您在处理工作流组件时自动化一些手动操作

  1. 基于事件的转换触发

  2. 基于事件的转换调度

  3. 可配置的转换阻止

要求

由于Symfony的工作流组件需要PHP 5.5.9+,因此WorkflowExtensionsBundle支持PHP 5.5.9及更高版本。

工作流组件从3.2版本开始集成到Symfony 3生态系统中。要在基于Symfony 3.1和更低版本的程序中使用它,您可以使用1.x版本的组件包

除了symfony/framework-bundlesymfony/expression-language包外,还需要其他包。

安装

应通过composer安装组件包

composer require gtt/workflow-extensions-bundle

之后,您需要在应用程序的内核中注册该组件包

public function registerBundles()
{
    $bundles = array(
        // ...
        new \Gtt\Bundle\WorkflowExtensionsBundle\WorkflowExtensionsBundle(),
    );
}

配置和使用

工作流主题

首先,您需要告诉WorkflowExtensionsBundle您想要它处理哪种类型的工作流主题。在subject_manipulator部分中列出。

workflow_extensions:
    subject_manipulator:
        My\Bundle\Entity\Order: ~
        My\Bundle\Entity\Claim: ~

日志记录

由于WorkflowExtensionsBundle所做的所有事情基本上都是自动化的(甚至是异步的),因此记录重要方面的详细日志是合理的。所有WorkflowExtensionsBundle子系统日志(在可能的情况下)在执行过程中记录工作流名称、主题类和主题ID。

这里有一个非平凡的问题:如何从主题中检索主题ID。通常,可以通过调用getId()方法来获取主题ID,在这种情况下,您无需做任何事情。否则(当您的主题类没有getId()方法或应使用其他方法来获取主题标识符时),您需要指定表达式来获取主题标识符。此表达式将由ExpressionLanguage组件使用代表主题对象的subject变量进行评估

workflow_extensions:
    subject_manipulator:
        My\Bundle\Entity\Order: ~
        My\Bundle\Entity\Claim:
            id_from_subject: 'subject.getCustomId()'

基于事件的转换处理

WorkflowExtensionsBundle最重要的用例之一是将某些工作流操作作为对特定系统事件的响应来执行。任何Symfony事件实例都可以扮演这种触发事件的角色。要订阅将工作流处理订阅到此类事件,您应该从以下配置开始

workflow_extensions:
    workflows:
        simple:
            triggers:
                event:
                    some.event:
                        ...
                    another.event:
                        ... 
        complex:
            triggers:
                event:
                    some.event:
                        ...
                    third.event:
                        ...
    ...                

此配置首先指定目标工作流名称(simple),它应等于symfony/framework-bundle或fduch/workflow-bundle配置中定义的工作流之一。然后,对于每个工作流,您定义目标事件并配置如下各节所述的处理细节。

基于事件的转换触发

WorkflowExtensionsBundle允许在特定事件触发时触发工作流转换。例如,如果您想在工作流主体(My\Bundle\Entity\Order实例)创建时触发转换to_processing(order_created.event事件触发),则WorkflowExtensionsBundle的配置可能如下所示

workflow_extensions:
    workflows:
        simple:
            triggers:
                event:
                    order_created.event:
                        actions:
                            apply_transition:
                                - [to_processing]
                        subject_retrieving_expression: 'event.getOrder()'
    subject_manipulator:
        My\Bundle\Entity\Order: ~

在上面的示例中,subject_retrieving_expression部分包含用于检索工作流主体的表达式(它将由ExpressionLanguage评估)。由于评估这些表达式的表达式语言启用了容器变量(表示DI容器),因此您可以构建更复杂的东西,例如以下内容:"container.get('doctrine').getEntityMangerForClass('My\\\\Bundle\\\\Entity\\\\Order').find('My\\\\Bundle\\\\Entity\\\\Order', event.getId())"(由于表达式语言语法的特殊性,设置了大量的反斜杠)。

您还可以使用apply_transitions构造指定在事件触发时尝试执行的一个以上的转换

    apply_transitions:
        - [[to_processing, closing]]

在这种情况下(默认情况下),将应用第一个适用的转换。您还可以连续尝试应用几个转换,而不会在第一个成功应用的转换后中断执行,使用在行中多次调用apply_transition操作并使用不同参数的能力

   apply_transition:
       - [to_processing]
       - [closing]

基于事件的转换调度

事件不仅可以用于立即应用转换,还可以使用指定的偏移量进行安排。WorkflowExtensionsBundle使用jms/job-queue-bundle作为调度引擎。想象一下,如果您需要应用转换set_problematic,该转换将工作流主体Order放置到“有问题”状态,如果它在30天内没有正确处理。可以使用以下配置实现此目标

workflow_extensions:
    workflows:
        simple:
            triggers:
                event:
                    order_created.event:
                        schedule:
                            apply_transition:
                                -
                                    arguments: [closing]
                                    offset: P30D
                        subject_retrieving_expression: 'event.getOrder()'
    scheduler: ~                
    subject_manipulator:
        My\Bundle\Entity\Order:
            subject_from_domain: "container.get('doctrine').getManagerForClass(subjectClass).find(subjectClass, subjectId)"
    context:
        doctrine: ~

上述配置与之前的配置类似,但有几个差异。

第一个差异是,将actions替换为schedule键,以告知引擎以下操作应被延迟执行。

第二个差异是,现在在每个操作的参数定义在显式的arguments键下(由于配置规范化规则,它会在简单触发时自动设置),以及offset键,它定义了从触发事件发生的时刻开始的时间间隔(根据ISO-8601),然后在此之后应用计划中的转换。

第三个差异是,您需要配置scheduler部分以激活调度引擎。它还可以用于设置特定的实体管理器以持久化调度作业。

第四个差异是,您必须在subject_manipulatorsubject_from_domain键下配置表达式(它将由ExpressionLanguage评估),该表达式将用于在计划中的转换尝试应用时检索工作流主体。这里的主类(例如My\Bundle\Entity\Order)和主键(即用于检索对象的标识符)是表达式变量。此外,您还可以在这里再次使用DI容器,因为它也注册为表达式变量。

此处的另一个功能是,如果您有频繁的重复事件,会触发状态转换,那么在事件首次触发时,转换将被简单调度,后续事件发生时将重置计时器,从当前时刻重新启动。当您需要连续延迟特定转换,直到特定事件定期触发时,此行为非常有用。您无需配置任何特定设置,因为此功能默认启用。

转换阻塞

基本上,您可以通过监听特殊的GuardEvent并在其内部调用setBlocked方法来显式地阻止转换。借助WorkflowExtensionsBundle,您可以再次自动化这些操作。例如,如果您想阻止所有由非ROLE_USER用户触发的转换,并允许只有管理者(ROLE_MANAGER持有者)应用dangerous转换,则应使用如下配置

workflow_extensions:
    workflows:
        simple:
            guard:
                expression: 'not container.get("access_checker").isGranted("ROLE_USER")'
                transitions:
                    dangerous: 'not container.get("access_checker").isGranted("ROLE_MANAGER")'
    subject_manipulator:
        My\Bundle\Entity\Order: ~
    context:
        access_checker: ~

请注意,此处我们再次使用由ExpressionLanguage评估的表达式,该表达式通过容器变量代表依赖注入容器,允许使用公共服务来决定是否阻止转换。

上下文

当表达式使用某些容器服务时,它将使用container.get()方法从容器中检索。由于Symfony 4中不能以这种方式从容器中获取私有服务,因此要访问表达式内部所需的服务,必须显式在包配置中公开该服务。这是通过在包配置中的context数组中完成的

workflow_extensions:
  ...
  context:
    # This will expose "doctrine" service from DI under "doctrine" alias inside expression container
    doctrine: ~ 
    
    # This will expose "security.authorization_checker" from DI and make it available under 
    # "auth_checker" alias inside expression container
    auth_checker: 'security.authorization_checker'
    
  workflows:
    simple:
      guard:
        expression: 'not container.get("auth_checker").isGranted("ROLE_USER")'
        transitions:
          dangerous: 'not container.get("auth_checker").isGranted("ROLE_MANAGER")'

测试

WorkflowExtensionsBundle由单元测试和功能测试覆盖。如果您对包的工作方式有疑问,功能测试可以更清楚地说明它的工作原理。