Get Salesforce Field Value(s) action implemented and committed.
What it does: Retrieve one or more field values from a Salesforce record. Simpler alternative to SOQL for single record field access. Perfect for fetching auto-generated fields after push operations or displaying Salesforce data when viewing Drupal entities.
Key features:
- Dual ID support: Standard Salesforce IDs and External IDs
- Flexible field retrieval: single field, multiple fields, or all fields (*)
- Efficient objectRead() API for retrieving all fields
- Comprehensive error handling with specific messages
- Field validation showing which requested fields don't exist
Available tokens:
- Direct field access:
[token:Email]
,[token:FirstName]
,[token:CustomField__c]
- Status:
[token:success]
(1/0),[token:error]
(error message) - Metadata:
[token:object_type]
,[token:record_id]
- Field info:
[token:field_count]
,[token:all_field_names]
(array),[token:fields_not_found]
- All fields:
[token:fields]
(associative array)
Example usage:
- Specific fields:
Email,FirstName,LastName,Phone
- All fields: Leave empty or use
*
- External ID lookup: Check "Use External ID", set field name (e.g., Email) and value
- After push: Use
[mapped_object:salesforce_id]
to fetch MDVIP_ID__c or other generated fields
Testing: Successfully tested with standard IDs, external ID lookups, field validation, and error handling. Integrates perfectly with mapped object tokens from other actions/conditions.
Files added/changed:
src/Plugin/Action/SalesforceGetFieldValue.php
(new action)config/schema/salesforce_eca.schema.yml
(configuration schema)
Now you can easily retrieve Salesforce field values without writing SOQL queries. Essential for displaying Salesforce data on entity views and fetching auto-generated fields after push operations.
Call Salesforce API action implemented and committed.
What it does: Make direct calls to any Salesforce REST API endpoint with full response access. Supports standard REST API, custom Apex endpoints, Composite API, and more. No more custom code needed for complex Salesforce integrations.
Key features:
- All HTTP methods: GET, POST, PUT, PATCH, DELETE
- Automatic path detection (relative for standard API, absolute for Apex)
- Request body support with JSON validation
- Custom headers configuration
- Full response object access (MDVIP compatible)
Available tokens:
- Response data:
[token:data]
(parsed JSON),[token:raw_body]
(raw string) - HTTP metadata:
[token:status_code]
,[token:reason_phrase]
,[token:protocol_version]
- Headers:
[token:headers]
(all),[token:content_type]
,[token:api_usage]
(Sforce-Limit-Info) - Status flags:
[token:success]
(1 if 2XX),[token:is_json]
- SObject helpers:
[token:fields:FieldName]
,[token:record_id]
,[token:sobject_type]
- Error handling:
[token:error]
,[token:request_endpoint]
,[token:request_method]
Example usage:
- Get record:
sobjects/Account/001D000000AbcDE
- SOQL query:
query?q=SELECT Id, Name FROM Contact LIMIT 10
- Custom Apex:
/services/apexrest/MyService/method
- Composite API:
composite/tree/Account
Testing: Successfully tested with multiple endpoints. Response tokens properly populated, status codes accessible, API usage tracking working. Created test controller and Drush commands for easy testing.
Files added/changed:
src/Plugin/Action/SalesforceCallApi.php
(new action)config/schema/salesforce_eca.schema.yml
(configuration schema)src/Controller/SalesforceEcaTestController.php
(test controller)src/Commands/SalesforceEcaCommands.php
(Drush commands)
Now you can call any Salesforce API endpoint directly from ECA workflows without writing custom code. This enables complex integrations like custom Apex calls, bulk operations, and advanced error handling.
ERROR event implemented and committed.
What it does:
Catches Salesforce errors and makes the data available in ECA workflows. No more custom event subscribers needed for error handling.
Available tokens:
[error_message]
, [entity_id]
, [mapping_info]
, [operation_type]
, [failure_details]
, and others.
Testing:
Created ECA model with both push_fail
and error
events. Both fire correctly during failures. The error event gives you the detailed context you need for smart error handling.
Files changed:
SalesforceEventsDeriver.php
and SalesforceEvent.php
Now you can build error workflows directly in ECA without writing code.
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 modules
Happy 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.
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.
teknorah → credited 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, including salesforce: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.
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, including salesforce: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.
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!
We need to ensure that we have the right libraries, and they are loaded correctly.
The content types are added.
The site has ways to follow this process, but we need review on the information we are gathering and the UX to create and follow an engagement.
The process has been setup, we will improve on this as we learn more.
For now the proposed solution was implemented.
Solution implemented:
- Created job post content type which has title, coupon, and request a coupon.
- Added a coupon content type, the title is the coupon
- Created a workflow and notifications so coupons can be assigned
- Created an ECA model to ensure that once a coupon is assigned it is marked as assigned.
Process:
- Company admin or member create the Job post (request coupon) content.
- An email is sent to the IXP reviewers when a coupon is requested
- IXP reviewer assigns coupon, this coupon gets marked as used.
- An email is sent to the requestor so they can access the coupon
Ixp reviewers need to maintain a list of coupons from the DA
Configuration changed and push to production.
This was due to the lack of an email service provider.
Setup Honeypot and antibot to protect the registration form
Added emails via Brevo (up to 300 a month)
Need to add protection to the registration form
We have github actions that are doing part of the job.
Rught now we have a deploy Github, tied uo to our hosting, based on dev panel. The GA automatically push code to that repo in the form of a deploy artifact.
We do need:
- Automatic deployment on the devpanel instance
- Run updb and CIM as needed.
We need to do a manual control for this initially, to make sure a coupon is only assigned to 1 IXP
Adding the drupal slack for Houston as part of the larger Texas Community
camoa → created an issue. See original summary → .
teknorah → credited camoa → .
volkswagenchick → credited camoa → .
From the DA:
Drupal Association Implementation Plan
MVP Implementation:
What we can implement in a short amount of time (hopefully end of January, subject to change)
Jobs.Drupal.org
For spam management and a huge variety of other reasons just having a free job type open to the web is not going to work for us.
Instead we propose the following:
A landing page: jobs.drupal.org/ixp
This contains the details about how to apply as an IXP organization
Copy provided by IXP community team
Once applied, we send an IXP post coupon code - unlimited free posts for that org - unique to each org
This page also embeds a view of all job postings made using that coupon code or more likely the job type filter
Should these posts expire? Yes
How long?
Default right now for other posts is 30 days
Moderation:
We will ask for the IXP community teams help
Case Studies
We will update the taxonomy for 'sectors' on the case study to provide an option for 'IXP-Experience'
We will add a new view that pre-filters on that sector
Thanks!!
I will check it out
Setting to needs review
I was working on rebasing the 8.2.x branch, made some mistakes but fixed it at the end. The new branch 3461920-logger-misconfigured-8.2.x should work for the 8.2.2 version of the module.
I did not review the changes made by the original committer, I just rebased the 8.2.x Branch
Usage (while this gets approved):
Add the patch in your composer.json
- If you are using 8.1.x use the merge request #10
- If you are using the 8.2.x version, use merge request #13
chadhester → credited camoa → .
As far as I can see in the bootstrap5 theme page, v3 and v4 don't have major differences. So maybe all that is needed is the composer.json change.
camoa → created an issue.
Closing in favor of 🌱 IXP Phase 2 proposed process Active
Closing in favor of 🌱 IXP Phase 2 proposed process Active
Forgot to close
closing in favor of 🌱 IXP Phase 2 proposed process Active
Can we start doing this?
We need a volunteer maybe?
Closed in favor of 🌱 IXP Phase 2 proposed process Active
Closed in favor of 🌱 IXP Phase 2 proposed process Active
This is closed in favor of Phase 1 Proposal 🌱 IXP Phase 2 proposed process Active
Why not use the Issue fork?
I believe that is a better practice.
Your dependencies are not D11 compatible yet.
https://www.drupal.org/project/image_style_quality → is not.
Any advice? I am using D11 and wanted to use this module
Yes, Bob, I will do that. Or at least link the docs!