Important
You are browsing documentation for version 6.1 of OroCommerce, supported until 2029. Read the documentation for the latest LTS version to get up-to-date information.
See our Release Process documentation for more information on the currently supported and upcoming releases.
Workflow Events
The platform triggers several events at various points in the workflow lifecycle. These events let you hook into workflow execution and run custom logic at specific points — for example, to add business logic, send notifications, or update external systems based on workflow activity.
Special guard events can prevent a transition from being executed or displayed.
Available Events
When a transition is initiated, the events are dispatched in the following order:
oro_workflow.pre_announce
Validate whether the transition button is allowed (triggered before pre-condition checks). This is a guard event.
The three events being dispatched are:
oro_workflow.pre_announce
oro_workflow.[workflow name].pre_announce
oro_workflow.[workflow name].pre_announce.[transition name]
oro_workflow.announce
Validate whether the transition button is allowed (triggered after pre-condition checks). This is a guard event.
The three events being dispatched are:
oro_workflow.announce
oro_workflow.[workflow name].announce
oro_workflow.[workflow name].announce.[transition name]
oro_workflow.pre_guard
Validate whether the transition is allowed (triggered before condition checks). This is a guard event.
The three events being dispatched are:
oro_workflow.pre_guard
oro_workflow.[workflow name].pre_guard
oro_workflow.[workflow name].pre_guard.[transition name]
oro_workflow.guard
Validate whether the transition is allowed (triggered after condition checks). This is a guard event.
The three events being dispatched are:
oro_workflow.guard
oro_workflow.[workflow name].guard
oro_workflow.[workflow name].guard.[transition name]
oro_workflow.leave
Workflow is leaving some step (triggered for already started workflows).
The three events being dispatched are:
oro_workflow.leave
oro_workflow.[workflow name].leave
oro_workflow.[workflow name].leave.[previous step name]
oro_workflow.start
Workflow is starting and entering the start step (oro_workflow.leave will not be triggered).
The two events being dispatched are:
oro_workflow.start
oro_workflow.[workflow name].start
oro_workflow.enter
This event is triggered right before the entity enters the new step.
The three events being dispatched are:
oro_workflow.enter
oro_workflow.[workflow name].enter
oro_workflow.[workflow name].enter.[new step name]
oro_workflow.entered
This event is triggered right after the entity has entered the new step.
The three events being dispatched are:
oro_workflow.entered
oro_workflow.[workflow name].entered
oro_workflow.[workflow name].entered.[new step name]
oro_workflow.transition.assemble
This event fires just before the transition model is assembled. It lets you hook into the transition build process and modify transition options.
For example, it can be used to add a form to the transition based on some conditions.
oro_workflow.transition
Transition logic is starting execution (triggered right before the execution of transition actions).
The three events being dispatched are:
oro_workflow.transition
oro_workflow.[workflow name].transition
oro_workflow.[workflow name].transition.[transition name]
oro_workflow.completed
Transition logic is being executed (triggered right after execution of transition actions).
The three events being dispatched are:
oro_workflow.completed
oro_workflow.[workflow name].completed
oro_workflow.[workflow name].completed.[transition name]
oro_workflow.finish
Transition logic is being executed (triggered right after execution of transition actions).
The two events being dispatched are:
oro_workflow.finish
oro_workflow.[workflow name].finish
Workflow Event Listener Example
Here is an example of how to enable logging every time an “opportunity_flow” workflow leaves a step:
namespace Acme\Bundle\DemoBundle\EventListener;
use Psr\Log\LoggerInterface;
use Oro\Bundle\WorkflowBundle\Event\Transition\StepLeaveEvent;
class OpportunityFlowLoggingEventListener
{
public function __construct(
private LoggerInterface $logger
) {
}
public function onLeave(StepLeaveEvent $event): void
{
$workflowItem = $event->getWorkflowItem();
$transition = $event->getTransition();
$entity = $workflowItem->getEntity();
$this->logger->alert(sprintf(
'Opportunity (id: "%d") performed transition "%s" from "%s" to "%s"',
$entity->getId(),
$transition->getName(),
$workflowItem->getCurrentStep()->getName(),
$transition->getResolvedStepTo($workflowItem)->getName()
));
}
}
services:
# ...
acme.demo.event_listener.opportunity_flow_logging_event_listener:
class: Acme\Bundle\DemoBundle\EventListener\OpportunityFlowLoggingEventListener:
arguments:
- '@logger'
tags:
- { name: kernel.event_listener, event: oro_workflow.opportunity_flow.leave, method: onLeave }
Guard Events
Four events can disable a transition: oro_workflow.pre_announce, oro_workflow.announce, oro_workflow.pre_guard and oro_workflow.guard. Use announce events to hide the transition button and guard events to prevent transition execution.
Note
Precondition checks (and announce events) run before transition button rendering and again during condition checks before execution. As a result, disabling transition availability in the announce event listener also disables transition execution.
Let’s review an example of the “Close As Won” transition being blocked when the Budget Amount is less than 100.
namespace Acme\Bundle\DemoBundle\EventListener;
use Oro\Bundle\WorkflowBundle\Event\Transition\PreAnnounceEvent;
class OpportunityFlowBudgetEventListener
{
public function onPreAnnounce(PreAnnounceEvent $event): void
{
// Do nothing if the execution was already disabled
if (!$event->isAllowed()) {
return;
}
$opportunity = $event->getWorkflowItem()->getEntity();
$event->setAllowed($opportunity->getBudgetAmount()->getValue() > 100.0);
}
}
services:
# ...
acme.demo.event_listener.opportunity_flow_budget_event_listener:
class: Acme\Bundle\DemoBundle\EventListener\OpportunityFlowBudgetEventListener:
tags:
- { name: kernel.event_listener, event: oro_workflow.opportunity_flow.pre_announce.close_won, method: onPreAnnounce }
Form Events
In addition to workflow events, the platform triggers a set of form-specific events on the workflow attributes form pre-set data.
oro_workflow.transition_form_init
This event is triggered when workflow transition attributes form is initialized
oro_workflow.transition_form_init
oro_workflow.[workflow name].transition_form_init
oro_workflow.[workflow name].transition_form_init.[transition name]
oro_workflow.attribute_form_init
This event is triggered when workflow attributes form is initialized
oro_workflow.attribute_form_init
oro_workflow.[workflow name].attribute_form_init
Extending Workflow Configuration
Sometimes you need to change the workflow configuration itself. Use Workflow Definition Builder extensions for this. The platform calls these extensions during the configuration-building process when loading workflow definitions.
To create a new extension service, implement the WorkflowDefinitionBuilderExtensionInterface and tag it with the oro.workflow.definition_builder.extension tag.
Let’s create an example where a new attribute is added to the workflow and used at the transition form.
namespace Acme\Bundle\DemoBundle\Workflow;
use Oro\Bundle\WorkflowBundle\Configuration\WorkflowDefinitionBuilderExtensionInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
/**
* Add call_rating to phone_call workflow attributes and end_conversation transition form
* if is_collaboration_workflow is enabled.
*/
class PhoneCallConfigBuilderExtension implements WorkflowDefinitionBuilderExtensionInterface
{
public function prepare($workflowName, array $configuration)
{
if ($workflowName !== 'phone_call') {
return $configuration;
}
if (empty($configuration['metadata']['is_collaboration_workflow'])) {
return $configuration;
}
if (empty($configuration['transitions']['end_conversation'])) {
return $configuration;
}
if (empty($configuration['attributes']['call_rating'])) {
$configuration['attributes']['call_rating'] = [
'type' => 'string',
'label' => 'oro.workflow.phone_call.attribute.call_rating.label'
];
}
$configuration['transitions']['end_conversation']['form_options']['attribute_fields']['call_rating'] = [
'form_type' => TextType::class,
'label' => 'oro.workflow.checkout.state_token.attribute_label'
];
return $configuration;
}
}
services:
# ...
acme.demo.workflow.phone_call_config_builder_extension:
class: Acme\Bundle\DemoBundle\Workflow\PhoneCallConfigBuilderExtension
tags:
- { name: oro.workflow.definition_builder.extension }
Note
The extension will change the configuration during the execution of the oro:workflow:definitions:load command. Do not forget to run this command when developing configuration extensions.