FINITE STATE MACHINE State description of configuration waiting to execute a transition (noun) Transition action to execute if a condition is fulfilled (verb) WORKFLOW NET’ state 1 state 2 transition Place input/output of a transition contains x tokens Transition action to fire to go from a place to another (verb) Marking / Tokens representation of the position of all tokens over the network. place a transition1 transition 2 transition 3 place b place s place e place d transition4 place f transition1 place a
TYPES OF WORKFLOW YOU SHOULD ENCOUNTER place 1 transition 1 place 2 transition 2 place 3 1. Straight (state machine look alike) 1I. Round trip place 1 transition 1 place 2 transition 2 place 3 transition 2 1/2
TYPES OF WORKFLOW YOU SHOULD ENCOUNTER III. OR IV. AND 2/2 place 1 transition a place 2 transition c place 4 transition b place 3 transition d place 1 transition a place 2 transition c place 6 place 3 transition d place 4 transition e place 5
A USE CASE Let’s say you are working on a e-commerce application with Symfony You are in charge of implementing the cart checkout You need to make sure that a product goes through a very precise process through the cart checkout
PROCESS DESCRIBED BY THE MANAGEMENT 1. The product is in stock 2. The customer puts the product in a cart 3. Then 2 options • either the customer puts the product in a wishlist, that way, a friend can pay the cart • either the customer is ready to pay the product 4. Then customer pays and that’s it!
HOW TO USE IT? Step 1: Take a pen and a paper and draw the workflow of your dreams Step 2: Declare your workflow Step 3: Dump it to check if everything’s ok Step 4: Write some code to deal with the process and display things
STEP 3: CHECK IT bin/console workflow:dump product | dot -Tpng > workflow.png /!\ This command is only enabled if there is at least one workflow declared.
SYMFONY\COMPONENT\WORKFLOW\WORKFLOW /** * Returns true if the transition is enabled. * * @param object $subject A subject * @param string $transitionName A transition * * @return bool true if the transition is enabled * * @throws LogicException If the transition does not exist */ public function can($subject, $transitionName) { //… } /** * @Route("/product/{id}", name="show_product") */ public function showAction(Product $product) { dump($this->get('workflow.product')->can($product, 'put_in_cart')); //… }
SYMFONY\COMPONENT\WORKFLOW\WORKFLOW /** * Returns true if the transition is enabled. * * @param object $subject A subject * @param string $transitionName A transition * * @return bool true if the transition is enabled * * @throws LogicException If the transition does not exist */ public function can($subject, $transitionName) { //… } /** * @Route("/product/{id}", name="show_product") */ public function showAction(Product $product) { dump($this->get('workflow.product')->can($product, 'put_in_cart')); //… } True False or according to the current marking
SYMFONY\COMPONENT\WORKFLOW\WORKFLOW /** * Fires a transition. * * @param object $subject A subject * @param string $transitionName A transition * * @return Marking The new Marking * * @throws LogicException If the transition is not applicable * @throws LogicException If the transition does not exist */ public function apply($subject, $transitionName) { //… }
STEP 4: IN YOUR CODE How can I display things? 3/4 The current marking {{ product.marking|keys|join(', ')|default('[]')|raw }} Available transitions {% for transition in workflow_transitions(product) %} {{ dump(transition) }} {% else %} No more transition available for the product object. {% endfor %}
STEP 4: IN YOUR CODE Go from a place to another 4/4 Apply a transition 1/2 /** * @Route("/apply-transition/{id}", name="article_apply_transition") */ public function applyTransitionAction(Request $request, Product $product) { try { $this->get('workflow.product') ->apply($product, $request->request->get('transition')); $this->get('doctrine')->getManager()->flush(); } catch (ExceptionInterface $e) { $this->get('session')->getFlashBag()->add('danger', $e->getMessage()); } return $this->redirect( $this->generateUrl('show_product', ['id' => $product->getId()]) ); }
EVENTS 3 nice events workflow.enter workflow.leave workflow.transition Take a look at that event subscriber: Symfony\Component\Workflow\EventListener\AuditTrailListener
EVENTS 3 nice events workflow.enter workflow.leave workflow.transition Take a look at that event subscriber: Symfony\Component\Workflow\EventListener\AuditTrailListener a place is reached
EVENTS 3 nice events workflow.enter workflow.leave workflow.transition Take a look at that event subscriber: Symfony\Component\Workflow\EventListener\AuditTrailListener a place is left a place is reached
EVENTS 3 nice events workflow.enter workflow.leave workflow.transition Take a look at that event subscriber: Symfony\Component\Workflow\EventListener\AuditTrailListener a place is left a place is reached a transition is fired
GUARD EVENT Make an event [listener|subscriber] on that event $event->setBlocked($bool) according to your logic https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Workflow/Workflow.php#L186
FOLLOW US ON THE INTER TUBES @openclassrooms www.facebook.com/openclassrooms www.instagram.com/openclassrooms plus.google.com/+OpenClassrooms www.youtube.com/user/TheOpenClassrooms