digitalstate/platform-bpm-camunda-bundle
Installation
Add the bundle to your composer.json:
composer require digitalstate/platform-bpm-camunda-bundle
Register the bundle in config/bundles.php:
return [
// ...
DigitalState\Platform\Bpm\CamundaBundle\DigitalStatePlatformBpmCamundaBundle::class => ['all' => true],
];
Configuration Publish the default configuration:
php bin/console digitalstate:bpm:camunda:install
Update config/packages/digitalstate_platform_bpm_camunda.yaml with your Camunda server details (e.g., URL, credentials).
First Use Case: Triggering a Process
Use the CamundaClient service to start a process:
use DigitalState\Platform\Bpm\CamundaBundle\Client\CamundaClientInterface;
class MyService {
public function __construct(private CamundaClientInterface $camundaClient) {}
public function startProcess(string $processDefinitionKey, array $variables = []): void {
$this->camundaClient->startProcess($processDefinitionKey, $variables);
}
}
Process Interaction
CamundaClientInterface to kick off workflows:
$this->camundaClient->startProcess('purchase-order', ['orderId' => 123]);
$processes = $this->camundaClient->getProcessInstances('purchase-order');
$this->camundaClient->signalEvent('order-approved', ['orderId' => 123]);
Variable Management
setVariables()/getVariables():
$this->camundaClient->setVariables('processInstanceId', ['status' => 'approved']);
$variables = $this->camundaClient->getVariables('processInstanceId');
Task Handling
$this->camundaClient->completeTask('taskId', ['assignee' => 'user1']);
$tasks = $this->camundaClient->getTasksForUser('user1');
Event Listeners
# config/services.yaml
services:
App\EventListener\CamundaProcessListener:
tags:
- { name: kernel.event_listener, event: digitalstate.bpm.camunda.process.started, method: onProcessStarted }
OroPlatform Integration
DigitalState\Platform\Bpm\CamundaBundle\Entity\CamundaProcess to add custom fields or behaviors.$processes = $this->entityManager->getRepository(CamundaProcess::class)
->findBy(['definitionKey' => 'purchase-order']);
Custom Process Definitions
config/bpmn/ and reference them in YAML:
# config/packages/digitalstate_platform_bpm_camunda.yaml
digitalstate_platform_bpm_camunda:
process_definitions:
purchase-order: { file: 'purchase_order.bpmn' }
API-Driven Workflows
#[Route('/api/processes/{processId}/complete', methods: ['POST'])]
public function completeProcess(CamundaClientInterface $camundaClient, string $processId): JsonResponse {
$camundaClient->completeProcess($processId);
return new JsonResponse(['status' => 'completed']);
}
Testing
CamundaClientInterface mock in PHPUnit:
$mockClient = $this->createMock(CamundaClientInterface::class);
$mockClient->method('startProcess')->willReturn(['id' => 'test-123']);
$this->container->set(CamundaClientInterface::class, $mockClient);
Configuration Overrides
digitalstate_platform_bpm_camunda.client.url.CamundaClientInterface (which uses the configured URL) instead of raw HTTP clients.Process Definition Key Mismatches
processDefinitionKey will silently fail. Validate keys against your process_definitions config:
if (!array_key_exists($processDefinitionKey, $this->config['process_definitions'])) {
throw new \InvalidArgumentException("Invalid process definition key: $processDefinitionKey");
}
Variable Serialization
// ❌ Avoid
$this->camundaClient->startProcess('process', ['user' => $userObject]);
// ✅ Do this
$this->camundaClient->startProcess('process', ['userId' => $userObject->getId()]);
Task Assignee Conflicts
CamundaClientInterface::claimTask() explicitly:
$this->camundaClient->claimTask('taskId', 'user1');
Rate Limiting
use Symfony\Component\Process\Exception\ProcessFailedException;
try {
$this->camundaClient->startProcess('process');
} catch (ProcessFailedException $e) {
if (str_contains($e->getMessage(), 'rate limit')) {
sleep(2 ** $attempt); // Exponential backoff
retry();
}
}
Enable API Logging
Add this to config/packages/monolog.yaml:
handlers:
digitalstate_bpm:
type: stream
path: "%kernel.logs_dir%/digitalstate_bpm.log"
level: debug
channels: ["digitalstate_bpm"]
Then enable logging in digitalstate_platform_bpm_camunda.yaml:
digitalstate_platform_bpm_camunda:
debug: true
Camunda Engine Logs
engine.log (default: logs/camunda-engine.log) for process execution details.Process Instance IDs
processInstanceId when debugging:
$processInstance = $this->camundaClient->startProcess('process');
$this->logger->info('Started process', ['instanceId' => $processInstance['id']]);
Custom Clients
CamundaClient to add domain-specific methods:
class CustomCamundaClient extends CamundaClient {
public function approvePurchaseOrder(string $orderId): void {
$this->signalEvent('order-approved', ['orderId' => $orderId]);
}
}
services:
App\Service\CustomCamundaClient:
decorates: digitalstate_platform_bpm_camunda.client
arguments: ['@digitalstate_platform_bpm_camunda.client.inner']
Event Subscribers
class CamundaToOroSyncListener {
public function onProcessCompleted(ProcessCompletedEvent $event) {
$this->entityManager->persist(new ProcessCompletionLog($event->getProcessInstance()));
$this->entityManager->flush();
}
}
Custom Process Variables
DigitalState\Platform\Bpm\CamundaBundle\Variable\VariableMetadata:
$metadata = new VariableMetadata('status', 'approved', ['readOnly' => true]);
$this->camundaClient->setVariables($instanceId, ['status' => 'approved'], [$metadata]);
BPMN File Watcher
FileWatcher to auto-reload BPMN files during development:
use Symfony\Component\Filesystem\Filesystem;
class BpmnWatcher {
public function __construct(private Filesystem $fs) {}
public function watch(string $directory): void {
$files = $this
How can I help you explore Laravel packages today?