如何覆盖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
相关产品推荐
相关产品推荐

