Installation
composer require phpmentors/workflower-bundle "1.4.*"
Register the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):
return [
// ...
PHPMentors\WorkflowerBundle\PHPMentorsWorkflowerBundle::class => ['all' => true],
];
Configure Workflower
Add a workflower.yaml config file in config/packages/:
phpmentors_workflower:
contexts:
default:
bpmn_directory: '%kernel.project_dir%/config/workflows'
serializer: 'phpmentors_workflower.serializer.doctrine'
First Use Case: Define a Workflow
.bpmn file (e.g., order_processing.bpmn) in config/workflows/default/.OrderProcessService) with the @phpmentors_workflower.process_aware tag:
use PHPMentors\WorkflowerBundle\Annotation\ProcessAware;
class OrderProcessService {
/**
* @ProcessAware(process="order_processing")
*/
public function startOrderProcess(Order $order) { ... }
}
Trigger a Workflow
Inject the Workflower service and call:
$workflower = $this->container->get('phpmentors_workflower.workflower');
$workflower->startProcess('order_processing', ['orderId' => $order->id]);
Process-Aware Services
@ProcessAware to bind them to BPMN processes.InvoiceService for invoice_workflow).class InvoiceService {
/**
* @ProcessAware(process="invoice_workflow")
*/
public function generateInvoice(Invoice $invoice) {
// Workflower will handle the process flow here.
}
}
Context Management
dev, prod).workflower.yaml:
phpmentors_workflower:
contexts:
dev:
bpmn_directory: '%kernel.project_dir%/config/workflows/dev'
prod:
bpmn_directory: '%kernel.project_dir%/config/workflows/prod'
$workflower->setContext('prod');
Entity Serialization
Serializable or use @Serializer annotations:
use PHPMentors\WorkflowerBundle\Annotation\Serializer;
class Order implements \Serializable {
/**
* @Serializer
*/
public function serialize() { ... }
}
Security Integration
workflower.yaml:
phpmentors_workflower:
security:
roles:
start_order_process: ROLE_ADMIN
if (!$this->isGranted('start_order_process')) {
throw new \RuntimeException('Unauthorized');
}
Event Listeners
ProcessStarted, ActivityExecuted).use PHPMentors\WorkflowerBundle\Event\ProcessStartedEvent;
$eventDispatcher->addListener(
'workflower.process.started',
function (ProcessStartedEvent $event) {
// Log or notify when a process starts.
}
);
BPMN File Paths
bpmn_directory in workflower.yaml is absolute and points to a valid directory.%kernel.project_dir% for cross-environment consistency.Serialization Issues
@Serializer or implement \Serializable.Order ↔ Customer with bidirectional relations).Process-Aware Tag Misconfiguration
@ProcessAware annotation must match a .bpmn file in the configured directory.process attribute in the annotation matches the BPMN file name (without .bpmn).Context Switching
$workflower->setContext('name') explicitly.Doctrine Integration
phpmentors_workflower.serializer.doctrine service is registered.PHPMentors\WorkflowerBundle\Serializer\SerializerInterface.Enable Workflower Logging
Add to config/packages/dev/monolog.yaml:
handlers:
workflower:
type: stream
path: '%kernel.logs_dir%/workflower.log'
level: debug
channels: ['workflower']
Then configure the channel in workflower.yaml:
phpmentors_workflower:
logging: true
Validate BPMN Files Use the Workflower CLI to validate BPMN syntax:
vendor/bin/workflower validate config/workflows/default/order_processing.bpmn
Check Process State
Inspect active processes via the Workflower service:
$activeProcesses = $workflower->getActiveProcesses();
Custom Serializers
Create a custom serializer by implementing SerializerInterface and register it as a service:
services:
app.custom_serializer:
class: App\Serializer\CustomSerializer
tags: ['phpmentors_workflower.serializer']
Workflow Events Extend workflow behavior by listening to events:
// Example: Pause a process on a custom event.
$eventDispatcher->addListener(
'workflower.activity.executed',
function (ActivityExecutedEvent $event) {
if ($event->getActivityName() === 'approve_order') {
$event->getProcess()->pause();
}
}
);
Dynamic Process Variables Use Symfony’s parameter bag to pass dynamic variables:
$workflower->startProcess('order_processing', [
'order' => $order,
'user' => $this->getUser(),
]);
Access these in BPMN scripts via execution.getVariable('order').
How can I help you explore Laravel packages today?