Sylius: Documentation issue: Unable to override statemachine (eg. remove state/transition)

Sylius docs version: 1.10 (though it looks unchanged for the last several versions). Problem was the same on 1.9. With 1.8 it worked.

Edit: provided reproduction that it works in 1.8

Description I am trying to follow the guide for customizing state machines, specifically the part about how to remove a state and its transitions. This links to the cookbook about How to customize Sylius checkout which I am aware is outdated.

I am hoping, that since the possibility of removing states/transitions is hinted in the up-to-date part of the docs, some helpful eyes can take a look at this. Prior to 1.9 this approach seemed to work.

I have provided a repository reproducing the problem. Base commit is sylius/sylius-standard installation. Second commit is adding the src/Resources/SyliusCoreBundle/config/app/state_machine/sylius_order_checkout.yml file (unmodified, verbatim copy of the vendor file). Third commit removes two transitions.

Prior to any modification the output of bin/console debug:config winzou_state_machine sylius_order_checkout looks like this (full dump)

...

transitions:
    address:
        from:
            - cart
            - addressed
            - shipping_selected
            - shipping_skipped
            - payment_selected
            - payment_skipped
        to: addressed
    ...
...

After making changes to the local resource file I expect the output to reflect the changes like this:

...
transitions:
    address:
        from:
            - cart
            - addressed
            - shipping_selected
            - shipping_skipped
        to: addressed
    ...
...

However the two removed transitions ([payment_selected, payment_skipped] -> address) are still there.

This stopped working with 1.9. It worked with 1.8.

I am aware that with 1.9 Symfony was updated to 5.X, and I believe this somehow changed the behaviour of resource overriding, though I can’t find anything about it in release notes. I have tried getting help for this in both the Sylius and Symfony slack channels, but with no luck.

I am hoping someone can help with this (and update the documentation - I’d be happy to help if only I knew what had changed). It is a very important usecase for us to remove states/transitions.

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 3
  • Comments: 21 (9 by maintainers)

Most upvoted comments

For anyone who comes across this issue, needing to completely modify state machines, as described in the docs, here’s how I solved it with a compiler pass. Overriding files can be dumped in <projectDirectory>/state_machine_overrides (or anywhere - just modify the path in the constructor)

<?php

declare(strict_types=1);

namespace App\DependencyInjection\Compiler;

use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\Yaml\Yaml;
use winzou\Bundle\StateMachineBundle\DependencyInjection\Configuration;
use winzou\Bundle\StateMachineBundle\DependencyInjection\winzouStateMachineExtension;

final class AlterStateMachineConfigurationPass implements CompilerPassInterface
{
    private string $overrideFilesDirectory;

    public function __construct(string $projectDir)
    {
        $this->overrideFilesDirectory = $projectDir . '/state_machine_overrides';
    }

    /** @psalm-suppress MixedAssignment, MixedArgument, PossiblyInvalidArgument, MixedArrayOffset */
    public function process(ContainerBuilder $container): void
    {
        /** @var array $configs */
        $configs = $container->getParameter('sm.configs');

        $finder = new Finder();
        $files = $finder->files()->in($this->overrideFilesDirectory);
        if (!$files->hasResults()) {
            return;
        }

        $parameterBag = $container->getParameterBag();
        $processor = new Processor();
        $configuration = new Configuration();
        $extension = new winzouStateMachineExtension();

        /** @var SplFileInfo $file */
        foreach ($files as $file) {
            $yaml = Yaml::parse($file->getContents());
            $yaml = $parameterBag->resolveValue($yaml);
            $stateMachines = $processor->processConfiguration($configuration, $yaml);
            $stateMachines = $extension->parseConfig($stateMachines);
            foreach ($stateMachines as $machineName => $machineDefinition) {
                if (array_key_exists($machineName, $configs)) {
                    $configs[$machineName] = $machineDefinition;
                }
            }
        }

        $container->setParameter('sm.configs', $configs);
    }
}

I don’t think there’s anything for Sylius to fix either, except for maybe their documentation, to stop someone from scratching their head for too long. Maybe a link to this issue would be sufficient to help someone in the right direction, should they come across this scenario.

Yes, that function was removed recently from both Sylius and Sylius-Standard, as part of the upgrade to Symfony 5: https://github.com/Sylius/Sylius/pull/12148/files#diff-9f0fabe23af928a9571327c664ebe4f50be0b60646e10e59ed40a30fdadd2532

That’s what made it work before, because that code introduce in 1.3 allowed to override any config file (meaning replace it entirely).

Right now, without that code, you can’t remove the transitions though configuration because the configuration definition does not have ->performNoDeepMerging() on the transitions node.