Search code examples
phpsymfonydependency-injectionsymfony-workflows

Add workflow to a service dynamically in Symfony 6.3


The Symfony 6.3 docs state concerning the workflow registry:

Beware that injecting the Registry into your services is not recommended.

However, I need to get a specific workflow within a service method which decides which workflow to use based on a key. I don't know in advance which workflow to load, so I can't inject a specific workflow. How can I do this? For now, I inject the registry. Could I somehow inject the service_container and get it from there later?


Solution

  • For Symfony 6.4 +

    This works around what is probably a bug, namely that when you load a Workflow with a serviceLocator, it's key will be prefixed with 'debug.' and the returned type is TraceableWorkflow. You can adjust this to your environment needs.

    use Symfony\Component\HttpKernel\KernelInterface;
    use Psr\Container\ContainerExceptionInterface;
    use Psr\Container\ContainerInterface;
    use Psr\Container\NotFoundExceptionInterface;
    use RuntimeException;
    use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
    use Symfony\Component\Workflow\WorkflowInterface;
    
    class WorkflowLoader
    {
        public function __construct(
            private readonly KernelInterface $kernel,
            #[TaggedLocator('workflow')] private readonly ContainerInterface $serviceLocator
        )
        {
        }
    
        public function getWorkflow($workflowName): WorkflowInterface
        {
            $prefix = '';
            if ($this->kernel->isDebug()) {
                $prefix = 'debug.';
            }
            try {
                if (!$workflow = $this->serviceLocator->get($prefix . 'state_machine.' . $workflowName)) {
                    $workflow = $this->serviceLocator->get($prefix . 'workflow.' . $workflowName);
                }
            } catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
                throw new RuntimeException("Process Workflow $workflowName could not be loaded." . PHP_EOL . $e->getMessage());
            }
            return $workflow;
        }
    }