Skip to main content

drupal eca integration guide

Drupal ECA Integration Guide

Table of Contents

  1. Overview
  2. Architecture
  3. Sub-Modules
  4. Actions, Conditions, and Events
  5. AI Integration
  6. Creating Custom ECA Plugins
  7. Agent Workflow Patterns
  8. BPMN.io Visual Builder
  9. Code Examples
  10. Best Practices
  11. 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 entity
  • eca_entity_update: Update an entity
  • eca_entity_delete: Delete an entity
  • eca_entity_clone: Clone an entity
  • eca_entity_revisions: Manage entity revisions

User Operations (ECA User)

  • eca_user_create: Create user account
  • eca_user_block: Block a user
  • eca_user_unblock: Unblock a user
  • eca_user_roles_add: Add user role
  • eca_user_roles_remove: Remove user role

Email Operations (core Actions)

  • eca_system_send_email: Send email message
  • eca_system_send_message: Send system message

Logging Operations (ECA Log)

  • eca_log_message: Log a message
  • eca_log_watchdog: Create watchdog entry

Data Operations

  • eca_set_variable: Store a variable
  • eca_get_variable: Retrieve a variable
  • eca_list_push: Add to list
  • eca_list_pop: Remove from list

Webhook/Integration Operations

  • eca_http_request: Make HTTP request
  • eca_json_parse: Parse JSON data
  • eca_xml_parse: Parse XML data

Common Conditions

Entity Conditions

  • eca_entity_is_new: Check if entity is new
  • eca_entity_type: Check entity type
  • eca_entity_bundle: Check entity bundle
  • eca_field_value: Compare field value
  • eca_field_is_empty: Check if field is empty

User Conditions

  • eca_user_has_role: Check user role
  • eca_user_is_authenticated: Check if user authenticated
  • eca_user_is_anonymous: Check if user anonymous

Data Conditions

  • eca_data_is_empty: Check if data is empty
  • eca_data_equals: Compare data values
  • eca_list_contains: Check if list contains value
  • eca_string_contains: Check string contains substring
  • eca_regex_match: Test regex pattern

Access Conditions

  • eca_permission: Check user permission
  • eca_access: Check entity access

Common Events

Content Events (ECA Content)

  • eca_entity_presave: Before entity save
  • eca_entity_insert: After entity creation
  • eca_entity_update: After entity update
  • eca_entity_delete: After entity deletion
  • eca_entity_view: When entity viewed

User Events (ECA User)

  • eca_user_login: User login
  • eca_user_insert: User creation
  • eca_user_update: User profile update
  • eca_user_delete: User deletion
  • eca_user_cancel: User account cancelled

Form Events (ECA Form)

  • eca_form_prepare: Form prepare
  • eca_form_validate: Form validation
  • eca_form_submit: Form submission
  • eca_form_alter: Form alteration

System Events (ECA Misc)

  • eca_cron: Cron job execution
  • eca_response: HTTP response
  • eca_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

  1. Navigate to: /admin/config/workflow/eca
  2. Click "Add model" to create new workflow
  3. Click model name to open visual editor
  4. 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

  1. Export Model:

    • Admin UI † Model † Export
    • Downloads BPMN XML file
    • Portable across instances
  2. 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

  • 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

Community

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