You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何覆盖Symfony Vendor工作流以移除指定转换与节点?

如何自定义/移除Symfony Workflow中供应商包定义的元素

我需要自定义(必要时完全覆盖)供应商包中定义的部分Symfony Workflow。Symfony的配置合并策略很容易添加places、transitions这类元素,但能不能移除这些元素?最核心的需求是实现transitions的移除,不可达的places暂时不影响。

示例

假设供应商提供了如下Workflow配置:

framework:
    workflows:
        vendor_workflow:
            # ...
            places:
                - one
                - two
                - three
            transitions:
                to_two:
                    from: [one]
                    to: two
                to_three:
                    from: [one, two]
                    to: three

需要完成以下操作:

  • 移除转换to_two;
  • 移除转换to_three中的from: one;
  • 移除节点one;

最终得到的配置如下:

framework:
    workflows:
        vendor_workflow:
            # ...
            places:
                - two
                - three
            transitions:
                to_three:
                    from: [two]
                    to: three

已尝试方案

我曾尝试添加compiler pass来修改framework扩展的未合并Symfony配置,移除$frameworkConfig['workflows']['vendor_workflow']下的所有相关键,但容器构建器不允许修改未合并配置,仅支持通过$container->prependExtensionConfig()添加前置配置。

上下文

使用的供应商为Sylius 1.13,其基于Symfony workflow适配器实现功能,我正尝试简化sylius_order_checkout工作流,移除所有与配送相关的内容:

  • 节点shipping_selected和shipping_skipped;
  • 转换skip_shipping和select_shipping。

解决方案

方法1:通用Symfony方案——用Compiler Pass修改Workflow定义

Symfony的Workflow最终会转化为Symfony\Component\Workflow\Definition实例,我们可以在容器编译阶段直接修改这个实例:

步骤1:创建自定义Compiler Pass

namespace App\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Workflow\Definition;
use Symfony\Component\Workflow\Transition;

class ModifyVendorWorkflowPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container): void
    {
        // 替换为目标Workflow的服务ID,格式为workflow.<workflow_name>
        // Sylius订单checkout工作流的ID是workflow.sylius_order_checkout
        $workflowServiceId = 'workflow.vendor_workflow';

        if (!$container->hasDefinition($workflowServiceId)) {
            return;
        }

        $definition = $container->getDefinition($workflowServiceId);
        // 替换工厂方法为自定义的修改逻辑
        $definition->setFactory([$this, 'createModifiedWorkflowDefinition']);
        $definition->setArguments($definition->getArguments());
    }

    public function createModifiedWorkflowDefinition(Definition $originalDefinition): Definition
    {
        // 1. 移除指定节点
        $places = array_filter($originalDefinition->getPlaces(), function (string $place) {
            // 这里替换成你要移除的节点
            return !in_array($place, ['one', 'shipping_selected', 'shipping_skipped']);
        });

        // 2. 处理转换:移除指定转换,修改现有转换的from列表
        $transitions = [];
        foreach ($originalDefinition->getTransitions() as $transition) {
            // 移除不需要的转换
            if (in_array($transition->getName(), ['to_two', 'skip_shipping', 'select_shipping'])) {
                continue;
            }

            // 修改目标转换的from列表(示例:修改to_three)
            if ($transition->getName() === 'to_three') {
                $newFrom = array_filter($transition->getFroms(), function (string $place) {
                    return $place !== 'one';
                });
                $modifiedTransition = new Transition(
                    $transition->getName(),
                    $newFrom,
                    $transition->getTos()
                );
                $transitions[] = $modifiedTransition;
                continue;
            }

            $transitions[] = $transition;
        }

        return new Definition($places, $transitions);
    }
}

步骤2:注册Compiler Pass

在你的Bundle类中添加注册逻辑:

namespace App;

use App\DependencyInjection\Compiler\ModifyVendorWorkflowPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class AppBundle extends Bundle
{
    public function build(ContainerBuilder $container): void
    {
        parent::build($container);
        $container->addCompilerPass(new ModifyVendorWorkflowPass());
    }
}

方法2:Sylius专属方案——装饰WorkflowRegistry服务

Sylius通过Sylius\Bundle\CoreBundle\Workflow\WorkflowRegistry管理工作流,装饰这个服务可以更优雅地修改订单checkout工作流:

步骤1:创建装饰类

namespace App\Workflow;

use Sylius\Bundle\CoreBundle\Workflow\WorkflowRegistryInterface;
use Symfony\Component\Workflow\Definition;
use Symfony\Component\Workflow\Transition;

class ModifiedWorkflowRegistry implements WorkflowRegistryInterface
{
    public function __construct(private WorkflowRegistryInterface $decorated) {}

    public function get(string $name): Definition
    {
        $definition = $this->decorated->get($name);

        // 只修改sylius_order_checkout工作流
        if ($name !== 'sylius_order_checkout') {
            return $definition;
        }

        // 移除配送相关节点
        $places = array_filter($definition->getPlaces(), function (string $place) {
            return !in_array($place, ['shipping_selected', 'shipping_skipped']);
        });

        // 移除配送相关转换,并清理其他转换的from列表
        $transitions = [];
        foreach ($definition->getTransitions() as $transition) {
            if (in_array($transition->getName(), ['skip_shipping', 'select_shipping'])) {
                continue;
            }

            // 清理转换中指向已移除节点的from项
            $newFrom = array_filter($transition->getFroms(), function (string $place) {
                return !in_array($place, ['shipping_selected', 'shipping_skipped']);
            });
            $modifiedTransition = new Transition(
                $transition->getName(),
                $newFrom,
                $transition->getTos()
            );
            $transitions[] = $modifiedTransition;
        }

        return new Definition($places, $transitions);
    }
}

步骤2:配置服务装饰

在config/services.yaml中添加:

services:
    App\Workflow\ModifiedWorkflowRegistry:
        decorates: Sylius\Bundle\CoreBundle\Workflow\WorkflowRegistryInterface
        arguments: ['@.inner']

注意事项

  • 确认Workflow服务ID的正确性:Symfony默认格式为workflow.<workflow_name>,Sylius订单checkout工作流ID是workflow.sylius_order_checkout
  • 修改后要验证所有转换的from/to都指向存在的节点,避免无效转换
  • Sylius场景优先使用方法2,更符合其扩展规范,维护性更强

内容的提问来源于stack exchange,提问作者yolenoyer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 23:49:52