Sylius: [Doc] Can't override sylius_order_checkout states

Created on 14 Dec 2016  路  22Comments  路  Source: Sylius/Sylius

Hello. i'm having problems to override states in sylius_order_checkout process. First thing i tried is follow instructions, but placing the file where it says, it doesn't seem to have any effect in the configurations...

Second thing i tried is to override this from my own bundle. so, i added a sylius_checkout_order.yml there and imported it from my config.yml. Just for testing purposes i added dummy values to the file. The plan is remove the shipping_selected state, so i went like

winzou_state_machine:
    sylius_order_checkout:
        class: my_class
        property_path: checkoutState
        graph: sylius_order_checkout_my_graph
        state_machine_class: "%sylius.state_machine.class%"
        states:
            cart: ~
            addressed: ~
            payment_selected: ~
            completed: ~

Now the problem: While the class and graph values are overrided, it looks i cannot delete that shipping_selected stated. doing a debug:container i can see this

winzou_state_machine:
    sylius_order_checkout:
        class: my_class
        property_path: checkoutState
        graph: sylius_order_checkout_my_graph
        state_machine_class: Sylius\Component\Resource\StateMachine\StateMachine
        states:
            cart: null
            addressed: null
            shipping_selected: null
            payment_selected: null
            completed: null

As you see, shipping_selected is there and i can't find the way to remove it. just for testing i modified my yml to be like

winzou_state_machine:
    sylius_order_checkout:
        class: my_class
        property_path: checkoutState
        graph: sylius_order_checkout_my_graph
        state_machine_class: "%sylius.state_machine.class%"
        states:
            a_dummy_state: ~

Doing the debug again i can see

winzou_state_machine:
    sylius_order_checkout:
        class: my_class
        property_path: checkoutState
        graph: sylius_order_checkout_my_graph
        state_machine_class: Sylius\Component\Resource\StateMachine\StateMachine
        states:
            cart: null
            addressed: null
            shipping_selected: null
            payment_selected: null
            completed: null
            a_dummy_state: null

So, looks that's something, and maybe not in the Sylius side, is merging the states isteand of replacing them?
Or am i missing something here?

Thanks a lot.

Potential Bug

Most helpful comment

@crevillo I had the same issue. This is my way of solution. I overwrite the getContainerLoader method in app/AppKernel.php like this:

protected function getContainerLoader(ContainerInterface $container)
    {
        $locator = new FileLocator($this, $this->getRootDir() . '/Resources');
        $resolver = new LoaderResolver(array(
            new XmlFileLoader($container, $locator),
            new YamlFileLoader($container, $locator),
            new IniFileLoader($container, $locator),
            new PhpFileLoader($container, $locator),
            new DirectoryLoader($container, $locator),
            new ClosureLoader($container),
        ));

        return new DelegatingLoader($resolver);
    }

After the instruction will work correctly.

All 22 comments

Hi @crevillo!

Yes. This is a known issue. We are not able to fully override state machines. The configurations are merged. And the problem lays rather in the state machine bundle than in Sylius itself :<

Although you can disable existing callbacks to certain transitions, and modify the graph, the old graph with its states and transition will still be there.

@TheMadeleine but if we "override" the whole file by placing a new one in app/... (as described here) shouldn't it work?

@michalmarcinkowski it doesn't as far i see. By the way, in the documentation your are told to that because is a standard procedure of overriding configs in Symfony, but if you open the symfony doc, in that page you are told to create a bundle having a parent in order to customize settings like this... don't you?

@crevillo I had the same issue. This is my way of solution. I overwrite the getContainerLoader method in app/AppKernel.php like this:

protected function getContainerLoader(ContainerInterface $container)
    {
        $locator = new FileLocator($this, $this->getRootDir() . '/Resources');
        $resolver = new LoaderResolver(array(
            new XmlFileLoader($container, $locator),
            new YamlFileLoader($container, $locator),
            new IniFileLoader($container, $locator),
            new PhpFileLoader($container, $locator),
            new DirectoryLoader($container, $locator),
            new ClosureLoader($container),
        ));

        return new DelegatingLoader($resolver);
    }

After the instruction will work correctly.

this indeed seems to work. can we be sure this has no unwanted side effects?

hi , i've did all the instructions and i've overrided the getContainerLoader method in app/AppKernel.php and when i click next in the payment step it keeps redirect me to payment step ? what can be the problem

hmm, overriding the the getContainerLoaded and following the instructions worked for me perfectly....

i'm using sylius beta

@yosriMekni, are you sure you haven't any state machine overrides?

let me add something. i have indeed to change some things from the doc, even i don't know if this is related where the problem @yosriMekni is having.

First, in the app/Resources/SyliusShopBundle/config/routing/checkout.yml i needed to change the form definitions. for instance, where it reads

form:
    type: sylius_checkout_address

i had to add the full form type class type there to make it work.

