yolenoyer
yolenoyer

Reputation: 9465

How to override a Symfony vendor workflow in order to remove some transitions and places

I want to customize (or fully override if needed) some Symfony workflows which are defined in a vendor package.

With the Symfony configuration merging strategy, it's easy to add some workflow places, transitions, etc... But is it possible to remove them? The most important is to be able to remove transitions, as unreachable places are not a problem.

Example

Let's say we have this vendor workflow:

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

Then how is it possible to:

Which would result to this config:

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

What I tried

I tried to add a compiler pass to mutate the unmerged Symfony config of the framework extension, by removing all the $frameworkConfig['workflows']['vendor_workflow'] keys, but the container builder does not allow to mutate the unmerged config (it only allows to prepend configs with $container->prependExtensionConfig())

Context

The vendor is Sylius 1.13, by using the Symfony workflow adapter, and I'm trying to simplify the sylius_order_checkout workflow by removing everything related to shipping:

Upvotes: 0

Views: 93

Answers (1)

Prometee
Prometee

Reputation: 86

Using a CompilerPass, you can redefine every states or transition by doing this:

<?php

declare(strict_types=1);

namespace App\DependencyInjection\Compiler;

use Sylius\Component\Core\OrderCheckoutStates;
use Sylius\Component\Core\OrderCheckoutTransitions;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class SyliusOrderCheckoutStateMachineCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container): void
    {
        $graph = OrderCheckoutTransitions::GRAPH;
        $addressTransition = OrderCheckoutTransitions::TRANSITION_ADDRESS;

        // Override the symfony/workflow to reduce the transitions on "addressed" transition from "address" and "cart"
        $definition = $container->getDefinition(sprintf('state_machine.%s.definition', $graph));
        /** @var Reference[] $transitionReferences */
        $transitionReferences = $definition->getArgument(1);

        $this->removeTransitionForState(
            OrderCheckoutStates::STATE_ADDRESSED,
            $container,
            $transitionReferences,
            $graph,
            $addressTransition,
        );
        $this->removeTransitionForState(
            OrderCheckoutStates::STATE_CART,
            $container,
            $transitionReferences,
            $graph,
            $addressTransition,
        );

        $definition->replaceArgument(1, $transitionReferences);
    }

    protected function removeTransitionForState(
        string $targetedState,
        ContainerBuilder $container,
        array &$transitionReferences,
        string $graph,
        string $transition,
    ): void {
        $indexFound = null;
        foreach ($transitionReferences as $i => $transitionReference) {
            $transitionReference = $container->getDefinition((string) $transitionReference);
            if ($transition !== $transitionReference->getArgument(0)) {
                continue;
            }

            if ($targetedState !== $transitionReference->getArgument(1)) {
                continue;
            }

            $indexFound = $i;
        }

        if (null === $indexFound) {
            throw new \LogicException(
                sprintf(
                    'Unable to locate the state "%s" into the transition of "%s:%s".',
                    $targetedState,
                    $graph,
                    $transition,
                ),
            );
        }

        unset($transitionReferences[$indexFound]);
    }
}

Upvotes: 1

Related Questions