drupal eca integration guide
Drupal ECA Integration Guide
Table of Contents
- Overview
- Architecture
- Sub-Modules
- Actions, Conditions, and Events
- AI Integration
- Creating Custom ECA Plugins
- Agent Workflow Patterns
- BPMN.io Visual Builder
- Code Examples
- Best Practices
- Resources
Overview
ECA (Event-Condition-Action) is a powerful, versatile rules engine for Drupal that enables both developers and site administrators to orchestrate complex workflows without writing code. It provides a no-code interface backed by a robust plugin-based architecture.
Key Capabilities
- Event-Driven Architecture: React to 200+ system events
- Conditional Logic: Evaluate 70+ condition types
- Action Execution: Perform 500+ actions from core and contrib modules
- Visual Workflow Builder: BPMN.io integration for graphical process design
- Context Stack Support: Manage complex data flow through workflows
- Extensible Plugin System: Create custom events, conditions, and actions
- Configuration-Based Storage: Export/import workflows via Drush or UI
- Recursion Prevention: Built-in safeguards for infinite loops
- TypedData Support: Type-safe data handling
- Caching & Performance: Optimized execution with caching support
Version Requirements
- Drupal: 10.3+ (Drupal 11.2+ for ECA 3.0)
- PHP: 8.1+ (PHP 8.3+ for ECA 3.0)
Use Cases
- Automated content processing pipelines
- Multi-step AI agent workflows
- User account lifecycle management
- Content publishing workflows
- Integration with external services
- Real-time notifications and alerts
- Data transformation and enrichment
Architecture
Core Concept: Event † Condition † Action
ECA operates on a simple but powerful principle:
EVENT (Something happens)
†
CONDITIONS (Verify specific criteria)
†
ACTIONS (Execute response)
Plugin System
ECA uses three core plugin managers:
1. Events Plugin Manager
Defines what can trigger a workflow. Events are dispatched when:
- Content is created, updated, or deleted
- Users log in or register
- Forms are submitted
- Migrations run
- Cron jobs execute
- Custom kernel events fire
2. Conditions Plugin Manager
Evaluates whether actions should execute. Conditions check:
- Node properties (type, status, author)
- User roles and permissions
- Entity field values
- Numeric comparisons
- String operations
- Custom logic
3. Actions Plugin Manager
Performs operations after conditions pass. Actions can:
- Create, update, or delete entities
- Send emails or messages
- Log information
- Call webhooks
- Execute custom code
- Manipulate user roles
- Modify cache
- Dispatch events
Context Stack
The context stack maintains data throughout workflow execution:
- Each action can receive context from previous steps
- Variables persist across conditions and actions
- Supports TypedData for type-safe operations
- Can be inspected for debugging
Sub-Modules
ECA includes 19 specialized sub-modules. Enable only those you need:
Foundational Modules
ECA Base
Status: Core foundation (always enabled) Purpose: Basic events, conditions, and actions Key Features:
- Event dispatching
- Core condition types
- Basic action execution
- State management
ECA UI
Purpose: Administrative interface for workflow management Features:
- Visual workflow editor (BPMN.io integration)
- Configuration management
- Model import/export
- Workflow testing interface
ECA Development
Purpose: Development and debugging utilities Features:
- Drush commands
- Log analysis
- Event tracking
- Performance profiling
Content & Entity Modules
ECA Content
Purpose: Content entity operations Key Actions:
- Create/update/delete nodes
- Create/update/delete media
- Create/update/delete taxonomy terms
- Bulk operations
- Entity reference operations
Key Conditions:
- Node type checks
- Published status checks
- Author checks
- Field value comparisons
ECA User
Purpose: User account and authentication operations Key Actions:
- Create/update/delete user accounts
- Modify user roles
- Set user passwords
- Block/unblock users
- Send user notifications
Key Events:
- User login
- User registration
- User deletion
- Password reset
ECA Form
Purpose: Form API integration Key Events:
- Form pre-render
- Form validation
- Form submission
- Form alter hooks
Key Actions:
- Modify form elements
- Add validation
- Redirect form submission
- Modify form submission data
ECA Views
Purpose: Views query execution and export Key Events:
- View execution
- View row render
Key Actions:
- Export view data
- Modify view results
- Execute view queries programmatically
System & Configuration Modules
ECA Config
Purpose: Configuration-related operations Key Events:
- Configuration save
- Configuration delete
- Configuration import/export
Key Actions:
- Save configuration
- Delete configuration
- Load configuration
ECA Cache
Purpose: Cache management Key Actions:
- Write cache item
- Read cache item
- Invalidate cache
- Clear cache tags
- Flush all caches
Key Conditions:
- Cache exists check
- Cache value comparison
ECA Workflow
Purpose: Content entity workflow state management Key Actions:
- Transition entity state
- Set workflow state
- Get current state
Key Events:
- Workflow state transition
- State change events
ECA Access
Purpose: Entity and field access control Key Actions:
- Grant/revoke entity access
- Modify field permissions
- Set access conditions
Key Conditions:
- Permission checks
- Access control checks
File & Media Modules
ECA File
Purpose: File system operations Key Actions:
- Create/update/delete files
- Copy files
- Move files
- Read file contents
- Write file contents
Key Events:
- File operations
- Media file changes
ECA Render
Purpose: Render API, blocks, views, themes, Twig Key Events:
- Block render
- View render
- Theme preprocess
- Element render
Key Actions:
- Modify render arrays
- Add CSS/JavaScript
- Modify Twig variables
- Cache render output
Integration & Utility Modules
ECA Language
Purpose: Language and translation handling Key Actions:
- Get language code
- Translate strings
- Set active language
Key Events:
- Language switch events
ECA Log
Purpose: Drupal logging integration Key Actions:
- Log messages
- Create watchdog entries
- Log warnings and errors
ECA Menu
Purpose: Menu system integration Key Actions:
- Create menu links
- Update menu links
- Delete menu links
Key Conditions:
- Menu path checks
- Menu item existence
ECA Queue
Purpose: Queued operations Key Actions:
- Queue item creation
- Queue item processing
Key Events:
- Queue processing
ECA Migrate
Purpose: Migration-related events Key Events:
- Pre-migration
- Post-migration
- Migration rollback
ECA Project Browser
Purpose: Project Browser module integration Features:
- Search projects
- Filter results
- Automation on project discovery
ECA Endpoint
Purpose: Custom route and endpoint creation (v1.1.0+) Key Actions:
- Create custom routes
- Define endpoint responses
- Handle custom requests
ECA Misc
Purpose: Miscellaneous core kernel events Key Events:
- Kernel events
- System events
- Custom events
Actions, Conditions, and Events
Overview
ECA includes:
- 500+ Actions from core and contrib modules
- 70+ Conditions for complex logic evaluation
- 200+ Events across all Drupal subsystems
Common Actions
Entity Operations (ECA Content)
eca_entity_create: Create a new entityeca_entity_update: Update an entityeca_entity_delete: Delete an entityeca_entity_clone: Clone an entityeca_entity_revisions: Manage entity revisions
User Operations (ECA User)
eca_user_create: Create user accounteca_user_block: Block a usereca_user_unblock: Unblock a usereca_user_roles_add: Add user roleeca_user_roles_remove: Remove user role
Email Operations (core Actions)
eca_system_send_email: Send email messageeca_system_send_message: Send system message
Logging Operations (ECA Log)
eca_log_message: Log a messageeca_log_watchdog: Create watchdog entry
Data Operations
eca_set_variable: Store a variableeca_get_variable: Retrieve a variableeca_list_push: Add to listeca_list_pop: Remove from list
Webhook/Integration Operations
eca_http_request: Make HTTP requesteca_json_parse: Parse JSON dataeca_xml_parse: Parse XML data
Common Conditions
Entity Conditions
eca_entity_is_new: Check if entity is neweca_entity_type: Check entity typeeca_entity_bundle: Check entity bundleeca_field_value: Compare field valueeca_field_is_empty: Check if field is empty
User Conditions
eca_user_has_role: Check user roleeca_user_is_authenticated: Check if user authenticatedeca_user_is_anonymous: Check if user anonymous
Data Conditions
eca_data_is_empty: Check if data is emptyeca_data_equals: Compare data valueseca_list_contains: Check if list contains valueeca_string_contains: Check string contains substringeca_regex_match: Test regex pattern
Access Conditions
eca_permission: Check user permissioneca_access: Check entity access
Common Events
Content Events (ECA Content)
eca_entity_presave: Before entity saveeca_entity_insert: After entity creationeca_entity_update: After entity updateeca_entity_delete: After entity deletioneca_entity_view: When entity viewed
User Events (ECA User)
eca_user_login: User logineca_user_insert: User creationeca_user_update: User profile updateeca_user_delete: User deletioneca_user_cancel: User account cancelled
Form Events (ECA Form)
eca_form_prepare: Form prepareeca_form_validate: Form validationeca_form_submit: Form submissioneca_form_alter: Form alteration
System Events (ECA Misc)
eca_cron: Cron job executioneca_response: HTTP responseeca_request: HTTP request
Custom Events
- Any Drupal kernel event can be exposed to ECA
- Module-specific events from contrib modules
- Custom events dispatched by your code
AI Integration
Integration with drupal/ai Module
ECA integrates seamlessly with the Drupal AI module for intelligent automation:
AI-Powered Decision Making
Event: Content created Conditions: - Use AI to analyze content sentiment - Check if AI-generated tags match criteria Actions: - Route to appropriate workflow based on AI analysis - Auto-publish if AI confidence is high
AI Content Generation
Event: Form submission Conditions: - Form is blog post draft Actions: - Use AI to generate SEO-optimized title - Generate meta description - Create excerpt - Save generated content
AI Content Moderation
Event: User-generated content submitted Conditions: - Content type is comment Actions: - Run AI content moderation check - If flagged: queue for human review - If approved: auto-publish
Integration with drupal/ai_agents Module
ECA forms the orchestration backbone for AI agent workflows:
Multi-Step Agent Pipelines
Event: Research request submitted Conditions: - Request meets quality threshold - User has permission Actions: - Step 1: Research Agent (gather information) - Step 2: Analysis Agent (process data) - Step 3: Summary Agent (create executive summary) - Step 4: Notification Agent (alert stakeholder)
Agent-Triggered Workflows
Event: Agent completes task Conditions: - Task status = completed - Agent produced results Actions: - Publish agent results - Notify relevant users - Create follow-up tasks - Log agent execution metrics
Conditional Agent Routing
Event: Request arrives Conditions: - Analyze request type - Check complexity Actions: - Route to appropriate agent pool - Set agent parameters based on context - Monitor agent execution - Handle agent failures gracefully
AI-Driven Entity Processing
Event: Media file uploaded Conditions: - File is image or video Actions: - AI image analysis (extract objects, faces, text) - Generate alt text automatically - Extract metadata - Tag content with AI-identified categories - Store AI metadata in custom fields
Practical AI Integration Example
Automated Content Enrichment Workflow
Model: "Automated Content Enrichment" Event: Node created of type "article" Conditions: - Node is new (not saved before) - Title field is not empty - Body field is not empty Actions: Step 1: AI Analysis - Call AI module to analyze content - Extract key topics - Determine content category - Calculate quality score Step 2: Conditional Processing - If quality_score > 0.8: - Auto-publish content - Set featured flag - Create social media post - Else: - Save as draft - Tag for editorial review - Notify content team Step 3: Content Enrichment - Generate SEO-optimized meta tags - Create thumbnail if not exists - Generate excerpt - Link to related content via AI Step 4: Notification - Send notification to author - Log enrichment details - Update analytics
Context Stack for AI Workflows
// When an AI action completes, it adds to the context stack: $context_stack = [ 'node' => $node_entity, 'ai_analysis' => [ 'topics' => ['topic1', 'topic2'], 'category' => 'technology', 'quality_score' => 0.92, 'sentiment' => 'positive' ], 'ai_metadata' => [ 'processing_time' => 1.2, 'model_used' => 'gpt-4', 'confidence' => 0.95 ] ]; // Subsequent conditions can access and use this data: $quality_score = $context_stack['ai_analysis']['quality_score']; if ($quality_score > 0.8) { // Execute premium workflow }
Creating Custom ECA Plugins
Create Custom Action
Step 1: Create Plugin Class
File: src/Plugin/ECA/Action/MyCustomAction.php
<?php namespace Drupal\my_module\Plugin\ECA\Action; use Drupal\eca\Plugin\ECA\Action\ActionBase; use Drupal\eca\Plugin\ECA\PluginUsesContext; /** * Provides a custom action plugin. * * @ECA( * id = "my_custom_action", * label = @Translation("My Custom Action"), * description = @Translation("Performs a custom operation."), * context_definitions = { * "node" = @ContextDefinition("entity:node", * label = @Translation("Node"), * description = @Translation("The node to process"), * assignment_restriction = "selector" * ) * } * ) */ class MyCustomAction extends ActionBase { use PluginUsesContext; /** * {@inheritdoc} */ public function execute(): void { // Get context $node = $this->getContextValue('node'); // Perform custom logic if ($node) { // Your custom code here $node->setTitle($node->getTitle() . ' - Processed'); $node->save(); } } /** * {@inheritdoc} */ public static function defaultConfiguration(): array { return [ 'prefix' => '', 'suffix' => ' - Processed', ] + parent::defaultConfiguration(); } /** * {@inheritdoc} */ public function buildConfigurationForm(array $form, FormStateInterface $form_state): array { $form = parent::buildConfigurationForm($form, $form_state); $form['prefix'] = [ '#type' => 'textfield', '#title' => $this->t('Prefix'), '#default_value' => $this->configuration['prefix'], ]; $form['suffix'] = [ '#type' => 'textfield', '#title' => $this->t('Suffix'), '#default_value' => $this->configuration['suffix'], ]; return $form; } /** * {@inheritdoc} */ public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void { $this->configuration['prefix'] = $form_state->getValue('prefix'); $this->configuration['suffix'] = $form_state->getValue('suffix'); parent::submitConfigurationForm($form, $form_state); } }
Step 2: Register in Module
File: my_module.info.yml
name: My Custom Module type: module core_version_requirement: '^10.0' dependencies: - eca
Create Custom Condition
File: src/Plugin/ECA/Condition/MyCustomCondition.php
<?php namespace Drupal\my_module\Plugin\ECA\Condition; use Drupal\eca\Plugin\ECA\Condition\ConditionBase; use Drupal\eca\Plugin\ECA\PluginUsesContext; /** * Provides a custom condition plugin. * * @ECA( * id = "my_custom_condition", * label = @Translation("My Custom Condition"), * description = @Translation("Checks a custom condition."), * context_definitions = { * "node" = @ContextDefinition("entity:node", * label = @Translation("Node"), * description = @Translation("The node to check") * ) * } * ) */ class MyCustomCondition extends ConditionBase { use PluginUsesContext; /** * {@inheritdoc} */ public function evaluate(): bool { $node = $this->getContextValue('node'); if (!$node) { return false; } // Custom evaluation logic return $node->getOwnerId() > 0; } /** * {@inheritdoc} */ public static function defaultConfiguration(): array { return [ 'min_owner_id' => 0, ] + parent::defaultConfiguration(); } /** * {@inheritdoc} */ public function buildConfigurationForm(array $form, FormStateInterface $form_state): array { $form = parent::buildConfigurationForm($form, $form_state); $form['min_owner_id'] = [ '#type' => 'number', '#title' => $this->t('Minimum Owner ID'), '#default_value' => $this->configuration['min_owner_id'], ]; return $form; } /** * {@inheritdoc} */ public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void { $this->configuration['min_owner_id'] = $form_state->getValue('min_owner_id'); parent::submitConfigurationForm($form, $form_state); } }
Create Custom Event
File: src/Plugin/ECA/Event/MyCustomEvent.php
<?php namespace Drupal\my_module\Plugin\ECA\Event; use Drupal\eca\Plugin\ECA\Event\EventBase; use Drupal\eca\Event\RenderingEvent; /** * Provides a custom event plugin. * * @ECA( * id = "my_custom_event", * label = @Translation("My Custom Event"), * description = @Translation("Triggers on custom event."), * deriver = "Drupal\eca\Plugin\ECA\Event\EventDeriver" * ) */ class MyCustomEvent extends EventBase { /** * {@inheritdoc} */ public static function definitions(): array { return [ 'my_custom_event' => [ 'label' => 'My Custom Event', 'description' => 'Triggered when custom event occurs', 'event_class' => 'Drupal\my_module\Event\MyCustomEvent', ], ]; } /** * {@inheritdoc} */ public function startListening(): void { $this->dispatcher->addListener('my_module.custom_event', [$this, 'onEvent']); } /** * The event handler. */ public function onEvent(MyCustomEvent $event): void { // Set context values $this->setEventContext('data', $event->getData()); // Trigger any listening ECA models $this->raiseEvent(); } }
Register Custom Event
Create file: src/Event/MyCustomEvent.php
<?php namespace Drupal\my_module\Event; use Symfony\Contracts\EventDispatcher\Event; class MyCustomEvent extends Event { const NAME = 'my_module.custom_event'; private $data; public function __construct($data) { $this->data = $data; } public function getData() { return $this->data; } }
Register Custom Plugins
Add to my_module.services.yml:
services: my_module.custom_action: class: Drupal\my_module\Plugin\ECA\Action\MyCustomAction tags: - { name: eca_action } my_module.custom_condition: class: Drupal\my_module\Plugin\ECA\Condition\MyCustomCondition tags: - { name: eca_condition } my_module.custom_event: class: Drupal\my_module\Plugin\ECA\Event\MyCustomEvent arguments: ['@event_dispatcher'] tags: - { name: eca_event } - { name: event_subscriber }
Agent Workflow Patterns
Pattern 1: Sequential Processing Pipeline
Model: "Sequential Content Processing" Event: Node created Conditions: - Content type is "article" Actions: Step 1: Validation Agent - Validate content structure - Store validation_result in context Step 2: Enrichment Agent (conditional on validation) - If validation_result == "passed": - Enrich with metadata - Generate taxonomy tags - Store enrichment_data in context Step 3: Approval Agent - If enrichment_data exists: - Auto-approve if score > threshold - Else: queue for human review Step 4: Publishing Agent - If approved: - Publish content - Create social posts - Send notifications
Pattern 2: Parallel Agent Execution
Model: "Parallel Content Analysis" Event: Media file uploaded Conditions: - File type is image Actions: Parallel Tasks: - Vision Agent: Extract visual features - OCR Agent: Extract text from image - Tagging Agent: Generate content tags - Classification Agent: Categorize content Consolidate Results: - Merge all agent outputs - Resolve conflicts - Store consolidated metadata Update Entity: - Add all extracted metadata to media item - Update file alt text - Link to related content
Pattern 3: Conditional Branching
Model: "Smart Content Routing" Event: User submits content request Conditions: - Request contains valid criteria Actions: Analyze Request: - AI analyzes request complexity - Determine appropriate workflow tier Branch on Complexity: - Simple Request (score < 0.3): - Route to Simple Processing Agent - Auto-respond - Complete immediately - Medium Request (0.3 - 0.7): - Route to Standard Processing Agent - Queue for processing - Send progress notifications - Complex Request (score > 0.7): - Route to Expert Agent Pool - Assign to senior specialist - Enable human escalation - Send regular updates Final Notification: - Send completion notification - Store request metrics - Update user profile
Pattern 4: Error Handling & Retry
Model: "Resilient Agent Workflow" Event: External API request needed Conditions: - API endpoint is required Actions: Initialize: - Set retry_count = 0 - Set max_retries = 3 - Set backoff_seconds = 5 Attempt Call: - Call external API - Store response in context Evaluate Response: - If success: - Process results - Log success - Complete workflow - If error and retry_count < max_retries: - Increment retry_count - Wait backoff_seconds - Jump back to "Attempt Call" - If error and retry_count >= max_retries: - Log failure - Send alert - Queue for manual review - Complete with error status
Pattern 5: Stateful Multi-Step Workflow
Model: "Content Approval Workflow" Event: Draft content submitted for review Conditions: - Content is in draft status - Author is authenticated Actions: Initialize Workflow: - Create workflow state record - Set state = "review_requested" - Assign to reviewer group Wait for Review: - Send review request notification - Monitor for reviewer response Handle Review Feedback: - If approved: - Set state = "approved" - Call publish action - Notify author - If rejected: - Set state = "changes_requested" - Send feedback to author - Create revision task Handle Author Revision: - Author resubmits - Set state = "resubmitted" - Return to "Wait for Review" Publish: - Set state = "published" - Update publish date - Create social media posts - Archive workflow record
Pattern 6: Webhook Integration Workflow
Model: "External Service Integration" Event: Order completed in e-commerce Conditions: - Order status = completed - Fulfillment needed Actions: Prepare Payload: - Extract order details - Format for external API - Add authentication token Send Webhook: - POST to fulfillment service - Include timeout (30 seconds) - Store webhook_id in context Handle Response: - If successful: - Update order status - Log fulfillment task creation - Send tracking notification - If failed: - Queue for retry - Escalate to support team - Create incident ticket Monitor Fulfillment: - Set up polling schedule - Check fulfillment status hourly - Update order on changes - Complete when fulfilled
BPMN.io Visual Builder
Overview
ECA's admin interface uses BPMN.io (Business Process Model and Notation) for visual workflow design.
Accessing the Visual Builder
- Navigate to:
/admin/config/workflow/eca - Click "Add model" to create new workflow
- Click model name to open visual editor
- Or enable "ECA UI" module for UI integration
BPMN Basics
Elements
- Start Event: Triggers workflow (circle)
- Task: Single action or condition group (rectangle)
- Exclusive Gateway: Decision point (diamond)
- Parallel Gateway: Simultaneous execution (diamond with +)
- End Event: Workflow completion (circle)
- Sequence Flow: Connection between elements (arrow)
Example: Visual Workflow
[Start] † [Check Content Type?] Yes> [Enrich Content] † [Publish] † [End]
‚ †‘
No> [Queue for Review] ˜
Building in BPMN.io
Step 1: Create Event
1. Drag Start Event onto canvas
2. Configure event:
- Select "Node created"
- Set entity type to "Article"
3. Label: "Article Created"
Step 2: Add Decision Point
1. Drag Exclusive Gateway
2. Add outgoing sequence flows:
- Condition: Content has required fields
- True path: Continue
- False path: Require revision
Step 3: Add Tasks
1. Drag Task element
2. Configure action:
- Select action type
- Map context variables
- Set parameters
3. Repeat for each action
Step 4: Configure End Event
1. Drag End Event
2. Mark workflow completion
3. Optional: Log completion status
Context Variable Mapping
BPMN.io supports token-based variable mapping:
# Use tokens to access context
[node:title] - Node title
[node:uid:entity:name] - Author username
[node:created] - Creation timestamp
[ai_metadata:score] - AI analysis score
# In action configuration:
Email subject: "Article '[node:title]' approved"
Message body: "Approved by [current_user:name]"
Complex Workflow Example
Start Event: "Content Submitted" † Task: "Analyze with AI" - AI analysis action - Store results in context † Gateway: "Quality Check" ‚ † High Quality (> 0.85) ‚ † ‚ Task: "Auto Publish" ‚ † ‚ Task: "Send Author Notification" ‚ † ‚ Gateway: Merge † ‚ † Medium Quality (0.6 - 0.85) † Task: "Queue for Review" † Task: "Notify Editorial Team" † Gateway: Merge † † End Event: "Workflow Complete"
Export/Import via BPMN.io
-
Export Model:
- Admin UI † Model † Export
- Downloads BPMN XML file
- Portable across instances
-
Import Model:
- Admin UI † Add Model
- Upload BPMN XML file
- Auto-configures ECA plugins
Drush Commands
# Export model to BPMN file drush eca:export-model article_workflow > article_workflow.bpmn # Import model from BPMN file drush eca:import-model article_workflow.bpmn # List all models drush eca:list-models # Test model execution drush eca:test-model article_workflow
Code Examples
Example 1: Complete Automated Blog Publishing Workflow
Scenario: Auto-publish blog posts that meet quality criteria
YAML Configuration (exportable via Drush):
id: automated_blog_publishing label: Automated Blog Publishing model: | { "rootElements": [ { "id": "StartEvent_1", "type": "bpmn:StartEvent", "name": "Blog Post Created", "outgoing": ["Flow_1"] }, { "id": "Activity_1", "type": "bpmn:Task", "name": "AI Content Analysis", "incoming": ["Flow_1"], "outgoing": ["Flow_2"], "extensions": { "action": "ai_content_analyze", "mappings": { "entity": "[node]" } } }, { "id": "Gateway_1", "type": "bpmn:ExclusiveGateway", "name": "Quality Check", "incoming": ["Flow_2"], "outgoing": ["Flow_High", "Flow_Low"] }, { "id": "Activity_2", "type": "bpmn:Task", "name": "Publish Post", "incoming": ["Flow_High"], "outgoing": ["Flow_3"], "extensions": { "action": "eca_entity_update", "mappings": { "entity": "[node]", "status": "1" } } }, { "id": "Activity_3", "type": "bpmn:Task", "name": "Queue for Review", "incoming": ["Flow_Low"], "outgoing": ["Flow_4"], "extensions": { "action": "eca_entity_update", "mappings": { "entity": "[node]", "field_review_status": "pending" } } }, { "id": "EndEvent_1", "type": "bpmn:EndEvent", "name": "Workflow Complete", "incoming": ["Flow_3", "Flow_4"] } ] } # Define the event events: - id: content_created event: eca_entity_insert entity_type: node bundle: blog_post # Define conditions conditions: quality_check: condition: eca_data_comparison left_value: "[ai_analysis:quality_score]" operator: '>' right_value: '0.80' # Define actions actions: analyze_content: action: ai_analyze_content entity: "[node]" publish_post: action: eca_entity_update entity: "[node]" updates: status: 1 promote: 1 notify_author_published: action: eca_system_send_email to: "[node:uid:entity:mail]" subject: "Your post '[node:title]' has been published!" body: "Congratulations! Your blog post has been automatically published based on quality criteria." queue_for_review: action: eca_entity_update entity: "[node]" updates: field_review_status: pending notify_reviewer: action: eca_system_send_email to: "editor@example.com" subject: "Blog post requires review: [node:title]" body: "A blog post needs editorial review: [node:url]"
PHP Implementation (If programmatically needed):
<?php namespace Drupal\my_blog_module\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Drupal\eca\Event\EntityInsertEvent; class BlogPostSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { return [ 'eca_entity_insert.node.blog_post' => ['onBlogPostCreate'], ]; } public function onBlogPostCreate(EntityInsertEvent $event) { $node = $event->getEntity(); // AI analysis would be done by ECA action // This just coordinates the workflow trigger \Drupal::messenger()->addStatus( "Blog post workflow triggered for: {$node->getTitle()}" ); } }
Example 2: User Onboarding Multi-Step Workflow
Scenario: Complete user onboarding with email sequence and AI suggestions
id: user_onboarding_workflow label: User Onboarding Workflow events: - id: user_created event: eca_user_insert conditions: is_new_user: condition: eca_user_is_authenticated negate: false actions: step_1_welcome_email: action: eca_system_send_email to: "[user:mail]" subject: "Welcome to our community!" body: | Welcome [user:name]! We're excited to have you join our community. Next steps: 1. Complete your profile 2. Join a group 3. Post your first message Questions? Contact us at support@example.com step_2_create_welcome_content: action: eca_entity_create entity_type: node bundle: welcome_message mappings: title: "Welcome [user:name]!" field_recipient: "[user:uid]" body: "Your personalized welcome message" step_3_schedule_followup: action: eca_queue_item_add queue: user_onboarding_followup data: uid: "[user:uid]" step: 2 delay_hours: 24 step_4_ai_recommendations: action: ai_generate_recommendations user: "[user]" topic: "community_groups" save_to: "[user:uid]:recommended_groups" step_5_send_recommendations: action: eca_system_send_email to: "[user:mail]" subject: "Groups we think you'll love" body: "Based on your interests, we recommend: [recommended_groups]" conditional_on: "recommendations_exist"
Example 3: Content Review & Approval Workflow
Scenario: Route content through approval chain with role-based decision making
<?php namespace Drupal\content_workflow\Plugin\ECA\Action; use Drupal\eca\Plugin\ECA\Action\ActionBase; use Drupal\eca\Plugin\ECA\PluginUsesContext; use Drupal\user\Entity\User; /** * Routes content to appropriate reviewer based on category. * * @ECA( * id = "route_to_reviewer", * label = @Translation("Route to Reviewer"), * context_definitions = { * "node" = @ContextDefinition("entity:node") * } * ) */ class RouteToReviewerAction extends ActionBase { use PluginUsesContext; public function execute(): void { $node = $this->getContextValue('node'); if (!$node) { return; } // Get content category $category = $node->get('field_category')->value; // Route to appropriate reviewer role $reviewer_role = $this->getReviewerRole($category); // Find available reviewer $reviewer = $this->findAvailableReviewer($reviewer_role); if ($reviewer) { // Assign review task $node->set('field_assigned_reviewer', $reviewer->id()); $node->set('field_review_status', 'pending'); $node->save(); // Send notification $this->notifyReviewer($reviewer, $node); } } private function getReviewerRole($category) { $mapping = [ 'technology' => 'tech_reviewer', 'marketing' => 'marketing_reviewer', 'legal' => 'legal_reviewer', 'finance' => 'finance_reviewer', ]; return $mapping[$category] ?? 'default_reviewer'; } private function findAvailableReviewer($role) { // Load users with role $query = \Drupal::entityQuery('user') ->condition('roles', $role) ->condition('status', 1); $user_ids = $query->execute(); if (empty($user_ids)) { return null; } // Find reviewer with fewest pending reviews $reviewer_id = reset($user_ids); return User::load($reviewer_id); } private function notifyReviewer($reviewer, $node) { $mail_manager = \Drupal::service('plugin.manager.mail'); $params = [ 'subject' => "Content Pending Review: {$node->getTitle()}", 'message' => $this->buildReviewNotification($reviewer, $node), 'node' => $node, 'reviewer' => $reviewer, ]; $mail_manager->mail( 'content_workflow', 'review_request', $reviewer->getEmail(), $reviewer->getPreferredLangcode(), $params ); } private function buildReviewNotification($reviewer, $node) { return "Hello {$reviewer->getDisplayName()},\n\n" . "Content pending your review:\n" . "Title: {$node->getTitle()}\n" . "Category: {$node->get('field_category')->value}\n" . "Review Link: {$node->toUrl('canonical', ['absolute' => true])->toString()}\n"; } }
Example 4: AI-Powered Content Moderation
id: ai_content_moderation label: AI Content Moderation events: - id: comment_created event: eca_entity_insert entity_type: comment conditions: comment_not_deleted: condition: eca_entity_is_deleted negate: true actions: step_1_analyze_content: action: ai_content_moderation_check entity: "[comment]" checks: - toxicity - hate_speech - spam - profanity store_results: moderation_check step_2_check_severity: condition: "[moderation_check:score] > 0.7" true_actions: - action: eca_entity_update entity: "[comment]" updates: field_moderation_status: flagged_high field_moderation_score: "[moderation_check:score]" - action: eca_system_create_message type: error message: "Comment flagged for human review due to: [moderation_check:reason]" - action: eca_queue_item_add queue: moderation_queue data: entity_id: "[comment:cid]" priority: high false_actions: - action: eca_entity_update entity: "[comment]" updates: field_moderation_status: approved field_moderation_score: "[moderation_check:score]" - action: eca_system_create_message type: status message: "Your comment has been approved" step_3_notify_moderators: conditional_on: "severity_high" action: eca_system_send_email to: "moderators@example.com" subject: "Content requires moderation" body: | A comment requires moderation review: Author: [comment:uid:entity:name] Score: [moderation_check:score] Reason: [moderation_check:reason] Link: [comment:url]
Best Practices
1. Design Principles
- Separation of Concerns: One model per workflow
- Idempotence: Make actions safe to repeat
- Error Handling: Always handle failure cases
- Recursion Prevention: Use state flags to prevent loops
- Performance: Avoid heavy operations in conditions
2. Context Management
- Use meaningful variable names
- Document context structure
- Validate context before use
- Clean up temporary variables
3. Testing
# Test model with specific event drush eca:test-model my_model --event=node_created # Enable debug logging drush config:set eca.settings debug_logging true # Monitor execution tail -f /var/log/drupal/eca.log
4. Monitoring & Debugging
- Enable watchdog logging
- Use Drupal's Event Listener for debugging
- Monitor cron job execution
- Track workflow performance metrics
5. Security
- Validate all user input
- Restrict action permissions
- Audit workflow modifications
- Use HTTPS for webhooks
- Never expose sensitive data in logs
6. Performance Optimization
- Index frequently-queried fields
- Cache expensive operations
- Use queued actions for heavy tasks
- Limit condition complexity
- Monitor database queries
7. Documentation
- Document workflow purpose
- Comment complex conditions
- Maintain runbook for troubleshooting
- Track workflow changes
- Create decision trees for branching logic
Resources
Official Documentation
- ECA Guide: https://ecaguide.org
- Drupal Project: https://www.drupal.org/project/eca
- Git Repository: https://git.drupalcode.org/project/eca
Related Modules
- drupal/ai: AI integration for Drupal
- drupal/ai_agents: Agent orchestration
- drupal/rules: Legacy rules engine
- drupal/webhook: Webhook support
- drupal/commerce: E-commerce integration
BPMN.io Resources
- BPMN.io Homepage: https://bpmn.io
- BPMN Spec: https://www.bpmn.org
- Modeler Documentation: https://docs.bpmn.io
Community
- Drupal Forums: https://www.drupal.org/forum
- GitLab Discussions: https://git.drupalcode.org/project/eca/-/discussions
- Drupal Slack: #drupal channel
Example Workflows
- Model Library: Available at ecaguide.org
- Community Examples: GitLab wiki and discussions
- Video Tutorials: Available on Drupal.org and YouTube
Appendix: Quick Reference
Common Token Patterns
# Entity Tokens
[node:title] Node title
[node:nid] Node ID
[node:uid:entity:name] Author username
[node:created] Creation timestamp
[node:url] Node URL
# User Tokens
[user:name] Username
[user:mail] User email
[user:uid] User ID
[current_user:name] Current user name
# Custom Fields
[node:field_custom] Custom field value
[node:field_ref:entity:title] Referenced entity title
Module Enable/Disable Checklist
# Install core ECA drush en eca # Install common sub-modules drush en eca_content eca_user eca_form eca_cache # Install UI for visual builder drush en eca_ui # For AI integration drush en eca_content_ai eca_user_ai # Clear cache drush cr
Drush Commands Summary
# Model management drush eca:list-models # List all models drush eca:export-model [id] > model.yaml # Export model drush eca:import-model model.yaml # Import model drush eca:delete-model [id] # Delete model # Debugging drush eca:test-model [id] # Test model drush eca:debug-event [name] # Debug event drush eca:trace-execution [id] # Trace execution
Document Version: 1.0 Last Updated: 2026-01-08 Drupal ECA Module Version: 2.0+ Maintained By: Agent Platform Team