Second, in the last part of this file, when trying to make the payment (i'm using a custom payum gateway, btw)

redirect:
                route: sylius_shop_order_pay
                parameters:
                    paymentId: expr:service('sylius.context.cart').getCart().getLastNewPayment().getId()

i had to modify the parameters part leaving it like

redirect:
                route: sylius_shop_order_pay
                parameters:
                    tokenValue: resource.tokenValue

Btw, this last part is what the sylius file has now. Same goes for the form definitions
https://github.com/Sylius/Sylius/blob/master/src/Sylius/Bundle/ShopBundle/Resources/config/routing/checkout.yml#L95

Maybe we should update the doc...

i've just removed shipping state as the docs says :

app/syliuscorebundle/config/app/state_machine/sylius_order_checkout.yml :

winzou_state_machine:
    sylius_order_checkout:
        class: "%sylius.model.order.class%"
        property_path: checkoutState
        graph: sylius_order_checkout
        state_machine_class: "%sylius.state_machine.class%"
        states:
            cart: ~
            addressed: ~
            payment_selected: ~
            completed: ~
        transitions:
            address:
                from: [cart, addressed, payment_selected]
                to: addressed
            select_payment:
                from: [addressed, payment_selected]
                to: payment_selected
            complete:
                from: [payment_selected]
                to: completed
        callbacks:
            after:
                sylius_process_cart:
                    on: ["address", "select_payment"]
                    do: ["@sylius.order_processing.order_processor", "process"]
                    args: ["object"]
                sylius_create_order:
                    on: ["complete"]
                    do: ["@sm.callback.cascade_transition", "apply"]
                    args: ["object", "event", "'create'", "'sylius_order'"]
                sylius_save_checkout_completion_date:
                    on: ["complete"]
                    do: ["object", "completeCheckout"]
                    args: ["object"]

app/Resources/syliusshopbundle/config/routing/checkout.yml:

```yaml
sylius_shop_checkout_start:
path: /
defaults:
_controller: FrameworkBundle:Redirect:redirect
route: sylius_shop_checkout_address

sylius_shop_checkout_address:
path: /address
methods: [GET, PUT]
defaults:
_controller: sylius.controller.order:updateAction
_sylius:
event: address
flash: false
template: SyliusShopBundle:Checkout:address.html.twig
form:
type: Sylius\Bundle\CoreBundle\Form\Type\Checkout\AddressType
options:
customer: expr:service('sylius.context.customer').getCustomer()
repository:
method: find
arguments:
- "expr:service('sylius.context.cart').getCart()"
state_machine:
graph: sylius_order_checkout
transition: address
redirect:
route: sylius_shop_checkout_select_payment
parameters: []

sylius_shop_checkout_select_payment:
path: /select-payment
methods: [GET, PUT]
defaults:
_controller: sylius.controller.order:updateAction
_sylius:
event: payment
flash: false
template: SyliusShopBundle:Checkout:selectPayment.html.twig
form: Sylius\Bundle\CoreBundle\Form\Type\Checkout\SelectPaymentType
repository:
method: find
arguments:
- "expr:service('sylius.context.cart').getCart()"
state_machine:
graph: sylius_order_checkout
transition: select_payment
redirect:
route: sylius_shop_checkout_complete
parameters: []

sylius_shop_checkout_complete:
path: /complete
methods: [GET, PUT]
defaults:
_controller: sylius.controller.order:updateAction
_sylius:
event: complete
flash: false
template: SyliusShopBundle:Checkout:complete.html.twig
repository:
method: find
arguments:
- "expr:service('sylius.context.cart').getCart()"
state_machine:
graph: sylius_order_checkout
transition: complete
redirect:
route: sylius_shop_order_pay
parameters:
tokenValue: resource.tokenValue
form:
type: Sylius\Bundle\CoreBundle\Form\Type\Checkout\CompleteType
options:
validation_groups: 'sylius_checkout_complete```

it worked , its a problem of cache , knowing that i've cleared it yesterday and nothing changed , and i've did it again now and it worked , confusing !!

An other problem appears , the order passed with total shipping costs = 20.64 , at the complete step !!

@yosriMekni is it wrong?

this make sense, afaik, if you still have some shipping method enabled for your channel and for the zone.
by default, when you add the product sylius adds a shipment if it finds one.

let the others correct me if i'm wrong, but i think yo need to delete every shipment method from your shop.

if i remove the shipping step it should passe the order without shipping costs .
i don't want to delete the shipping methods from my store because i'm tying to achieve that some products needs to be shipped and others not
*excuse my english

Then you need more work, You need to work in the OrderProcessors. These ones are executed in every step or your process. This one assigns a default shipment to your order/cart as soon as it's created. you'll probably need to override this so the method doesn't get added to the other.

@yosriMekni The solution for your problem is here: #7215. The shipment is still created for the order, even if you skip this step.

after removing the shipping step ,i've created an other channel with code 'tn_store' and i've added a product to it , and when i try to add the product to the cart and exception appears in the ajax call :
the url : web/app_dev.php/ajax/cart/add?productId=62
the exeption : Notice: Undefined index: tn_store / 500 Internal Server Error - ContextErrorException
stack trace :
image

hi again. i've just exposed this problem in a symfony-devs channel and somebody has pointed me to http://symfony.com/doc/current/components/config/definition.html#merging-options.
Do you think this can suitable? i guess this should added in the sylius bundle configuration... i'll give a try to it and let you know.

@c-revillo Looks really promising. Looking forward for your feedback on it! 馃憤

Still stumbled on this. i found another way to make the override part remove the 'shipping_selected' method but:
1) is not the method we have in the doc
2) if involves a change in the winzou_state_machine bundle.

So, what has worked for me is to add the winzow_state_machine part directly in the app/config/config.yml file, just aboves the import parts.
also, i needed to manually modify this file adding a new line there, like

$configNode
            ->arrayNode('states')
                ->performNoDeepMerging() // added line
                ->useAttributeAsKey('name')
                ->prototype('scalar')
            ->end()
        ;

with this, doing the debug container part i can't see the shipping_select anymore. but i need to recheck in this is not doing anything nasty with the rest of defined winzow_state_machines...

So, should we ping the Winzow state machine creator(s) to see if they can at least at that line to their code?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

inssein picture inssein  路  3Comments

stefandoorn picture stefandoorn  路  3Comments

Chrysweel picture Chrysweel  路  3Comments

javiereguiluz picture javiereguiluz  路  3Comments

mikemix picture mikemix  路  3Comments