Configuring Workflow Management In Pimcore: Events

Paul July 29th 2016

Introduction

This is the last post in an Introduction to Pimcore Workflow Management. In part 1 and part 2 I introduced workflow management for Pimcore and walked through the concepts of states, statuses and actions, using a common use-case of e-commerce in a PIM system. 


In part three I'll carry on with the same use-case and explain how actions can become much more powerful when events are attached.

 

Action Events

Action events happen when an action is being performed. There are 5 events in total and depending on how your workflow is configured only a number of these will actually fire. At the very least, 2 events will always fire - these are called global action events.

 

Global Action Events

The following events are always fired whenever an action takes place.

 

workflowmanagement.preAction

The preAction event is fired right before an action happens, giving us the ability to interrogate the whole process before anything is committed. This event is intended for situations where you may have many actions that require similar tests. For more action specific tests, I recommend using the Action Specific Events below. A good example of where this event is useful though is for checking the availability of 3rd party services or using it to store information in logs for auditing. 

This event passes and instance of the 'Workflow\Manager' class as the event target along with the 'actionName' as a parameter.

 

workflowmanagement.postAction

The postAction event is fired after the action has happened and the element state, status and notes have been saved. Similarly, this event gives us the ability to see the results of all actions by passing an instance of 'Workflow\Manager' class as the event target along with the 'actionName' as a parameter. Again this is great for logging all actions or replacing email notifications with your own implementation.

 

Using Global Events

Global event handlers are attached to the Pimcore application in the same way as any other Pimcore event handler. For example

 

attach("workflowmanagement.preAction", function(\Zend_EventManager_Event $e) { $manager= $e->getTarget(); //the workflow manager $element = $manager->getElement(); // the element $actionData = $manager->getActionData(); // the action data from the action form if (!My3rdPartyService::isAvailable()) { throw new \Exception('3rd Party Service is unavailable'); } }); \Pimcore::getEventManager()->attach("workflowmanagement.postAction", function(\Zend_EventManager_Event $e) { $manager= $e->getTarget(); //the workflow manager $actionName = $e->getParam('actionName'); //the action name $element = $manager->getElement(); // the element $actionData = $manager->getActionData(); // the action data from the action form $payload = [ 'text' => "I just performed '$actionName' on {$element->getFullPath()}", 'username' => $manager->getUser()->getName() ] //post to slack \Pimcore\Tool::getHttpData( \Pimcore\Config::getWebsiteConfig()->get('slack_webhook_url'), null, [ 'payload' => json_encode($payload) ] ); });

Action Specific Events

Action specific events are assigned to individual actions in the workflow management configuration. Event handlers will only be attached if the specific action being performed has a handler configured.

The following events are available for specific actions.

workflowmanagement.action.before

The before event fires when all requirements set out in an actions configuration have been met and an action is about to be performed on an element. The event passes an instance of the 'Workflow\Manager' class as the event target, and the current 'actionConfig' as a parameter. The form data from the Pimcore admin panel is also passed as the parameter 'data'.
 

This action is great for checking that additional requirements have been met before an action can happen on an element. For example, in an e-commerce PIM system we may have an order ready to be shipped, but before a user can carry out the action "Ship Order", the PIM needs to verify stock of the items.
 

Note that throwing an exception from this event will trigger the 'workflowmanagement.action.failure' event if this has been configured.
 

workflowmanagement.action.success

As we saw in part two, this action can be configured to fire when an action has successfully completed. I've included it in the full example below. This event passes an instance of the 'Workflow\Manager' class as the event target, and the 'actionConfig' and 'data' parameters.
 

workflowmanagement.action.failure

The failure event is wrapped around the entire transition, meaning it can be used as a catch-all for errors or for hooking into the result of the workflowmanagemen.action.before event. The event also passes an instance of the Workflow\Manager class as the target, with 'actionConfig' and 'data' parameters. Additionally, this event also has an 'exception' parameter, which is the '\Exception' thrown.
 

Putting Action Specific Events into Practice

Using these three events we are able to create very powerful chains of events that can automate many different processes within a CRM or PIM. In the use-case of a PIM e-commerce we talked about shipping an order, so below is an example of what could be implemented within a shipment module to verify and automate shipping. The example demonstrates a fall back where there is no stock for a shipment. Obviously the example below assumes a lot about the PIM system, so don't expect to copy and paste this ;-)
 

The action configuration

[ "name" => "ship_order", "label" => "Ship Order", ... "events" => [ "before" => ["\\MyWebshop\\ShippingService", "beforeShipOrder"], "failure" => ["\\MyWebshop\\ShippingService", "shipOrderFailed"], "success" => ["\\MyWebshop\\ShippingService", "printPackingSlip"] ] ]
getTarget(); $element = $manager->getElement(); //check order items has stock foreach ($element->getItems() as $itemOrdered) { if (!$itemOrdered->getStockAvailable()) { throw new \OutOfStockException('Stock is not available'); } } } public static function shipOrderFailed($event) { $exception = $event->getException(); if ($exception instanceof \OutOfStockException) { // do something awesome here // - trigger stock order? // - inform customer? // - inform the admin? } //throw anything else throw $exception } public static function printPackingSlip($event) { $manager = $event->getTarget(); $actionConfig = $event->getParam('actionConfig'); $data = $event->getParam('data'); //Print Packing slip logic would go here ... Maybe use web-to-print ;-) } }

Other Events

At the time of writing, there is only one other event in the Workflow Management feature in Pimcore. However, this event is quite powerful if configured correctly.
 

workflowmanagement.preReturnAvailableActions

In the Pimcore admin panel, when an admin opts to perform an action on an element, they first have to select which action to perform. This event is fired when the user requests the available actions for an element. The result of this event can have an effect on these actions by returning a new array of options for the user to choose from.
 

The event passes an array of allowed actions as the target, and the instance of the 'Workflow\Manager' as a 'manager' parameter. This event is great for customising actions available to users on the fly. How this is done is shown in the example below, once again the handler can be attached like any other event in Pimcore. Let's see how we can restrict the shipping action on the fly.

attach("workflowmanagement.preReturnAvailableActions", function (\Zend_EventManager_Event $e) { $availableActions = $e->getTarget(); //the workflow manager // check for some arbittrary logic and remove the action if false. if (!\ShippingService::isShippingAvailable()) { unset($availableActions['ship_order']); } // this is the most important part, the event MUST return the new available actions // to change them return ['availableActions' => $availableActions]; });

There may be a use-case where you would want to add actions too, simply reverse the logic above and add to the array. The choice is yours!
 

Conclusion

Events are awesome....
 

That's it for part three of the Workflow Management tutorials. I hope that this series has been helpful to developers and shown you just how powerful workflow can make PIM, and Pimcore.
 

If you have any queries relating to the series, want to share ideas or discussion Pimcore and/or Workflow Management please get in touch below or find me in any of the Pimcore groups, twitter, linkedIn and whatnot. I'd be happy to help out.
 

Cheers!

Author Paul Technical Director

Technical Director & Co-founder of Gather. Paul is a Manchester born computer scientist with broad full stack web & mobile application skillset, he has helped shaped Gather's technology, and build many large scale web applications.