Account created on 13 January 2013, over 12 years ago
  • Drupal Advisor at Palcera 
  • Technical Account Manager at Acquia 
#

Recent comments

🇺🇸United States camoa

Adding the module link to the guide description

🇺🇸United States camoa

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.

🇺🇸United States camoa

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.

🇺🇸United States camoa

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.

🇺🇸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 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.

🇺🇸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

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:

  1. Extends ECA's ConfigurableActionBase to properly integrate with the ECA system
  2. Provides two execution methods:
    • A structured approach using the SelectQuery object with RestClient::query()
    • A raw query option using RestClient::apiCall() for complex queries
  3. 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
  4. Includes robust query parsing with extraction of object type, fields, conditions, ordering, limits, and offset
  5. Handles error conditions by catching exceptions and logging detailed error messages
  6. 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:

  1. Implement additional actions, conditions, and events as outlined in the proposed list
  2. Consider expanding token support across all aspects of the integration
  3. Ensure consistent error handling and permission checking across all actions
  4. 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, 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:

  1. Extends ECA's ConfigurableActionBase to properly integrate with the ECA system
  2. Provides two execution methods:
    • A structured approach using the SelectQuery object with RestClient::query()
    • A raw query option using RestClient::apiCall() for complex queries
  3. 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
  4. Includes robust query parsing with extraction of object type, fields, conditions, ordering, limits, and offset
  5. Handles error conditions by catching exceptions and logging detailed error messages
  6. 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:

  1. Implement additional actions, conditions, and events as outlined in the proposed list
  2. Consider expanding token support across all aspects of the integration
  3. Ensure consistent error handling and permission checking across all actions
  4. 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

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_SUCCESS
  • salesforce_eca.push_fail - Uses SalesforceEvents::PUSH_FAIL
  • salesforce_eca.push_params - Uses SalesforceEvents::PUSH_PARAMS
  • salesforce_eca.push_allowed - Uses SalesforceEvents::PUSH_ALLOWED

Pull Events

  • salesforce_eca.pull_presave - Uses SalesforceEvents::PULL_PRESAVE
  • salesforce_eca.pull_entity_value - Uses SalesforceEvents::PULL_ENTITY_VALUE
  • salesforce_eca.pull_prepull - Uses SalesforceEvents::PULL_PREPULL
  • salesforce_eca.pull_query - Uses SalesforceEvents::PULL_QUERY

Error Events

  • salesforce_eca.error - Uses SalesforceEvents::ERROR
  • salesforce_eca.warning - Uses SalesforceEvents::WARNING
  • salesforce_eca.notice - Uses SalesforceEvents::NOTICE

Conditions

Object Conditions

  • salesforce_object_type - Uses SObject class type checking
  • salesforce_field_value - Uses SObject field access methods
  • salesforce_object_exists - Uses RestClient::objectRead() or RestClient::objectReadbyExternalId()

Mapping Conditions

  • salesforce_is_mapped - Uses SalesforceMapping entity queries
  • salesforce_field_is_mapped - Uses SalesforceMappingFieldPluginManager
  • salesforce_mapping_direction - Uses SalesforceMapping properties

Entity Conditions

  • entity_has_sfid - Uses MappedObject entity queries
  • entity_sync_status - Uses MappedObject status property
  • entity_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 system
  • salesforce_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 creation
  • salesforce_update_mapping - Uses SalesforceMapping entity update
  • salesforce_delete_mapping - Uses SalesforceMapping entity deletion
  • salesforce_sync_mapping - Uses SalesforceMapping with batch operations

Data Transformation Actions

  • salesforce_transform_data - Would need custom transformations, potentially with ECA's data plugins
  • salesforce_export_to_variable - Uses ECA variable system with Salesforce data

Utility Actions

  • salesforce_log - Uses Drupal logger system
  • salesforce_clear_cache - Uses Cache tags and bins related to Salesforce
  • salesforce_connection_test - Uses RestClient::apiCall() with HEAD method

Common Use Cases

This integration would enable several key use cases without custom code:

  1. Enhanced Lead Generation: Trigger custom email sequences when leads are created in Salesforce
  2. Conditional Synchronization: Only push content to Salesforce if it meets specific criteria
  3. Cross-Platform Workflows: Create workflows spanning both systems
  4. Data Enrichment: Pull additional data from Salesforce based on form submissions
  5. Reporting Automation: Generate reports when Salesforce data meets thresholds
  6. Data Transformation Pipeline: Transform data formats between systems
  7. Batch Processing Management: Schedule and manage large-scale synchronization
  8. 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

We need to ensure that we have the right libraries, and they are loaded correctly.

🇺🇸United States camoa

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.

🇺🇸United States camoa

The process has been setup, we will improve on this as we learn more.

For now the proposed solution was implemented.

🇺🇸United States camoa

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

🇺🇸United States camoa

Configuration changed and push to production.

🇺🇸United States camoa

This was due to the lack of an email service provider.

🇺🇸United States camoa

Setup Honeypot and antibot to protect the registration form

🇺🇸United States camoa

Added emails via Brevo (up to 300 a month)

Need to add protection to the registration form

🇺🇸United States camoa

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.

🇺🇸United States camoa

camoa created an issue.

🇺🇸United States camoa

We need to do a manual control for this initially, to make sure a coupon is only assigned to 1 IXP

🇺🇸United States camoa

Adding the drupal slack for Houston as part of the larger Texas Community

🇺🇸United States camoa

camoa made their first commit to this issue’s fork.

🇺🇸United States 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

🇺🇸United States camoa

Thanks!!

I will check it out

🇺🇸United States camoa

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

🇺🇸United States camoa

camoa changed the visibility of the branch 8.2.x to hidden.

🇺🇸United States camoa

camoa changed the visibility of the branch 8.2.x to hidden.

🇺🇸United States camoa

camoa changed the visibility of the branch 8.2.x to hidden.

🇺🇸United States camoa

camoa made their first commit to this issue’s fork.

🇺🇸United States 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.

🇺🇸United States camoa

Can we start doing this?

We need a volunteer maybe?

🇺🇸United States camoa

Why not use the Issue fork?

I believe that is a better practice.

🇺🇸United States camoa

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

🇺🇸United States camoa

Adding the ixp core competencies survey. 

🇺🇸United States camoa

Yes, Bob, I will do that. Or at least link the docs!

Production build 0.71.5 2024