Search code examples
symfonyworkflowtransition

Symfony workflow initializes back itself when passing to another route


I'm using Symfony workflow on my project. I can pass the first transition and see that the next transitions are enabled with $workflow->getEnabledTransitions($entity);. When passing to another route which introduce the next transition (part of the enabled transitions) it seems that the workflow has initialized back itself when checking the enabled transitions.

Here is my workflow.yaml configuration file :

framework:
    workflows:
        produit_selection:
            type: 'workflow' # or 'state_machine'
            audit_trail:
                enabled: true
            marking_store:
                type: 'single_state'
                arguments:
                    - 'currentPlace'
            supports:
                - App\Entity\Produit
            initial_place: initiale
            places:
                - initiale
                - commande
                - selectionne
                - invalide_selection
            transitions:
                commander:
                    from: initiale
                    to:   commande
                selectionner:
                    from: commande
                    to:   selectionne
                invalider_selection:
                    from: commande
                    to:   invalide_selection

Here is my commandeProduit controller action :

/**
 * @Route("/produit/commande/{id<\d+>}", name="produit_commande")
 * @param Request $request
 * @param $id
 * @param ProduitRequestCommandeUpdateHandler $updateHandler
 * @return \Symfony\Component\HttpFoundation\Response
 * @Security("has_role('ROLE_MARKETING')")
 */
public function commandeProduit(
    Request $request,
    $id,
    ProduitRequestCommandeUpdateHandler $updateHandler,
    Registry $workflows
) {
    $repository = $this->getDoctrine()->getRepository(Produit::class);
    /** @var Produit $produit */
    $produit = $repository->find($id);

    $produitRequest = ProduitRequest::createFromProduit($produit);

    $form = $this->createForm(ProduitCommandeType::class, $produitRequest)->handleRequest($request);

    $box = $produit->getBox();

    if ($form->isSubmitted() AND $form->isValid()) {
        $produit = $updateHandler->handle($produitRequest, $produit, $box);

        if (null === $produit) {
            $this->addFlash(
                'error',
                "La commande a été annulée car elle dépasse le budget."
            );
        } elseif ($produit->getCommande()) {
            $workflow = $workflows->get($produit, 'produit_selection');
            //$workflow->getMarking($produit);

            if ($workflow->can($produit, 'commander')) {
                try {
                    $workflow->apply($produit, 'commander');
                } catch (TransitionException $exception) {
                    // ... if the transition is not allowed

                }
            }

            $transitions = $workflow->getEnabledTransitions($produit);

            /** @var Transition $transition */
            foreach($transitions as $transition) {
                $this->addFlash(
                    'error',
                    $transition->getName()
                );
            }

            $this->addFlash(
                'notice',
                "La commande du produit a bien été prise en compte avec la quantité " . $produit->getQuantite() . "."
            );
        } else {
            $this->addFlash(
                'warning',
                "Le produit n'est pas disponible."
            );
        }

        return $this->redirectToRoute("produits_commande");
    }

    $fournisseur = $produit->getFournisseur();

    return $this->render('produits/commande_produit.html.twig', [
        'box' => $box,
        'fournisseur' => $fournisseur,
        'form' => $form->createView()
    ]);
}

And here is my selectionProduit controller action :

/**
 * @Route("/produit/selection/{id<\d+>}", name="produit_selection")
 * @param Request $request
 * @param $id
 * @param ProduitRequestUpdateHandler $updateHandler
 * @param Registry $workflows
 * @return \Symfony\Component\HttpFoundation\Response
 * @Security("has_role('ROLE_MARKETING')")
 */
public function selectionProduit(
    Request $request,
    $id,
    ProduitRequestUpdateHandler $updateHandler,
    Registry $workflows
) {
    $repository = $this->getDoctrine()->getRepository(Produit::class);
    /** @var Produit $produit */
    $produit = $repository->find($id);

    $produitRequest = ProduitRequest::createFromProduit($produit);

    $form = $this->createForm(ProduitSelectionType::class, $produitRequest)->handleRequest($request);

    if($form->isSubmitted() AND $form->isValid()) {
        $produit = $updateHandler->handle($produitRequest, $produit);

        if ($produit->getSelectionne()) {
            $workflow = $workflows->get($produit, 'produit_selection');
            //$workflow->getMarking($produit);

            $workflow->can($produit, 'selectionner');

            try {
                $workflow->apply($produit, 'selectionner');
            } catch (TransitionException $exception) {
                // ... if the transition is not allowed
            }

            $transitions = $workflow->getEnabledTransitions($produit);

            /** @var Transition $transition */
            foreach($transitions as $transition) {
                $this->addFlash(
                    'error',
                    $transition->getName()
                );
            }

            $this->addFlash(
                'notice',
                "Le produit a bien été sélectionné avec la quantité " . $produit->getQuantite() . ".");
        } else {
            $workflow = $workflows->get($produit, 'produit_selection');
            //$workflow->getMarking($produit);

            if ($workflow->can($produit, 'invalider_selection')) {
                try {
                    $workflow->apply($produit, 'invalider_selection');
                } catch (TransitionException $exception) {
                    // ... if the transition is not allowed

                }
            }

            $transitions = $workflow->getEnabledTransitions($produit);

            $this->addFlash(
                'warning',
                "Le produit n'a pas été sélectionné.");
        }

        return $this->redirectToRoute("produits_selection");
    }

    $box = $produit->getBox();
    $fournisseur = $produit->getFournisseur();

    return $this->render('produits/selection_produit.html.twig', [
        'box' => $box,
        'fournisseur' => $fournisseur,
        'form' => $form->createView()
    ]);
}

Why the workflow doesn't transit to the next place after changing route ? How to fix that ? Thanks for help.


Solution

  • I found it. We have to flush the entity to store the current place :

    $workflow->apply($produit, 'selectionner');
    $this->getDoctrine()->getManager()->flush();
    

    And in the entity we have a field defined like this :

    /**
     * @ORM\Column(type="string", length=100)
     */
    public $currentPlace;