- Issue created by @camoa
- π©πͺGermany jurgenhaas Gottmadingen
This sounds amazing. As an ECA maintainer I'd be happy to provide help when needed.
- πΊπΈUnited States armyguyinfl Florida
Let's go! Can't wait for the Salesforce integration.
- πΊπΈUnited States camoa
After reviewing the Salesforce module, I've put together a list of potential events, conditions, and actions we could implement for the ECA integration. This is based on the existing Salesforce module architecture to ensure we're leveraging what's already available:
Events
Push Events
salesforce_eca.push_success
- Uses SalesforceEvents::PUSH_SUCCESSsalesforce_eca.push_fail
- Uses SalesforceEvents::PUSH_FAILsalesforce_eca.push_params
- Uses SalesforceEvents::PUSH_PARAMSsalesforce_eca.push_allowed
- Uses SalesforceEvents::PUSH_ALLOWED
Pull Events
salesforce_eca.pull_presave
- Uses SalesforceEvents::PULL_PRESAVEsalesforce_eca.pull_entity_value
- Uses SalesforceEvents::PULL_ENTITY_VALUEsalesforce_eca.pull_prepull
- Uses SalesforceEvents::PULL_PREPULLsalesforce_eca.pull_query
- Uses SalesforceEvents::PULL_QUERY
Error Events
salesforce_eca.error
- Uses SalesforceEvents::ERRORsalesforce_eca.warning
- Uses SalesforceEvents::WARNINGsalesforce_eca.notice
- Uses SalesforceEvents::NOTICE
Conditions
Object Conditions
salesforce_object_type
- Uses SObject class type checkingsalesforce_field_value
- Uses SObject field access methodssalesforce_object_exists
- Uses RestClient::objectRead() or RestClient::objectReadbyExternalId()
Mapping Conditions
salesforce_is_mapped
- Uses SalesforceMapping entity queriessalesforce_field_is_mapped
- Uses SalesforceMappingFieldPluginManagersalesforce_mapping_direction
- Uses SalesforceMapping properties
Entity Conditions
entity_has_sfid
- Uses MappedObject entity queriesentity_sync_status
- Uses MappedObject status propertyentity_recently_synced
- Uses MappedObject updated timestamp
System Conditions
salesforce_is_connected
- Uses RestClient::isInit()salesforce_api_limits
- Uses RestClient::getApiUsage()salesforce_queue_status
- Uses PushQueue service
Actions
Push Actions
salesforce_push_entity
- Uses MappedObject::push()salesforce_push_multiple
- Uses batch operations with MappedObject::push()salesforce_queue_push
- Uses PushQueue::createItem()
Pull Actions
salesforce_pull_object
- Uses RestClient::objectRead() and pull systemsalesforce_pull_by_query
- Uses SelectQuery objects with RestClient::query()salesforce_queue_pull
- Uses PullQueue::createItem()
API Actions
salesforce_execute_soql
- Uses SelectQuery objects with RestClient::query()salesforce_api_call
- Uses RestClient::apiCall()salesforce_create_object
- Uses RestClient::objectCreate()salesforce_update_object
- Uses RestClient::objectUpdate()salesforce_delete_object
- Uses RestClient::objectDelete()salesforce_upsert_object
- Uses RestClient::objectUpsert()
Mapping Actions
salesforce_create_mapping
- Uses SalesforceMapping entity creationsalesforce_update_mapping
- Uses SalesforceMapping entity updatesalesforce_delete_mapping
- Uses SalesforceMapping entity deletionsalesforce_sync_mapping
- Uses SalesforceMapping with batch operations
Data Transformation Actions
salesforce_transform_data
- Would need custom transformations, potentially with ECA's data pluginssalesforce_export_to_variable
- Uses ECA variable system with Salesforce data
Utility Actions
salesforce_log
- Uses Drupal logger systemsalesforce_clear_cache
- Uses Cache tags and bins related to Salesforcesalesforce_connection_test
- Uses RestClient::apiCall() with HEAD method
Common Use Cases
This integration would enable several key use cases without custom code:
- Enhanced Lead Generation: Trigger custom email sequences when leads are created in Salesforce
- Conditional Synchronization: Only push content to Salesforce if it meets specific criteria
- Cross-Platform Workflows: Create workflows spanning both systems
- Data Enrichment: Pull additional data from Salesforce based on form submissions
- Reporting Automation: Generate reports when Salesforce data meets thresholds
- Data Transformation Pipeline: Transform data formats between systems
- Batch Processing Management: Schedule and manage large-scale synchronization
- Connection Monitoring: Automatically monitor Salesforce connectivity
This is just a starting point - if there are other actions, events, or conditions people would find useful, let me know and we can expand this list!
- πΊπΈUnited States camoa
Initial Implementation of the Salesforce ECA Module and Execute SOQL Query Action
This comment provides an overview of the initial implementation of the Salesforce ECA module, focusing on the first action we've created:
salesforce_execute_soql
.Module Structure
We set up the following directory structure for the
salesforce_eca
module:salesforce_eca/ βββ config/ β βββ install/ β β βββ system.action.salesforce_execute_soql.yml β βββ schema/ β βββ salesforce_eca.schema.yml βββ src/ β βββ EventSubscriber/ β β βββ SalesforceEcaEventSubscriber.php β βββ Plugin/ β βββ Action/ β β βββ SalesforceExecuteSoql.php β βββ ECA/ β βββ Condition/ β βββ Event/ β β βββ SalesforceEvents.php β β βββ SalesforceEventsDeriver.php βββ salesforce_eca.info.yml βββ salesforce_eca.module βββ salesforce_eca.services.yml βββ README.md
Module Files
salesforce_eca.info.yml: Defines the module metadata and dependencies, including:
- salesforce:salesforce
- salesforce:salesforce_push
- salesforce:salesforce_mapping
- eca:eca
salesforce_eca.module: Implements
hook_eca_actions_info_alter()
to ensure our custom actions are properly categorized in the ECA UI.salesforce_eca.services.yml: Defines our EventSubscriber service which listens to Salesforce events and triggers corresponding ECA events.
Event Integration
The
SalesforceEcaEventSubscriber
class subscribes to all major Salesforce events (PUSH_ALLOWED, PUSH_PARAMS, PUSH_SUCCESS, PUSH_FAIL, PULL_PRESAVE, PULL_QUERY, PULL_PREPULL) and translates them into ECA events that can be used in ECA workflows.Event Plugin Implementation
The
SalesforceEvents
class and its deriver define the Salesforce events for ECA, includingsalesforce:push_allowed
,salesforce:push_params
,salesforce:push_success
, etc.Execute SOQL Query Action Implementation
The main focus of this initial implementation is the
SalesforceExecuteSoql
action, which:- Extends ECA's ConfigurableActionBase to properly integrate with the ECA system
- Provides two execution methods:
- A structured approach using the
SelectQuery
object withRestClient::query()
- A raw query option using
RestClient::apiCall()
for complex queries
- A structured approach using the
- Offers a configurable form with:
- A textarea for entering the SOQL query with token support
- A checkbox to toggle between structured and raw query execution
- A field to specify the token name where results will be stored
- Includes robust query parsing with extraction of object type, fields, conditions, ordering, limits, and offset
- Handles error conditions by catching exceptions and logging detailed error messages
- Implements access control by checking for the 'access salesforce' permission
Future Considerations
This implementation establishes a foundation for the Salesforce ECA integration. As we continue development, we should:
- Implement additional actions, conditions, and events as outlined in the proposed list
- Consider expanding token support across all aspects of the integration
- Ensure consistent error handling and permission checking across all actions
- Add comprehensive tests for all components
The current implementation of the
salesforce_execute_soql
action serves as a template for other API-related actions in the proposed list, particularly those that interact with the Salesforce REST client. - πΊπΈUnited States camoa
Initial Implementation of the Salesforce ECA Module and Execute SOQL Query Action
This comment provides an overview of the initial implementation of the Salesforce ECA module, focusing on the first action we've created:
salesforce_execute_soql
.Module Structure
We set up the following directory structure for the
salesforce_eca
module:salesforce_eca/ βββ config/ β βββ install/ β β βββ system.action.salesforce_execute_soql.yml β βββ schema/ β βββ salesforce_eca.schema.yml βββ src/ β βββ EventSubscriber/ β β βββ SalesforceEcaEventSubscriber.php β βββ Plugin/ β βββ Action/ β β βββ SalesforceExecuteSoql.php β βββ ECA/ β βββ Condition/ β βββ Event/ β β βββ SalesforceEvents.php β β βββ SalesforceEventsDeriver.php βββ salesforce_eca.info.yml βββ salesforce_eca.module βββ salesforce_eca.services.yml βββ README.md
Module Files
salesforce_eca.info.yml: Defines the module metadata and dependencies, including:
- salesforce:salesforce
- salesforce:salesforce_push
- salesforce:salesforce_mapping
- eca:eca
salesforce_eca.module: Implements
hook_eca_actions_info_alter()
to ensure our custom actions are properly categorized in the ECA UI.salesforce_eca.services.yml: Defines our EventSubscriber service which listens to Salesforce events and triggers corresponding ECA events.
Event Integration
The
SalesforceEcaEventSubscriber
class subscribes to all major Salesforce events (PUSH_ALLOWED, PUSH_PARAMS, PUSH_SUCCESS, PUSH_FAIL, PULL_PRESAVE, PULL_QUERY, PULL_PREPULL) and translates them into ECA events that can be used in ECA workflows.Event Plugin Implementation
The
SalesforceEvents
class and its deriver define the Salesforce events for ECA, includingsalesforce:push_allowed
,salesforce:push_params
,salesforce:push_success
, etc.Execute SOQL Query Action Implementation
The main focus of this initial implementation is the
SalesforceExecuteSoql
action, which:- Extends ECA's ConfigurableActionBase to properly integrate with the ECA system
- Provides two execution methods:
- A structured approach using the
SelectQuery
object withRestClient::query()
- A raw query option using
RestClient::apiCall()
for complex queries
- A structured approach using the
- Offers a configurable form with:
- A textarea for entering the SOQL query with token support
- A checkbox to toggle between structured and raw query execution
- A field to specify the token name where results will be stored
- Includes robust query parsing with extraction of object type, fields, conditions, ordering, limits, and offset
- Handles error conditions by catching exceptions and logging detailed error messages
- Implements access control by checking for the 'access salesforce' permission
Future Considerations
This implementation establishes a foundation for the Salesforce ECA integration. As we continue development, we should:
- Implement additional actions, conditions, and events as outlined in the proposed list
- Consider expanding token support across all aspects of the integration
- Ensure consistent error handling and permission checking across all actions
- Add comprehensive tests for all components
The current implementation of the
salesforce_execute_soql
action serves as a template for other API-related actions in the proposed list, particularly those that interact with the Salesforce REST client. - πΊπΈUnited States camoa
I've been working on implementing the Salesforce ECA integration and wanted to share where things stand. Got pretty deep into this and there's some good progress to report, along with the usual bumps along the way.
What's Actually Working
Built out the full integration between Salesforce and ECA. The core pieces are in place and I've been able to test the main functionality in a real environment.
ECA Events: All 11 Salesforce events now show up in the ECA interface. These cover the major operations - push success/fail, pull operations, delete permissions, etc. Used the deriver pattern that ECA expects, so each event gets its own plugin.
SOQL Action: This turned out to be more interesting than expected. Built a custom ECA action that lets you run raw SOQL queries and store results in tokens. The tricky part was figuring out how to handle Salesforce's SObject responses - they don't play nice with ECA's token system out of the box. Had to convert them properly using the
.fields()
method.Field Discovery: Added something I didn't originally plan for. When you run a SOQL query, the action now tells you what fields are available. Helpful when you're working with custom objects or complex queries where you're not sure what Salesforce will return.
Real Testing Results
Set up a proper test environment with a Salesforce developer account and ngrok for OAuth (since you need a public callback URL). Here's what actually works:
- Connected to Salesforce successfully through OAuth
- Ran
SELECT Id, Name, Email, Phone, CreatedDate, LastModifiedDate FROM Contact LIMIT 5
- Got back 5 contact records with all the expected data
- Token access working:
[soql_results:records:0:Name]
returns "Rose Gonzalez" - Field discovery shows: "Name, Email, Phone, CreatedDate, LastModifiedDate, Id"
The token structure ended up being more complex than I initially thought. Records use numeric indexing (0, 1, 2...) and you need to use Salesforce's exact field names - capitalized like "Name" not "name".
What Still Needs Work
The push/pull events are implemented but not tested yet. They require setting up actual Salesforce mappings (Drupal entity to Salesforce object), which I haven't done. The events should fire when you create/update entities that are mapped to Salesforce, but that's the next testing phase.
Also want to test the mapping ID filtering - the idea is you can have multiple Salesforce mappings and filter events to only specific ones.
Technical Challenges I Hit
Token serialization: ECA tokens need scalar values, but Salesforce returns complex objects. Spent time figuring out the right conversion approach. The
.fields()
method on SObject was key.Access control: Initially tried to use Salesforce permissions, but that breaks anonymous workflows. ECA actions generally allow access by default since the workflow controls execution - had to align with that pattern.
Array indexing: Salesforce uses IDs as array keys, but ECA tokens work better with numeric indices. Added a conversion loop to fix this.
Current Module Structure
salesforce_eca/ βββ src/ β βββ EventSubscriber/SalesforceEcaEventSubscriber.php β βββ Plugin/ β βββ Action/SalesforceExecuteSoql.php β βββ ECA/Event/ β βββ SalesforceEvents.php β βββ SalesforceEventsDeriver.php βββ config/ (schema and install configs) βββ standard module files
The event subscriber listens for Salesforce events and triggers corresponding ECA events. The SOQL action handles query execution and result processing.
What's Next
Need to create some Salesforce mappings and test the push/pull event integration. That's when we'll see if the event filtering and real-world workflows actually work as intended.
The SOQL functionality is solid and ready to use. People can build ECA workflows that query Salesforce data right now. The push/pull integration needs that next testing phase, but the code is there.
Anyone interested in testing this out? Would be helpful to get feedback on the approach and see how it works in different environments.
- πΊπΈUnited States camoa
Hey folks, wanted to update on this integration.
Since there wasn't activity on the issue, I went ahead and released this as an independent module: https://www.drupal.org/project/salesforce_eca β
The module is now available as an alpha release. It provides:
- All Salesforce events exposed to ECA
- SOQL query action
- Trigger push/pull actions
- Smart dependency handling for optional push/pull modulesHappy to maintain it separately - this way people can start using it right away and iterate based on real-world usage.
Closing this issue since the functionality is now available as a standalone module. Thanks for the Salesforce suite foundation that made this possible.